@finos/legend-studio
Version:
279 lines (264 loc) • 9.68 kB
text/typescript
/**
* 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 { observable, action, flow, makeObservable } from 'mobx';
import { EditorState } from './EditorState.js';
import {
type GeneratorFn,
assertErrorThrown,
LogEvent,
UnsupportedOperationError,
isNonNullable,
} from '@finos/legend-shared';
import { LEGEND_STUDIO_APP_EVENT } from '../LegendStudioAppEvent.js';
import type { EditorStore } from '../EditorStore.js';
import type { Entity } from '@finos/legend-model-storage';
import {
type ImportConfigurationDescription,
ImportMode,
} from '@finos/legend-graph';
import { TAB_SIZE } from '@finos/legend-application';
import type {
ModelLoaderExtensionConfiguration,
LegendStudioApplicationPlugin,
} from '../LegendStudioApplicationPlugin.js';
export enum MODEL_UPDATER_INPUT_TYPE {
ENTITIES = 'ENTITIES',
PURE_PROTOCOL = 'PURE_PROTOCOL',
PURE_GRAMMAR = 'PURE_GRAMMAR',
}
export class ModelLoaderState extends EditorState {
modelText = this.getExampleEntitiesInputText();
currentModelLoadType: MODEL_UPDATER_INPUT_TYPE | string =
MODEL_UPDATER_INPUT_TYPE.ENTITIES;
// TODO: remove model import in favor of external formats
modelImportDescriptions: ImportConfigurationDescription[] = [];
modelLoaderExtensionConfigurations: ModelLoaderExtensionConfiguration[] = [];
replace = true;
isLoadingModel = false;
constructor(editorStore: EditorStore) {
super(editorStore);
makeObservable(this, {
modelText: observable,
currentModelLoadType: observable,
modelImportDescriptions: observable,
modelLoaderExtensionConfigurations: observable,
replace: observable,
isLoadingModel: observable,
setReplaceFlag: action,
setModelText: action,
loadCurrentProjectEntities: flow,
loadModel: flow,
fetchAvailableModelImportDescriptions: flow,
});
//extensions
this.modelLoaderExtensionConfigurations = this.editorStore.pluginManager
.getApplicationPlugins()
.flatMap(
(plugin: LegendStudioApplicationPlugin) =>
plugin.getExtraModelLoaderExtensionConfigurations?.() ?? [],
)
.filter(isNonNullable);
}
get headerName(): string {
return 'Model Loader';
}
getImportConfigurationDescription(
key: string,
): ImportConfigurationDescription | undefined {
return this.modelImportDescriptions.find((i) => i.key === key);
}
getLoaderExtensionConfiguration(
key: string,
): ModelLoaderExtensionConfiguration | undefined {
return this.modelLoaderExtensionConfigurations.find(
(i) => i.modelGenerationConfig.key === key,
);
}
setReplaceFlag(val: boolean): void {
this.replace = val;
}
setModelText(modelText: string): void {
this.modelText = modelText;
}
setCurrentModelLoadType(
modelLoadType: MODEL_UPDATER_INPUT_TYPE | string,
): void {
if (modelLoadType !== this.currentModelLoadType) {
this.currentModelLoadType = modelLoadType;
this.modelText = this.getExampleText(modelLoadType);
}
}
getExampleText(inputType: MODEL_UPDATER_INPUT_TYPE | string): string {
if (inputType === MODEL_UPDATER_INPUT_TYPE.PURE_PROTOCOL) {
return this.getExamplePureProtocolInputText();
} else if (inputType === MODEL_UPDATER_INPUT_TYPE.ENTITIES) {
return this.getExampleEntitiesInputText();
} else if (this.getImportConfigurationDescription(inputType)) {
return this.getExampleExternalFormatInputText();
}
return '';
}
/**
* Current project entities will be taken from the current graph
* If graph is not parsable, we will fall back to model loader
*/
*loadCurrentProjectEntities(): GeneratorFn<void> {
switch (this.currentModelLoadType) {
case MODEL_UPDATER_INPUT_TYPE.PURE_PROTOCOL: {
const graphEntities = this.editorStore.graphManagerState.graphBuildState
.hasSucceeded
? this.editorStore.graphManagerState.graph.allOwnElements.map(
(element) =>
this.editorStore.graphManagerState.graphManager.elementToEntity(
element,
),
)
: this.editorStore.changeDetectionState
.workspaceLocalLatestRevisionState.entities;
this.modelText =
(yield this.editorStore.graphManagerState.graphManager.entitiesToPureProtocolText(
graphEntities,
)) as string;
break;
}
case MODEL_UPDATER_INPUT_TYPE.ENTITIES: {
const graphEntities = this.editorStore.graphManagerState.graphBuildState
.hasSucceeded
? this.editorStore.graphManagerState.graph.allOwnElements.map(
(element) =>
this.editorStore.graphManagerState.graphManager.elementToEntity(
element,
),
)
: this.editorStore.changeDetectionState
.workspaceLocalLatestRevisionState.entities;
this.modelText = JSON.stringify(graphEntities, undefined, TAB_SIZE);
break;
}
case MODEL_UPDATER_INPUT_TYPE.PURE_GRAMMAR: {
this.modelText =
(yield this.editorStore.graphManagerState.graphManager.graphToPureCode(
this.editorStore.graphManagerState.graph,
)) as string;
break;
}
default:
throw new UnsupportedOperationError(
`Can't load current project entities for input type of type '${this.currentModelLoadType}'`,
);
}
}
*loadModel(): GeneratorFn<void> {
try {
this.isLoadingModel = true;
this.editorStore.setBlockingAlert({
message: 'Loading model...',
prompt: 'Please do not close the application',
showLoading: true,
});
let entities: Entity[];
const externalConfigType = this.getImportConfigurationDescription(
this.currentModelLoadType,
);
if (externalConfigType) {
entities =
(yield this.editorStore.graphManagerState.graphManager.externalFormatTextToEntities(
this.modelText,
externalConfigType.key,
ImportMode.SCHEMA_IMPORT,
)) as Entity[];
} else {
switch (this.currentModelLoadType) {
case MODEL_UPDATER_INPUT_TYPE.PURE_PROTOCOL: {
entities =
this.editorStore.graphManagerState.graphManager.pureProtocolTextToEntities(
this.modelText,
);
break;
}
case MODEL_UPDATER_INPUT_TYPE.ENTITIES: {
entities = JSON.parse(this.modelText) as Entity[];
break;
}
case MODEL_UPDATER_INPUT_TYPE.PURE_GRAMMAR: {
entities =
(yield this.editorStore.graphManagerState.graphManager.pureCodeToEntities(
this.modelText,
)) as Entity[];
break;
}
default:
throw new UnsupportedOperationError(
`Can't load model for input of type '${this.currentModelLoadType}'`,
);
}
}
const message = `loading entities from ${
this.editorStore.applicationStore.config.appName
} [${this.replace ? `potentially affected ` : ''} ${
entities.length
} entities]`;
yield this.editorStore.sdlcServerClient.updateEntities(
this.editorStore.sdlcState.activeProject.projectId,
this.editorStore.sdlcState.activeWorkspace,
{ replace: this.replace, entities, message },
);
this.editorStore.applicationStore.navigator.reload();
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.MODEL_LOADER_FAILURE),
error,
);
this.editorStore.applicationStore.notifyError(error);
} finally {
this.isLoadingModel = false;
this.editorStore.setBlockingAlert(undefined);
}
}
*fetchAvailableModelImportDescriptions(): GeneratorFn<void> {
try {
this.modelImportDescriptions =
(yield this.editorStore.graphManagerState.graphManager.getAvailableImportConfigurationDescriptions()) as ImportConfigurationDescription[];
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.MODEL_LOADER_FAILURE),
error,
);
this.editorStore.applicationStore.notifyError(error);
}
}
private getExampleEntitiesInputText(): string {
return `// example entity\n${JSON.stringify(
[
{
classifierPath: 'string',
content: {},
path: 'string',
} as Entity,
],
undefined,
TAB_SIZE,
)}`;
}
private getExamplePureProtocolInputText(): string {
return `// example Pure model context data\n${this.editorStore.graphManagerState.graphManager.getExamplePureProtocolText()}`;
}
private getExampleExternalFormatInputText(): string {
return `// example external format import data\n${this.editorStore.graphManagerState.graphManager.getExampleExternalFormatImportText()}`;
}
}