UNPKG

@finos/legend-studio

Version:
352 lines (314 loc) 10.3 kB
/** * 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 { type EmbeddedData, type Class, type DataElement, DataElementReference, ExternalFormatData, ModelStoreData, RelationalCSVData, RelationalCSVDataTable, } from '@finos/legend-graph'; import { ContentType, guaranteeNonEmptyString, tryToFormatLosslessJSONString, UnsupportedOperationError, } from '@finos/legend-shared'; import { action, makeObservable, observable } from 'mobx'; import type { DSLData_LegendStudioApplicationPlugin_Extension } from '../../../DSLData_LegendStudioApplicationPlugin_Extension.js'; import type { EditorStore } from '../../../EditorStore.js'; import { dataElementReference_setDataElement, externalFormatData_setContentType, externalFormatData_setData, modelStoreData_setInstance, relationalData_addTable, relationalData_deleteData, relationalData_setTableName, relationalData_setTableSchemaName, relationalData_setTableValues, } from '../../../graphModifier/DSLData_GraphModifierHelper.js'; import { EmbeddedDataType } from '../../ExternalFormatState.js'; export const createEmbeddedData = ( type: string, editorStore: EditorStore, ): EmbeddedData => { if (type === EmbeddedDataType.EXTERNAL_FORMAT_DATA) { const externalFormatData = new ExternalFormatData(); externalFormatData_setData(externalFormatData, ''); externalFormatData_setContentType( externalFormatData, guaranteeNonEmptyString( editorStore.graphState.graphGenerationState.externalFormatState .formatContentTypes[0], ), ); return externalFormatData; } else if (type === EmbeddedDataType.RELATIONAL_CSV) { const relational = new RelationalCSVData(); return relational; } else if (type === EmbeddedDataType.MODEL_STORE_DATA) { const modelStoreData = new ModelStoreData(); modelStoreData_setInstance(modelStoreData, new Map<Class, object>()); return modelStoreData; } else { const extraEmbeddedDataCreator = editorStore.pluginManager .getApplicationPlugins() .flatMap( (plugin) => ( plugin as DSLData_LegendStudioApplicationPlugin_Extension ).getExtraEmbeddedDataCreators?.() ?? [], ); for (const creator of extraEmbeddedDataCreator) { const embeddedData = creator(type); if (embeddedData) { return embeddedData; } } throw new UnsupportedOperationError( `Can't create embedded data: no compatible creators available from plugins`, type, ); } }; export abstract class EmbeddedDataState { editorStore: EditorStore; embeddedData: EmbeddedData; constructor(editorStore: EditorStore, embeddedData: EmbeddedData) { this.editorStore = editorStore; this.embeddedData = embeddedData; } abstract label(): string; } export class ExternalFormatDataState extends EmbeddedDataState { override embeddedData: ExternalFormatData; constructor(editorStore: EditorStore, embeddedData: ExternalFormatData) { super(editorStore, embeddedData); makeObservable(this, { format: action, }); this.embeddedData = embeddedData; } label(): string { return 'ExternalFormat Data'; } get supportsFormatting(): boolean { return this.embeddedData.contentType === ContentType.APPLICATION_JSON; } format(): void { externalFormatData_setData( this.embeddedData, tryToFormatLosslessJSONString(this.embeddedData.data), ); } } export class ModelStoreDataState extends EmbeddedDataState { override embeddedData: ModelStoreData; constructor(editorStore: EditorStore, embeddedData: ModelStoreData) { super(editorStore, embeddedData); this.embeddedData = embeddedData; } label(): string { return 'ModelStore Data'; } } export class RelationalCSVDataTableState { readonly editorStore: EditorStore; table: RelationalCSVDataTable; constructor(table: RelationalCSVDataTable, editorStore: EditorStore) { this.table = table; this.editorStore = editorStore; makeObservable(this, { table: observable, updateTableValues: action, }); } updateTableValues(val: string): void { relationalData_setTableValues(this.table, val); } } export class IdentifierTableState { table: RelationalCSVDataTable | undefined; dataState: RelationalCSVDataState; schemaName = ''; tableName = ''; constructor(dataState: RelationalCSVDataState) { this.dataState = dataState; makeObservable(this, { dataState: observable, schemaName: observable, tableName: observable, table: observable, setTableName: action, setSchemaName: action, setTable: action, handleSubmit: action, }); } setTable(table: RelationalCSVDataTable | undefined): void { this.table = table; if (table) { this.tableName = table.table; this.schemaName = table.schema; } } setTableName(val: string): void { this.tableName = val; } setSchemaName(val: string): void { this.schemaName = val; } get isEditingDisabled(): boolean { if (!(this.tableName && this.schemaName)) { return true; } return Boolean( this.dataState.embeddedData.tables.find( (t) => `${t.table}.${t.schema}` === `${this.tableName}.${this.schemaName}`, ), ); } handleSubmit(): void { const table = this.table ?? new RelationalCSVDataTable(); relationalData_setTableSchemaName(table, this.schemaName); relationalData_setTableName(table, this.tableName); if (!this.table) { table.values = ''; relationalData_addTable(this.dataState.embeddedData, table); this.dataState.changeSelectedTable(table); } } } export class RelationalCSVDataState extends EmbeddedDataState { override embeddedData: RelationalCSVData; showTableIdentifierModal = false; tableIdentifierState: IdentifierTableState; selectedTable: RelationalCSVDataTableState | undefined; constructor(editorStore: EditorStore, embeddedData: RelationalCSVData) { super(editorStore, embeddedData); makeObservable(this, { selectedTable: observable, showTableIdentifierModal: observable, deleteTable: observable, tableIdentifierState: observable, resetSelectedTable: action, changeSelectedTable: action, closeModal: action, openIdentifierModal: action, }); this.embeddedData = embeddedData; this.tableIdentifierState = new IdentifierTableState(this); this.resetSelectedTable(); } openIdentifierModal(renameTable?: RelationalCSVDataTable | undefined): void { this.showTableIdentifierModal = true; this.tableIdentifierState.setTable(renameTable); } closeModal(): void { this.tableIdentifierState.setSchemaName(''); this.tableIdentifierState.setTableName(''); this.showTableIdentifierModal = false; } resetSelectedTable(): void { const table = this.embeddedData.tables[0]; if (table) { this.selectedTable = new RelationalCSVDataTableState( table, this.editorStore, ); } else { this.selectedTable = undefined; } } deleteTable(val: RelationalCSVDataTable): void { relationalData_deleteData(this.embeddedData, val); if (this.selectedTable?.table === val) { this.resetSelectedTable(); } } changeSelectedTable(val: RelationalCSVDataTable): void { this.selectedTable = new RelationalCSVDataTableState(val, this.editorStore); } label(): string { return 'Relational Data'; } } export class DataElementReferenceState extends EmbeddedDataState { override embeddedData: DataElementReference; embeddedDataValueState: EmbeddedDataState; constructor(editorStore: EditorStore, embeddedData: DataElementReference) { super(editorStore, embeddedData); this.embeddedData = embeddedData; this.embeddedDataValueState = this.buildValueState(); } label(): string { return 'Data Element Reference'; } setDataElement(dataElement: DataElement): void { dataElementReference_setDataElement( this.embeddedData, dataElement, this.editorStore.changeDetectionState.observerContext, ); this.embeddedDataValueState = this.buildValueState(); } buildValueState(): EmbeddedDataState { return buildEmbeddedDataEditorState( this.embeddedData.dataElement.value.data, this.editorStore, ); } } export class UnsupportedDataState extends EmbeddedDataState { label(): string { return 'Unsupported embedded data'; } } export function buildEmbeddedDataEditorState( _embeddedData: EmbeddedData, editorStore: EditorStore, ): EmbeddedDataState { const embeddedData = _embeddedData; if (embeddedData instanceof ExternalFormatData) { return new ExternalFormatDataState(editorStore, embeddedData); } else if (embeddedData instanceof ModelStoreData) { return new ModelStoreDataState(editorStore, embeddedData); } else if (embeddedData instanceof RelationalCSVData) { return new RelationalCSVDataState(editorStore, embeddedData); } else if (embeddedData instanceof DataElementReference) { return new DataElementReferenceState(editorStore, embeddedData); } else { const extraEmbeddedDataEditorStateBuilders = editorStore.pluginManager .getApplicationPlugins() .flatMap( (plugin) => ( plugin as DSLData_LegendStudioApplicationPlugin_Extension ).getExtraEmbeddedDataEditorStateBuilders?.() ?? [], ); for (const stateBuilder of extraEmbeddedDataEditorStateBuilders) { const state = stateBuilder(editorStore, embeddedData); if (state) { return state; } } return new UnsupportedDataState(editorStore, embeddedData); } }