/** * 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 { useState, useCallback, forwardRef } from 'react'; import { observer } from 'mobx-react-lite'; import { useDrop } from 'react-dnd'; import { type DEPRECATED__MappingTestState, MAPPING_TEST_EDITOR_TAB_TYPE, TEST_RESULT, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/legacy/DEPRECATED__MappingTestState.js'; import { clsx, ContextMenu, ProgressBar, PlayIcon, EmptyCircleIcon, TimesCircleIcon, CheckCircleIcon, CircleNotchIcon, PlusIcon, EmptyStopCircleIcon, ExclamationCircleIcon, PauseCircleIcon, PanelDropZone, MenuContent, MenuContentItem, Panel, WarningIcon, } from '@finos/legend-art'; import { type MappingElementDragSource, CORE_DND_TYPE, } from '../../../../stores/editor/utils/DnDUtils.js'; import { ClassMappingSelectorModal } from './MappingExecutionBuilder.js'; import { flowResult } from 'mobx'; import { useEditorStore } from '../../EditorStoreProvider.js'; import { useApplicationStore } from '@finos/legend-application'; import { SetImplementation } from '@finos/legend-graph'; import { MappingEditorState } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js'; export const MappingTestExplorerContextMenu = observer( forwardRef< HTMLDivElement, { mappingTestState?: DEPRECATED__MappingTestState; showCreateNewTestModal?: () => void; isReadOnly: boolean; } >(function MappingTestExplorerContextMenu(props, ref) { const { mappingTestState, isReadOnly, showCreateNewTestModal } = props; const applicationStore = useApplicationStore(); const runMappingTest = (): void => { if (mappingTestState) { flowResult(mappingTestState.runTest()).catch( applicationStore.alertUnhandledError, ); } }; const removeMappingTest = (): void => { if (mappingTestState) { flowResult( mappingTestState.mappingEditorState.deleteTest(mappingTestState.test), ).catch(applicationStore.alertUnhandledError); } }; const toggleSkipTest = (): void => mappingTestState?.toggleSkipTest(); const viewTestResult = (): void => { if (mappingTestState) { mappingTestState.mappingEditorState.openTest( mappingTestState.test, MAPPING_TEST_EDITOR_TAB_TYPE.RESULT, ); } }; const editTest = (): void => { if (mappingTestState) { mappingTestState.mappingEditorState.openTest( mappingTestState.test, MAPPING_TEST_EDITOR_TAB_TYPE.SETUP, ); } }; return ( {mappingTestState && ( Run )} {mappingTestState && mappingTestState.result !== TEST_RESULT.NONE && ( View Result )} {mappingTestState && ( Edit )} {mappingTestState && ( {mappingTestState.isSkipped ? 'Unskip' : 'Skip'} )} {!isReadOnly && mappingTestState && ( Delete )} {!isReadOnly && !mappingTestState && showCreateNewTestModal && ( Create new test )} ); }), ); export const MappingTestStatusIndicator: React.FC<{ testState: DEPRECATED__MappingTestState; }> = (props) => { const { testState } = props; if (testState.isSkipped) { return (
); } if (testState.isRunningTest) { return (
); } return ( <> {testState.result === TEST_RESULT.NONE && (
)} {testState.result === TEST_RESULT.ERROR && (
)} {testState.result === TEST_RESULT.FAILED && (
)} {testState.result === TEST_RESULT.PASSED && (
)} ); }; export const MappingTestExplorer = observer( (props: { testState: DEPRECATED__MappingTestState; isReadOnly: boolean }) => { const { isReadOnly, testState } = props; const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState); const openTest = applicationStore.guardUnhandledError(() => flowResult(mappingEditorState.openTest(testState.test)), ); const runTest = applicationStore.guardUnhandledError(() => flowResult(testState.runTest()), ); const cancelTest = (): void => { testState.setIsRunningTest(false); testState.setTestRunPromise(undefined); }; const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false); const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true); const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false); const isActive = mappingEditorState.currentTabState === testState; return ( } menuProps={{ elevation: 7 }} onOpen={onContextMenuOpen} onClose={onContextMenuClose} >
{testState.isRunningTest ? ( ) : ( )}
); }, ); export const MappingTestsExplorer = observer( (props: { isReadOnly: boolean }) => { const { isReadOnly } = props; const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState); const runAllTests = applicationStore.guardUnhandledError(() => flowResult(mappingEditorState.runTests()), ); // all test run report summary const numberOfTests = mappingEditorState.DEPRECATED_mappingTestStates.length; const numberOfTestsPassed = mappingEditorState.DEPRECATED_mappingTestStates.filter( (testState) => testState.result === TEST_RESULT.PASSED, ).length; const numberOfTestsFailed = mappingEditorState.DEPRECATED_mappingTestStates.filter( (testState) => testState.result === TEST_RESULT.FAILED || testState.result === TEST_RESULT.ERROR, ).length; const numberOfTestSkipped = mappingEditorState.DEPRECATED_mappingTestStates.filter( (testState) => testState.isSkipped, ).length; const percentageTestRun = Math.floor( (mappingEditorState.DEPRECATED_mappingTestStates.filter( (testState) => testState.result !== TEST_RESULT.NONE, ).length / numberOfTests) * 100, ); let testReportSummary = ''; switch (mappingEditorState.testSuiteResult) { case TEST_RESULT.NONE: testReportSummary = mappingEditorState.isRunningAllTests ? `Running ${numberOfTests} tests...` : 'No tests run!'; break; case TEST_RESULT.FAILED: testReportSummary = `${numberOfTestsFailed} of ${numberOfTests} failed`; break; case TEST_RESULT.PASSED: testReportSummary = numberOfTestsPassed === numberOfTests ? `All ${numberOfTests} passed` : `${numberOfTestsPassed} of ${numberOfTests} passed`; break; default: break; } // Drag and Drop const handleDrop = useCallback( (item: MappingElementDragSource): void => { if (isReadOnly) { return; } if (item.data instanceof SetImplementation) { flowResult(mappingEditorState.createNewTest(item.data)).catch( applicationStore.alertUnhandledError, ); } }, [applicationStore.alertUnhandledError, isReadOnly, mappingEditorState], ); const [{ isDragOver }, dropConnector] = useDrop< MappingElementDragSource, void, { isDragOver: boolean } >( () => ({ accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING, drop: (item) => handleDrop(item), collect: (monitor) => ({ isDragOver: monitor.isOver({ shallow: true }), }), }), [handleDrop], ); // Class mapping selector const [openClassMappingSelectorModal, setOpenClassMappingSelectorModal] = useState(false); const openMigrationtool = (): void => mappingEditorState.openMigrationTool(); const showClassMappingSelectorModal = (): void => setOpenClassMappingSelectorModal(true); const hideClassMappingSelectorModal = (): void => setOpenClassMappingSelectorModal(false); const changeClassMapping = useCallback( (setImplementation: SetImplementation | undefined): void => { if (setImplementation) { flowResult(mappingEditorState.createNewTest(setImplementation)).catch( applicationStore.alertUnhandledError, ); hideClassMappingSelectorModal(); } }, [applicationStore, mappingEditorState], ); return (
{numberOfTests} total
{numberOfTestsPassed} passed
{numberOfTestsFailed} failed
{Boolean(numberOfTestSkipped) && (
{numberOfTestSkipped} skipped
)}
{mappingEditorState.testSuiteResult !== TEST_RESULT.NONE && (
{mappingEditorState.allTestRunTime}ms
)}
{Boolean(mappingEditorState.mapping.test.length) && ( )}
} menuProps={{ elevation: 7 }} >
{Boolean( mappingEditorState.DEPRECATED_mappingTestStates.length, ) && mappingEditorState.DEPRECATED_mappingTestStates.slice().map( (testState) => ( ), )}
{openClassMappingSelectorModal && ( )}
); }, );