/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { observer } from 'mobx-react-lite'; import { useEditorStore } from '../../EditorStoreProvider.js'; import { type AccessPointGroupState, type AccessPointState, type LakehouseAccessPointState, DATA_PRODUCT_TAB, DATA_PRODUCT_TYPE, DataProductEditorState, ModelAccessPointGroupState, } from '../../../../stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js'; import { BugIcon, BuildingIcon, CaretDownIcon, Checkbox, CloseEyeIcon, clsx, compressImage, ControlledDropdownMenu, CustomSelectorInput, Dialog, DragPreviewLayer, ErrorWarnIcon, EyeIcon, GroupWorkIcon, HomeIcon, IconSelectorGrid, IconSelectorIcons, InfoCircleIcon, ListEditor, LockIcon, MenuContent, MenuContentItem, Modal, ModalBody, ModalFooter, ModalFooterButton, ModalHeader, PanelContent, PanelDnDEntry, PanelEntryDragHandle, PanelFormTextField, PanelHeader, PanelHeaderActionItem, PanelHeaderActions, PencilEditIcon, PlusIcon, QuestionCircleIcon, ResizablePanel, ResizablePanelGroup, ResizablePanelSplitter, Switch, TimesIcon, Tooltip, UploadIcon, useDragPreviewLayer, WarningIcon, LongArrowRightIcon, PURE_MappingIcon, GitBranchIcon, ListIcon, PanelLoadingIndicator, GearSuggestIcon, FlaskIcon, SparkleIcon, } from '@finos/legend-art'; import { type ChangeEventHandler, useCallback, useEffect, useMemo, useRef, useState, } from 'react'; import { assertErrorThrown, guaranteeNonNullable, guaranteeType, HttpStatus, isNonNullable, NetworkClientError, UserSearchService, } from '@finos/legend-shared'; import { AccessorQueryBuilderState, getCompatibleRuntimesFromAccessorOwner, InlineLambdaEditor, LineageViewer, QueryBuilderActionConfig, QueryBuilderAdvancedWorkflowState, type QueryBuilderState, } from '@finos/legend-query-builder'; import { action, autorun, flowResult, runInAction } from 'mobx'; import { DataProductTestableEditor } from './testable/DataProductTestableEditor.js'; import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor'; import { CodeEditor } from '@finos/legend-lego/code-editor'; import { type Expertise, type GraphManagerState, type LakehouseAccessPoint, type Mapping, type PackageableElement, type AccessPointGroup, DataProduct, DataProductEmbeddedImageIcon, DataProductLibraryIcon, Email, LakehouseTargetEnv, StereotypeExplicitReference, V1_DataProduct, V1_DataProductIconLibraryId, V1_PureGraphManager, V1_RemoteEngine, validate_PureExecutionMapping, InternalDataProductType, ExternalDataProductType, DataProductLink, observer_DataProductLink, Region, DeliveryFrequency, AppDirOwner, AppDirNode, observe_AppDirOwner, observe_AppDirNode, AppDirLevel, } from '@finos/legend-graph'; import { accessPoint_setClassification, accessPoint_setReproducible, accessPointGroup_addTarget, accessPointGroup_deleteTarget, accessPointGroup_setDescription, accessPointGroup_setName, dataProduct_setDescription, dataProduct_setIcon, dataProduct_setSupportInfoIfAbsent, dataProduct_setTitle, supportInfo_addEmail, supportInfo_deleteEmail, supportInfo_setDocumentationUrl, supportInfo_setFaqUrl, supportInfo_setLinkLabel, supportInfo_setSupportUrl, supportInfo_setWebsite, dataProduct_setType, expertise_setDescription, expertise_addId, expertise_deleteId, supportInfo_deleteExpertise, externalType_setLinkURL, externalType_setLinkLabel, accessPointGroup_setTitle, accessPoint_setDescription, accessPoint_setTitle, dataProduct_setOperationalMetadataIfAbsent, operationalMetadata_deleteCoverageRegion, operationalMetadata_addCoverageRegion, operationalMetadata_setUpdateFrequency, dataProduct_setOwner, appDirOwner_setProduction, appDirOwner_setProdParallel, appDirNode_setAppDirId, } from '../../../../stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js'; import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js'; import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../__lib__/LegendStudioApplicationNavigationContext.js'; import { ActionAlertActionType, ActionAlertType, useApplicationNavigationContext, } from '@finos/legend-application'; import { useDrag, useDrop } from 'react-dnd'; import { annotatedElement_addStereotype, annotatedElement_deleteStereotype, } from '../../../../stores/graph-modifier/DomainGraphModifierHelper.js'; import { buildElementOption, type PackageableElementOption, } from '@finos/legend-lego/graph-editor'; import { DataProductViewerState, ProductViewer, } from '@finos/legend-extension-dsl-data-product'; import type { LegendStudioApplicationStore } from '../../../../stores/LegendStudioBaseStore.js'; import type { DepotServerClient } from '@finos/legend-server-depot'; import { RelationElementSampleValuesEditor } from '../data-editor/RelationElementSampleValuesEditor.js'; import type { AccessPointGroupMeta, AccessPointMeta, DataProductDocResponse, DSL_DataProduct_LegendStudioApplicationPlugin_Extension, } from '../../../../stores/extensions/DSL_DataProduct_LegendStudioApplicationPlugin_Extension.js'; import { LEGENDAI_SUGGEST_MATCH_STRATEGY, LEGENDAI_SUGGEST_STAGE, LEGENDAI_SUGGEST_SURFACE, } from '../../../../__lib__/LegendStudioTelemetryHelper.js'; import { useLegendAISuggestTelemetry } from '../LegendAISuggestTelemetryHooks.js'; import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js'; export enum AP_GROUP_MODAL_ERRORS { GROUP_NAME_EMPTY = 'Group Name is empty', GROUP_NAME_EXISTS = 'Group Name already exists', GROUP_DESCRIPTION_EMPTY = 'Group Description is empty', AP_NAME_EMPTY = 'Access Point Name is empty', AP_NAME_EXISTS = 'Access Point Name already exists', AP_DESCRIPTION_EMPTY = 'Access Point Description is empty', } export const AP_EMPTY_DESC_WARNING = 'Click here to describe the data this access point produces'; const AP_DND_TYPE = 'ACCESS_POINT'; const AP_GROUP_DND_TYPE = 'ACCESS_POINT_GROUP'; export type AccessPointDragSource = { accessPointState: AccessPointState; }; export type APGDragSource = { groupState: AccessPointGroupState; }; const newNamePlaceholder = ''; interface HoverTextAreaProps { text: string; handleMouseOver: (event: React.MouseEvent) => void; handleMouseOut: (event: React.MouseEvent) => void; className?: string; } const HoverTextArea: React.FC = ({ text: text, handleMouseOver, handleMouseOut, className, }) => { return (
{text}
); }; const hoverIcon = () => { return (
); }; const AccessPointTitle = observer( (props: { accessPointState: LakehouseAccessPointState; aiSuggestionMeta?: AccessPointMeta | undefined; }) => { const { accessPointState, aiSuggestionMeta } = props; const accessPoint = accessPointState.accessPoint; const [editingName, setEditingName] = useState( accessPoint.id === newNamePlaceholder, ); const handleNameEdit = () => setEditingName(true); const handleNameBlur = () => { if (accessPoint.id !== newNamePlaceholder) { setEditingName(false); const relationElement = accessPointState.relationElementState?.relationElement; if (relationElement) { relationElement.paths[0] = accessPoint.id; } } }; const updateAccessPointName: React.ChangeEventHandler = action((event) => { if (event.target.value.match(/^[0-9a-zA-Z_]*$/)) { accessPoint.id = event.target.value; } }); return (
{editingName ? (