UNPKG

@finos/legend-application-studio

Version:
201 lines 15.5 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; /** * Copyright (c) 2025-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 React, { useState, useRef } from 'react'; import { BlankPanelPlaceholder, PanelContent, PanelHeader, PlusIcon, TimesIcon, LockIcon, TrashIcon, UploadIcon, FileImportIcon, Dialog, clsx, CustomSelectorInput, } from '@finos/legend-art'; import { RelationElement } from '@finos/legend-graph'; import { guaranteeNonNullable } from '@finos/legend-shared'; import { ActionAlertActionType, ActionAlertType, useApplicationNavigationContext, } from '@finos/legend-application'; import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../__lib__/LegendStudioApplicationNavigationContext.js'; import { useEditorStore } from '../../EditorStoreProvider.js'; const NewRelationElementModal = observer((props) => { const { isReadOnly, dataState } = props; const applicationStore = dataState.editorStore.applicationStore; let PathType; (function (PathType) { PathType["SCHEMA_TABLE"] = "Schema and Table"; })(PathType || (PathType = {})); const pathTypeOptions = Object.values(PathType).map((type) => ({ label: type, value: type, })); const [pathType, setPathType] = useState(pathTypeOptions[0]); const onPathTypeChange = (val) => { setPathType(val); }; const [schemaName, setSchemaName] = useState(); const [tableName, setTableName] = useState(); const changeSchemaValue = (event) => { setSchemaName(event.target.value); }; const changeTableValue = (event) => { setTableName(event.target.value); }; const closeModal = () => dataState.setShowNewRelationElementModal(false); const handleSubmit = () => { const path = []; if (pathType && schemaName && tableName) { path.push(schemaName); path.push(tableName); } const relationElement = new RelationElement(); relationElement.columns = []; relationElement.rows = []; relationElement.paths = path; dataState.addRelationElement(relationElement); closeModal(); }; return (_jsx(Dialog, { open: dataState.showNewRelationElementModal, onClose: closeModal, classes: { container: 'search-modal__container' }, slotProps: { paper: { classes: { root: 'search-modal__inner-container' }, }, }, children: _jsxs("form", { onSubmit: (event) => { event.preventDefault(); handleSubmit(); closeModal(); }, className: "modal modal--dark search-modal", children: [_jsx("div", { className: "modal__title", children: "Add Relation Element" }), _jsxs("div", { className: "relational-data-editor__identifier", children: [_jsx("div", { className: "relational-data-editor__identifier__values", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: pathTypeOptions, onChange: onPathTypeChange, value: pathType, isClearable: false, darkMode: !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled }) }), _jsxs(_Fragment, { children: [_jsx("div", { className: "relational-data-editor__identifier__values", children: _jsx("input", { className: "panel__content__form__section__input", disabled: isReadOnly, placeholder: "schemaName", value: schemaName, onChange: changeSchemaValue }) }), _jsx("div", { className: "relational-data-editor__identifier__values", children: _jsx("input", { className: "relational-data-editor__identifier__values panel__content__form__section__input", disabled: isReadOnly, placeholder: "tableName", value: tableName, onChange: changeTableValue }) })] })] }), _jsx("div", { className: "search-modal__actions", children: _jsx("button", { className: "btn btn--dark", disabled: isReadOnly, children: "Add" }) })] }) })); }); export const RelationElementEditor = observer((props) => { const { relationElementState, isReadOnly } = props; const editorStore = useEditorStore(); const embeddedData = relationElementState.relationElement; const [exportFormat, setExportFormat] = useState('json'); const fileInputRef = useRef(null); const addColumn = () => { if (!isReadOnly) { const columnName = `column_${embeddedData.columns.length + 1}`; relationElementState.addColumn(columnName); } }; const removeColumn = (index) => { if (!isReadOnly) { relationElementState.removeColumn(index); } }; const updateColumn = (index, value) => { if (!isReadOnly) { const column = embeddedData.columns[index]; if (column) { relationElementState.updateColumn(index, value); } } }; const addRow = () => { if (!isReadOnly) { relationElementState.addRow(); } }; const removeRow = (index) => { if (!isReadOnly) { relationElementState.removeRow(index); } }; const updateCellValue = (rowIndex, columnIndex, value) => { if (!isReadOnly) { relationElementState.updateRow(rowIndex, columnIndex, value); } }; const handleFileUpload = (event) => { const file = event.target.files?.[0]; if (file && file.type === 'text/csv') { const reader = new FileReader(); reader.onload = (e) => { const csvContent = e.target?.result; if (csvContent) { relationElementState.importCSV(csvContent); } }; reader.readAsText(file); } if (fileInputRef.current) { fileInputRef.current.value = ''; } }; const exportData = () => { let content = ''; let filename = ''; let mimeType = ''; switch (exportFormat) { case 'json': content = relationElementState.exportJSON(); filename = 'test_data.json'; mimeType = 'application/json'; break; case 'csv': content = relationElementState.exportCSV(); filename = 'test_data.csv'; mimeType = 'text/csv'; break; case 'sql': content = relationElementState.exportSQL(); filename = 'test_data.sql'; mimeType = 'text/sql'; break; default: content = relationElementState.exportJSON(); filename = 'test_data.json'; mimeType = 'application/json'; break; } const blob = new Blob([content], { type: mimeType }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handleClearData = () => { editorStore.applicationStore.alertService.setActionAlertInfo({ message: 'Are you sure you want to clear all test data?', type: ActionAlertType.CAUTION, actions: [ { label: 'Confirm', type: ActionAlertActionType.PROCEED_WITH_CAUTION, handler: () => { relationElementState.clearAllData(); }, }, { label: 'Cancel', type: ActionAlertActionType.PROCEED, default: true, }, ], }); }; return (_jsxs("div", { className: "relation-test-data-editor__content", children: [_jsxs("div", { className: "relation-test-data-editor__columns", children: [_jsxs("div", { className: "relation-test-data-editor__section-header", children: [_jsx("div", { className: "relation-test-data-editor__section-title", children: "Column Definitions" }), _jsx("button", { className: "btn--icon btn--dark btn--sm", onClick: addColumn, disabled: isReadOnly, title: "Add Column", children: _jsx(PlusIcon, {}) })] }), _jsx("div", { className: "relation-test-data-editor__columns-grid", children: embeddedData.columns.map((column, index) => (_jsxs("div", { className: "relation-test-data-editor__column-row", children: [_jsx("input", { className: "relation-test-data-editor__column-input", type: "text", value: column, onChange: (e) => updateColumn(index, e.target.value), placeholder: "Column Name", disabled: isReadOnly }), _jsx("button", { className: "btn--icon btn--caution btn--dark btn--sm", onClick: () => removeColumn(index), disabled: isReadOnly, title: "Remove Column", children: _jsx(TimesIcon, {}) })] }, `column-${guaranteeNonNullable(index)}`))) })] }), _jsxs("div", { className: "relation-test-data-editor__data", children: [_jsx("div", { className: "relation-test-data-editor__section-header", children: _jsxs("div", { className: "relation-test-data-editor__section-title", children: ["Test Data (", embeddedData.rows.length, " rows)"] }) }), embeddedData.rows.length === 0 ? (_jsx("div", { className: "relation-test-data-editor__empty-data", children: _jsx("div", { className: "relation-test-data-editor__empty-text", children: "No test data rows. Click \"+\" below to start entering data." }) })) : (_jsxs("div", { className: "relation-test-data-editor__data-grid", children: [_jsxs("div", { className: "relation-test-data-editor__data-header", children: [embeddedData.columns.map((column) => (_jsx("div", { className: "relation-test-data-editor__data-header-cell", children: column }, column))), _jsx("div", { className: "relation-test-data-editor__data-header-cell relation-test-data-editor__data-actions", children: "Actions" })] }), embeddedData.rows.map((row, rowIndex) => (_jsxs("div", { className: "relation-test-data-editor__data-row", children: [embeddedData.columns.map((column, columnIndex) => (_jsx("div", { className: "relation-test-data-editor__data-cell", children: _jsx("input", { type: "text", value: row.values[columnIndex] ?? '', onChange: (e) => updateCellValue(rowIndex, columnIndex, e.target.value), disabled: isReadOnly, className: "relation-test-data-editor__data-input" }) }, column))), _jsx("div", { className: "relation-test-data-editor__data-cell relation-test-data-editor__data-actions", children: _jsx("button", { className: "btn--icon btn--caution btn--dark btn--sm", onClick: () => removeRow(rowIndex), disabled: isReadOnly, title: "Remove Row", children: _jsx(TimesIcon, {}) }) })] }, `row-${guaranteeNonNullable(rowIndex)}`)))] })), _jsxs("div", { className: "relation-test-data-editor__export-controls", children: [_jsxs("div", { className: "relation-test-data-editor__export-controls__btn-group", children: [_jsx("button", { className: "btn--icon btn--dark btn--sm", onClick: addRow, disabled: isReadOnly || embeddedData.columns.length === 0, title: "Add Row", children: _jsx(PlusIcon, {}) }), _jsx("button", { className: "btn--icon btn--caution btn--dark btn--sm", onClick: handleClearData, disabled: isReadOnly || embeddedData.rows.length === 0, title: "Clear All Data", children: _jsx(TrashIcon, {}) })] }), _jsxs("div", { className: "relation-test-data-editor__export-format", children: [_jsx("label", { htmlFor: "exportFormat", children: "Export as:" }), _jsxs("select", { id: "exportFormat", value: exportFormat, onChange: (e) => setExportFormat(e.target.value), disabled: isReadOnly, className: "relation-test-data-editor__export-select", children: [_jsx("option", { value: "json", children: "JSON" }), _jsx("option", { value: "csv", children: "CSV" }), _jsx("option", { value: "sql", children: "SQL INSERT" })] }), _jsx("button", { className: "btn--icon btn--dark btn--sm", onClick: exportData, disabled: isReadOnly, title: `Export as ${exportFormat.toUpperCase()}`, children: _jsx(FileImportIcon, {}) })] }), _jsxs("div", { className: "relation-test-data-editor__import-controls", children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".csv", onChange: handleFileUpload, style: { display: 'none' }, disabled: isReadOnly }), _jsx("button", { className: "btn--icon btn--dark btn--sm", onClick: () => fileInputRef.current?.click(), disabled: isReadOnly, title: "Upload a file of CSV", children: _jsx(UploadIcon, {}) })] })] })] })] })); }); export const RelationElementsDataEditor = observer((props) => { const { dataState, isReadOnly } = props; useApplicationNavigationContext(LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.EMBEDDED_DATA_RELATIONAL_EDITOR); const addRelationElement = () => { dataState.setShowNewRelationElementModal(true); }; const changeRelationElement = (newRelationElement) => { dataState.setActiveRelationElement(newRelationElement); }; return (_jsxs("div", { className: "panel relation-test-data-editor", children: [_jsx(PanelHeader, { children: _jsxs("div", { className: "panel__header__title", children: [isReadOnly && (_jsx("div", { className: "panel__header__lock", children: _jsx(LockIcon, {}) })), _jsx("div", { className: "panel__header__title__label", children: dataState.label() })] }) }), _jsxs(PanelContent, { children: [_jsxs("div", { className: "panel__header service-editor__header--with-tabs", children: [_jsx("div", { className: "uml-element-editor__tabs", children: dataState.relationElementStates.map((relationElementState) => (_jsx("div", { onClick: () => changeRelationElement(relationElementState), className: clsx('service-editor__tab', { 'service-editor__tab--active': relationElementState === dataState.activeRelationElement, }), children: relationElementState.relationElement.paths.length > 1 ? (_jsx("span", { children: relationElementState.relationElement.paths.join('.') })) : (_jsx("span", { children: relationElementState.relationElement.paths[0] })) }, relationElementState.relationElement.paths.join('.')))) }), _jsx("button", { onClick: addRelationElement, disabled: isReadOnly, title: "Add Relation Element", children: _jsx(PlusIcon, {}) })] }), dataState.relationElementStates.length === 0 || dataState.activeRelationElement === undefined ? (_jsx(BlankPanelPlaceholder, { text: "Add a relation element to define your test data structure", onClick: addRelationElement, clickActionType: "add", tooltipText: "Add Relation Element", disabled: isReadOnly })) : (_jsx(RelationElementEditor, { relationElementState: dataState.activeRelationElement, isReadOnly: isReadOnly }))] }), dataState.showNewRelationElementModal && (_jsx(NewRelationElementModal, { dataState: dataState, isReadOnly: isReadOnly }))] })); }); //# sourceMappingURL=RelationElementsDataEditor.js.map