@finos/legend-application-studio 28.18.123 → 28.18.125

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/lib/__lib__/LegendStudioNavigation.d.ts +7 -0
  2. package/lib/__lib__/LegendStudioNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioNavigation.js +5 -0
  4. package/lib/__lib__/LegendStudioNavigation.js.map +1 -1
  5. package/lib/application/LegendIngestionConfiguration.d.ts +40 -0
  6. package/lib/application/LegendIngestionConfiguration.d.ts.map +1 -0
  7. package/lib/application/LegendIngestionConfiguration.js +57 -0
  8. package/lib/application/LegendIngestionConfiguration.js.map +1 -0
  9. package/lib/application/LegendStudioApplicationConfig.d.ts +2 -0
  10. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  11. package/lib/application/LegendStudioApplicationConfig.js +6 -0
  12. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  13. package/lib/components/ElementIconUtils.d.ts.map +1 -1
  14. package/lib/components/ElementIconUtils.js +3 -1
  15. package/lib/components/ElementIconUtils.js.map +1 -1
  16. package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
  17. package/lib/components/LegendStudioWebApplication.js +16 -0
  18. package/lib/components/LegendStudioWebApplication.js.map +1 -1
  19. package/lib/components/editor/Editor.d.ts.map +1 -1
  20. package/lib/components/editor/Editor.js +3 -2
  21. package/lib/components/editor/Editor.js.map +1 -1
  22. package/lib/components/editor/editor-group/EditorGroup.d.ts.map +1 -1
  23. package/lib/components/editor/editor-group/EditorGroup.js +5 -0
  24. package/lib/components/editor/editor-group/EditorGroup.js.map +1 -1
  25. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.d.ts +19 -0
  26. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.d.ts.map +1 -0
  27. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js +71 -0
  28. package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js.map +1 -0
  29. package/lib/components/lazy-text-editor/LazyTextEditor.js +1 -1
  30. package/lib/components/lazy-text-editor/LazyTextEditor.js.map +1 -1
  31. package/lib/index.css +1 -1
  32. package/lib/package.json +3 -1
  33. package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
  34. package/lib/stores/editor/EditorGraphState.js +4 -1
  35. package/lib/stores/editor/EditorGraphState.js.map +1 -1
  36. package/lib/stores/editor/EditorStore.d.ts +6 -2
  37. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  38. package/lib/stores/editor/EditorStore.js +21 -4
  39. package/lib/stores/editor/EditorStore.js.map +1 -1
  40. package/lib/stores/editor/EditorTabManagerState.d.ts +2 -1
  41. package/lib/stores/editor/EditorTabManagerState.d.ts.map +1 -1
  42. package/lib/stores/editor/EditorTabManagerState.js +6 -2
  43. package/lib/stores/editor/EditorTabManagerState.js.map +1 -1
  44. package/lib/stores/editor/GraphEditFormModeState.d.ts +2 -1
  45. package/lib/stores/editor/GraphEditFormModeState.d.ts.map +1 -1
  46. package/lib/stores/editor/GraphEditFormModeState.js +2 -2
  47. package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
  48. package/lib/stores/editor/GraphEditorMode.d.ts +2 -1
  49. package/lib/stores/editor/GraphEditorMode.d.ts.map +1 -1
  50. package/lib/stores/editor/GraphEditorMode.js.map +1 -1
  51. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts +30 -0
  52. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.d.ts.map +1 -0
  53. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js +50 -0
  54. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.js.map +1 -0
  55. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.d.ts +2 -1
  56. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.d.ts.map +1 -1
  57. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.js +1 -1
  58. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.js.map +1 -1
  59. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts +37 -0
  60. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts.map +1 -0
  61. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js +107 -0
  62. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js.map +1 -0
  63. package/lib/stores/editor/utils/ModelClassifierUtils.d.ts +2 -1
  64. package/lib/stores/editor/utils/ModelClassifierUtils.d.ts.map +1 -1
  65. package/lib/stores/editor/utils/ModelClassifierUtils.js +1 -0
  66. package/lib/stores/editor/utils/ModelClassifierUtils.js.map +1 -1
  67. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts +29 -0
  68. package/lib/stores/ingestion/IngestDeploymentServerClient.d.ts.map +1 -0
  69. package/lib/stores/ingestion/IngestDeploymentServerClient.js +49 -0
  70. package/lib/stores/ingestion/IngestDeploymentServerClient.js.map +1 -0
  71. package/lib/stores/ingestion/IngestDiscoveryServerClient.d.ts +26 -0
  72. package/lib/stores/ingestion/IngestDiscoveryServerClient.d.ts.map +1 -0
  73. package/lib/stores/ingestion/IngestDiscoveryServerClient.js +35 -0
  74. package/lib/stores/ingestion/IngestDiscoveryServerClient.js.map +1 -0
  75. package/lib/stores/ingestion/IngestionDeploymentResponse.d.ts +30 -0
  76. package/lib/stores/ingestion/IngestionDeploymentResponse.d.ts.map +1 -0
  77. package/lib/stores/ingestion/IngestionDeploymentResponse.js +37 -0
  78. package/lib/stores/ingestion/IngestionDeploymentResponse.js.map +1 -0
  79. package/lib/stores/ingestion/IngestionManager.d.ts +35 -0
  80. package/lib/stores/ingestion/IngestionManager.d.ts.map +1 -0
  81. package/lib/stores/ingestion/IngestionManager.js +80 -0
  82. package/lib/stores/ingestion/IngestionManager.js.map +1 -0
  83. package/package.json +10 -8
  84. package/src/__lib__/LegendStudioNavigation.ts +14 -0
  85. package/src/application/LegendIngestionConfiguration.ts +94 -0
  86. package/src/application/LegendStudioApplicationConfig.ts +15 -0
  87. package/src/components/ElementIconUtils.tsx +3 -0
  88. package/src/components/LegendStudioWebApplication.tsx +29 -0
  89. package/src/components/editor/Editor.tsx +8 -3
  90. package/src/components/editor/editor-group/EditorGroup.tsx +4 -1
  91. package/src/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.tsx +156 -0
  92. package/src/components/lazy-text-editor/LazyTextEditor.tsx +1 -1
  93. package/src/stores/editor/EditorGraphState.ts +3 -0
  94. package/src/stores/editor/EditorStore.ts +39 -1
  95. package/src/stores/editor/EditorTabManagerState.ts +6 -0
  96. package/src/stores/editor/GraphEditFormModeState.ts +9 -2
  97. package/src/stores/editor/GraphEditorMode.ts +5 -1
  98. package/src/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.ts +97 -0
  99. package/src/stores/editor/editor-state/element-editor-state/ElementEditorState.ts +6 -1
  100. package/src/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.ts +169 -0
  101. package/src/stores/editor/utils/ModelClassifierUtils.ts +1 -0
  102. package/src/stores/ingestion/IngestDeploymentServerClient.ts +83 -0
  103. package/src/stores/ingestion/IngestDiscoveryServerClient.ts +52 -0
  104. package/src/stores/ingestion/IngestionDeploymentResponse.ts +45 -0
  105. package/src/stores/ingestion/IngestionManager.ts +151 -0
  106. package/tsconfig.json +8 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ SerializationFactory,
19
+ UnsupportedOperationError,
20
+ usingConstantValueSchema,
21
+ type PlainObject,
22
+ } from '@finos/legend-shared';
23
+ import { PACKAGEABLE_ELEMENT_TYPE } from '../../utils/ModelClassifierUtils.js';
24
+ import {
25
+ createModelSchema,
26
+ custom,
27
+ deserialize,
28
+ optional,
29
+ primitive,
30
+ serialize,
31
+ } from 'serializr';
32
+
33
+ export abstract class ElementEditorInitialConfiguration {
34
+ abstract type: PACKAGEABLE_ELEMENT_TYPE;
35
+ }
36
+
37
+ export class IngestElementEditorInitialConfiguration extends ElementEditorInitialConfiguration {
38
+ deployOnOpen?: boolean;
39
+ type = PACKAGEABLE_ELEMENT_TYPE.INGEST_DEFINITION;
40
+
41
+ static readonly serialization = new SerializationFactory(
42
+ createModelSchema(IngestElementEditorInitialConfiguration, {
43
+ _type: usingConstantValueSchema(
44
+ PACKAGEABLE_ELEMENT_TYPE.INGEST_DEFINITION,
45
+ ),
46
+ deployOnOpen: optional(primitive()),
47
+ }),
48
+ );
49
+ }
50
+
51
+ const serializeElementEditorInitialConfiguration = (
52
+ protocol: ElementEditorInitialConfiguration,
53
+ ): PlainObject<ElementEditorInitialConfiguration> => {
54
+ if (protocol instanceof IngestElementEditorInitialConfiguration) {
55
+ return serialize(
56
+ IngestElementEditorInitialConfiguration.serialization.schema,
57
+ protocol,
58
+ );
59
+ }
60
+ throw new UnsupportedOperationError(
61
+ `Can't serialize element config`,
62
+ protocol,
63
+ );
64
+ };
65
+
66
+ const deseralizeElementEditorInitialConfiguration = (
67
+ json: PlainObject<ElementEditorInitialConfiguration>,
68
+ ): ElementEditorInitialConfiguration => {
69
+ switch (json._type) {
70
+ case PACKAGEABLE_ELEMENT_TYPE.INGEST_DEFINITION:
71
+ return deserialize(
72
+ IngestElementEditorInitialConfiguration.serialization.schema,
73
+ json,
74
+ );
75
+ default: {
76
+ throw new UnsupportedOperationError(
77
+ `Can't deserialize element config`,
78
+ json,
79
+ );
80
+ }
81
+ }
82
+ };
83
+
84
+ export class EditorInitialConfiguration {
85
+ elementEditorConfiguration?: ElementEditorInitialConfiguration;
86
+
87
+ static readonly serialization = new SerializationFactory(
88
+ createModelSchema(EditorInitialConfiguration, {
89
+ elementEditorConfiguration: optional(
90
+ custom(
91
+ serializeElementEditorInitialConfiguration,
92
+ deseralizeElementEditorInitialConfiguration,
93
+ ),
94
+ ),
95
+ }),
96
+ );
97
+ }
@@ -36,6 +36,7 @@ import {
36
36
  import { DEFAULT_TAB_SIZE } from '@finos/legend-application';
37
37
  import type { ElementFileGenerationState } from './ElementFileGenerationState.js';
38
38
  import type { ElementXTSchemaGenerationState } from './ElementExternalFormatGenerationState.js';
39
+ import type { EditorInitialConfiguration } from './ElementEditorInitialConfiguration.js';
39
40
 
40
41
  const generateMultiLineCommentForError = (
41
42
  message: string,
@@ -104,7 +105,11 @@ export abstract class ElementEditorState extends EditorState {
104
105
  textContent = '';
105
106
  isReadOnly = false;
106
107
 
107
- constructor(editorStore: EditorStore, element: PackageableElement) {
108
+ constructor(
109
+ editorStore: EditorStore,
110
+ element: PackageableElement,
111
+ config?: EditorInitialConfiguration | undefined,
112
+ ) {
108
113
  super(editorStore);
109
114
 
110
115
  makeObservable(this, {
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { IngestDefinition, type PackageableElement } from '@finos/legend-graph';
18
+ import { ElementEditorState } from '../ElementEditorState.js';
19
+ import type { EditorStore } from '../../../EditorStore.js';
20
+ import {
21
+ ActionState,
22
+ assertErrorThrown,
23
+ assertTrue,
24
+ guaranteeNonNullable,
25
+ guaranteeType,
26
+ type GeneratorFn,
27
+ } from '@finos/legend-shared';
28
+ import type { IngestionManager } from '../../../../ingestion/IngestionManager.js';
29
+ import { flow, flowResult, makeObservable, observable } from 'mobx';
30
+ import type { IngestDefinitionDeploymentResponse } from '../../../../ingestion/IngestionDeploymentResponse.js';
31
+ import {
32
+ EditorInitialConfiguration,
33
+ IngestElementEditorInitialConfiguration,
34
+ } from '../ElementEditorInitialConfiguration.js';
35
+ import type { AuthContextProps } from 'react-oidc-context';
36
+ import { EXTERNAL_APPLICATION_NAVIGATION__generateUrlWithEditorConfig } from '../../../../../__lib__/LegendStudioNavigation.js';
37
+
38
+ const createEditorInitialConfiguration = (): EditorInitialConfiguration => {
39
+ const config = new EditorInitialConfiguration();
40
+ const ingest = new IngestElementEditorInitialConfiguration();
41
+ ingest.deployOnOpen = true;
42
+ config.elementEditorConfiguration = ingest;
43
+ return config;
44
+ };
45
+
46
+ const editorInitialConfigToBase64 = (val: EditorInitialConfiguration): string =>
47
+ btoa(JSON.stringify(EditorInitialConfiguration.serialization.toJson(val)));
48
+
49
+ export const generateUrlToDeployOnOpen = (
50
+ val: IngestDefinitionEditorState,
51
+ ): string => {
52
+ return val.editorStore.applicationStore.navigationService.navigator.generateAddress(
53
+ EXTERNAL_APPLICATION_NAVIGATION__generateUrlWithEditorConfig(
54
+ val.editorStore.editorMode.generateElementLink(val.ingest.path),
55
+ editorInitialConfigToBase64(createEditorInitialConfiguration()),
56
+ ),
57
+ );
58
+ };
59
+ export class IngestDefinitionEditorState extends ElementEditorState {
60
+ deploymentState = ActionState.create();
61
+ deployOnOpen = false;
62
+
63
+ constructor(
64
+ editorStore: EditorStore,
65
+ element: PackageableElement,
66
+ config?: EditorInitialConfiguration,
67
+ ) {
68
+ super(editorStore, element);
69
+
70
+ makeObservable(this, {
71
+ deploymentState: observable,
72
+ deployOnOpen: observable,
73
+ setDeployOnOpen: observable,
74
+ init_with_deploy: flow,
75
+ deploy: flow,
76
+ });
77
+ const elementConfig = config?.elementEditorConfiguration;
78
+ if (elementConfig instanceof IngestElementEditorInitialConfiguration) {
79
+ this.deployOnOpen = elementConfig.deployOnOpen ?? false;
80
+ }
81
+ }
82
+
83
+ get ingestionManager(): IngestionManager | undefined {
84
+ return this.editorStore.ingestionManager;
85
+ }
86
+
87
+ setDeployOnOpen(value: boolean): void {
88
+ this.deployOnOpen = value;
89
+ }
90
+
91
+ *init_with_deploy(auth: AuthContextProps): GeneratorFn<void> {
92
+ this.setDeployOnOpen(false);
93
+ if (!auth.isAuthenticated) {
94
+ auth
95
+ .signinRedirect({
96
+ state: generateUrlToDeployOnOpen(this),
97
+ })
98
+ .catch(this.editorStore.applicationStore.alertUnhandledError);
99
+ return;
100
+ }
101
+ const token = auth.user?.access_token;
102
+ yield flowResult(this.generateElementGrammar()).catch(
103
+ this.editorStore.applicationStore.alertUnhandledError,
104
+ );
105
+ flowResult(this.deploy(token)).catch(
106
+ this.editorStore.applicationStore.alertUnhandledError,
107
+ );
108
+ }
109
+
110
+ *deploy(token: string | undefined): GeneratorFn<void> {
111
+ try {
112
+ assertTrue(
113
+ this.validForDeployment,
114
+ 'Ingest definition is not valid for deployment',
115
+ );
116
+ this.deploymentState.inProgress();
117
+ const response = (yield guaranteeNonNullable(
118
+ this.ingestionManager,
119
+ ).deploy(
120
+ guaranteeNonNullable(this.textContent),
121
+ guaranteeNonNullable(this.ingest.appDirDeployment),
122
+ this.deploymentState,
123
+ token,
124
+ )) as unknown as IngestDefinitionDeploymentResponse;
125
+ this.editorStore.applicationStore.notificationService.notifySuccess(
126
+ `Ingest definition successfully deployed on ${response.ingestDefinitionUrn}`,
127
+ );
128
+ } catch (error) {
129
+ assertErrorThrown(error);
130
+ this.editorStore.applicationStore.notificationService.notifyError(
131
+ `Ingest definition failed to deploy: ${error.message}`,
132
+ );
133
+ } finally {
134
+ this.deploymentState.complete();
135
+ }
136
+ }
137
+
138
+ reprocess(
139
+ newElement: PackageableElement,
140
+ editorStore: EditorStore,
141
+ ): ElementEditorState {
142
+ return new IngestDefinitionEditorState(editorStore, newElement);
143
+ }
144
+
145
+ get validForDeployment(): boolean {
146
+ return Boolean(
147
+ this.ingest.appDirDeployment && this.textContent && this.ingestionManager,
148
+ );
149
+ }
150
+
151
+ get validationMessage(): string {
152
+ if (!this.ingest.appDirDeployment) {
153
+ return 'No app dir deployment found';
154
+ } else if (!this.textContent) {
155
+ return 'No ingest definition found';
156
+ } else if (!this.ingestionManager) {
157
+ return 'No ingestion manager found';
158
+ }
159
+ return 'Deploy';
160
+ }
161
+
162
+ get ingest(): IngestDefinition {
163
+ return guaranteeType(
164
+ this.element,
165
+ IngestDefinition,
166
+ 'Element inside ingest editor state must be a IngestDefinition',
167
+ );
168
+ }
169
+ }
@@ -76,6 +76,7 @@ export enum PACKAGEABLE_ELEMENT_TYPE {
76
76
 
77
77
  TEMPORARY__LOCAL_CONNECTION = 'LOCAL_CONNECTION',
78
78
  INTERNAL__UnknownElement = 'UNKNOWN',
79
+ INGEST_DEFINITION = 'INGEST_DEFINITION',
79
80
  }
80
81
 
81
82
  export enum PACKAGEABLE_ELEMENT_GROUP_BY_CATEGORY {
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ AbstractServerClient,
19
+ ContentType,
20
+ HttpHeader,
21
+ type PlainObject,
22
+ } from '@finos/legend-shared';
23
+ import { makeObservable, observable } from 'mobx';
24
+ import type {
25
+ IngestDefinitionDeploymentResponse,
26
+ IngestDefinitionValidationResponse,
27
+ } from './IngestionDeploymentResponse.js';
28
+ import type { IngestDeploymentServerConfig } from '../../application/LegendIngestionConfiguration.js';
29
+
30
+ export class IngestDeploymentServerClient extends AbstractServerClient {
31
+ environmentClassification: string;
32
+ constructor(config: IngestDeploymentServerConfig) {
33
+ super({
34
+ baseUrl: config.ingestServerUrl,
35
+ });
36
+ this.environmentClassification = config.environmentClassification;
37
+ makeObservable(this, {
38
+ environmentClassification: observable,
39
+ baseUrl: observable,
40
+ });
41
+ }
42
+
43
+ private _token = (token?: string) => ({
44
+ Authorization: `Bearer ${token}`,
45
+ });
46
+
47
+ private _tokenWithTextPlain = (token?: string) => ({
48
+ [HttpHeader.CONTENT_TYPE]: ContentType.TEXT_PLAIN,
49
+ Authorization: `Bearer ${token}`,
50
+ });
51
+
52
+ private _ingest = (): string =>
53
+ `${this.baseUrl}/ingest/sdlc/deploy/definitions`;
54
+
55
+ changeServer(serverConfig: IngestDeploymentServerConfig): void {
56
+ this.baseUrl = serverConfig.ingestServerUrl;
57
+ this.environmentClassification = serverConfig.environmentClassification;
58
+ }
59
+
60
+ validate(
61
+ validateGrammar: string,
62
+ token: string | undefined,
63
+ ): Promise<PlainObject<IngestDefinitionValidationResponse>> {
64
+ return this.post(
65
+ `${this._ingest()}/validate`,
66
+ validateGrammar,
67
+ undefined,
68
+ this._tokenWithTextPlain(token),
69
+ );
70
+ }
71
+
72
+ deploy(
73
+ deployGrammar: string,
74
+ token: string | undefined,
75
+ ): Promise<IngestDefinitionDeploymentResponse> {
76
+ return this.post(
77
+ `${this._ingest()}`,
78
+ deployGrammar,
79
+ undefined,
80
+ this._tokenWithTextPlain(token),
81
+ );
82
+ }
83
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { AbstractServerClient, type PlainObject } from '@finos/legend-shared';
18
+ import type { IngestDeploymentServerConfig } from '../../application/LegendIngestionConfiguration.js';
19
+
20
+ export class IngestDiscoveryServerClient extends AbstractServerClient {
21
+ constructor(url: string) {
22
+ super({
23
+ baseUrl: url,
24
+ });
25
+ }
26
+ private _ingest = (): string =>
27
+ `${this.baseUrl}/ingest/discovery/environments/producers`;
28
+
29
+ private _env = (): string => `${this.baseUrl}/ingest/discovery/environments`;
30
+
31
+ private _token = (token?: string) => ({
32
+ Authorization: `Bearer ${token}`,
33
+ });
34
+
35
+ discover(
36
+ token?: string | undefined,
37
+ ): Promise<PlainObject<IngestDeploymentServerConfig[]>> {
38
+ return this.get(`${this._env()}`, {}, this._token(token));
39
+ }
40
+
41
+ findProducerServer(
42
+ id: number,
43
+ level: string,
44
+ token?: string | undefined,
45
+ ): Promise<PlainObject<IngestDeploymentServerConfig>> {
46
+ return this.get(
47
+ `${this._ingest()}/${id}/${level}/search`,
48
+ {},
49
+ this._token(token),
50
+ );
51
+ }
52
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { SerializationFactory } from '@finos/legend-shared';
18
+ import { createModelSchema, primitive } from 'serializr';
19
+
20
+ export enum IngestDefinitionValidationResponseStatus {
21
+ NOT_CHECKED = 'NOT_CHECKED',
22
+ SUCCESS = 'SUCCESS',
23
+ FAILURE = 'FAILURE',
24
+ }
25
+
26
+ // TODO: include full response for user
27
+ export class IngestDefinitionValidationResponse {
28
+ status!: IngestDefinitionValidationResponseStatus;
29
+
30
+ static readonly serialization = new SerializationFactory(
31
+ createModelSchema(IngestDefinitionValidationResponse, {
32
+ status: primitive(),
33
+ }),
34
+ );
35
+ }
36
+
37
+ export class IngestDefinitionDeploymentResponse {
38
+ ingestDefinitionUrn!: string;
39
+
40
+ static readonly serialization = new SerializationFactory(
41
+ createModelSchema(IngestDefinitionDeploymentResponse, {
42
+ ingestDefinitionUrn: primitive(),
43
+ }),
44
+ );
45
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import type { AppDirNode } from '@finos/legend-graph';
18
+ import { IngestDeploymentServerClient } from './IngestDeploymentServerClient.js';
19
+ import { IngestDiscoveryServerClient } from './IngestDiscoveryServerClient.js';
20
+ import type { GenericLegendApplicationStore } from '@finos/legend-application';
21
+ import { type ActionState, type PlainObject } from '@finos/legend-shared';
22
+ import {
23
+ IngestDefinitionValidationResponse,
24
+ IngestDefinitionDeploymentResponse,
25
+ IngestDefinitionValidationResponseStatus,
26
+ } from './IngestionDeploymentResponse.js';
27
+ import {
28
+ IngestDeploymentServerConfig,
29
+ type LegendIngestionConfiguration,
30
+ } from '../../application/LegendIngestionConfiguration.js';
31
+
32
+ export class IngestionManager {
33
+ private ingestDiscoveryServerClient: IngestDiscoveryServerClient;
34
+ private ingestDeploymentServerClient: IngestDeploymentServerClient;
35
+ private _currentAppID: number | undefined;
36
+ private _currentLevel: string | undefined;
37
+ private readonly applicationStore: GenericLegendApplicationStore;
38
+
39
+ constructor(
40
+ config: LegendIngestionConfiguration,
41
+ applicationStore: GenericLegendApplicationStore,
42
+ ) {
43
+ this.ingestDiscoveryServerClient = new IngestDiscoveryServerClient(
44
+ config.discoveryUrl,
45
+ );
46
+ this.ingestDiscoveryServerClient.setTracerService(
47
+ applicationStore.tracerService,
48
+ );
49
+ this.ingestDeploymentServerClient = new IngestDeploymentServerClient(
50
+ config.deployment.defaultServer,
51
+ );
52
+ this.ingestDeploymentServerClient.setTracerService(
53
+ applicationStore.tracerService,
54
+ );
55
+ this.applicationStore = applicationStore;
56
+ }
57
+
58
+ isCurrentAppDirNode(appDirNode: AppDirNode): boolean {
59
+ return (
60
+ this._currentAppID === appDirNode.appDirId &&
61
+ this._currentLevel === appDirNode.level
62
+ );
63
+ }
64
+
65
+ setCurrentAppDirNode(appDirNode: AppDirNode): void {
66
+ this._currentAppID = appDirNode.appDirId;
67
+ this._currentLevel = appDirNode.level;
68
+ }
69
+
70
+ async deploy(
71
+ ingestDefinition: string,
72
+ appDirNode: AppDirNode,
73
+ actionState: ActionState | undefined,
74
+ token: string | undefined,
75
+ ): Promise<IngestDefinitionDeploymentResponse> {
76
+ actionState?.setMessage(
77
+ `Discovering associated ingest environment for DID ${appDirNode.appDirId}...`,
78
+ );
79
+ await this.identifyIngestDeploymentServer(appDirNode, token);
80
+ actionState?.setMessage(
81
+ `Validating ingest with server ${this.ingestDeploymentServerClient.baseUrl ?? ''} for realm ${this.ingestDeploymentServerClient.environmentClassification}...`,
82
+ );
83
+ const validateResonse = await this._validate(
84
+ ingestDefinition,
85
+ undefined,
86
+ token,
87
+ );
88
+ if (
89
+ validateResonse.status !==
90
+ IngestDefinitionValidationResponseStatus.SUCCESS
91
+ ) {
92
+ throw new Error('Failed to validate Ingest Definition');
93
+ }
94
+ actionState?.setMessage(
95
+ `Validation Success. Deploying ingest with server ${this.ingestDeploymentServerClient.baseUrl ?? ''} for realm ${this.ingestDeploymentServerClient.environmentClassification}...`,
96
+ );
97
+ return this._deploy(ingestDefinition, undefined, token);
98
+ }
99
+
100
+ private async _validate(
101
+ ingestDefinition: string,
102
+ appDirNode: AppDirNode | undefined,
103
+ token: string | undefined,
104
+ ): Promise<IngestDefinitionValidationResponse> {
105
+ if (appDirNode) {
106
+ await this.identifyIngestDeploymentServer(appDirNode, token);
107
+ }
108
+ // validate
109
+ const response = await this.ingestDeploymentServerClient.validate(
110
+ ingestDefinition,
111
+ token,
112
+ );
113
+ return IngestDefinitionValidationResponse.serialization.fromJson(response);
114
+ }
115
+
116
+ private async _deploy(
117
+ ingestDefinition: string,
118
+ appDirNode: AppDirNode | undefined,
119
+ token: string | undefined,
120
+ ): Promise<IngestDefinitionDeploymentResponse> {
121
+ if (appDirNode) {
122
+ await this.identifyIngestDeploymentServer(appDirNode, token);
123
+ }
124
+ // validate
125
+ const response = (await this.ingestDeploymentServerClient.deploy(
126
+ ingestDefinition,
127
+ token,
128
+ )) as unknown as PlainObject<IngestDefinitionDeploymentResponse>;
129
+ return IngestDefinitionDeploymentResponse.serialization.fromJson(response);
130
+ }
131
+
132
+ private async identifyIngestDeploymentServer(
133
+ appDirNode: AppDirNode,
134
+ token: string | undefined,
135
+ ): Promise<void> {
136
+ // we do not change if current appDirNode is the same as the one we are trying to set
137
+ if (this.isCurrentAppDirNode(appDirNode)) {
138
+ return;
139
+ }
140
+ const serverConfig = IngestDeploymentServerConfig.serialization.fromJson(
141
+ await this.ingestDiscoveryServerClient.findProducerServer(
142
+ appDirNode.appDirId,
143
+ appDirNode.level,
144
+ token,
145
+ ),
146
+ );
147
+
148
+ this.ingestDeploymentServerClient.changeServer(serverConfig);
149
+ this.setCurrentAppDirNode(appDirNode);
150
+ }
151
+ }
package/tsconfig.json CHANGED
@@ -67,6 +67,7 @@
67
67
  "./src/__lib__/LegendStudioTesting.ts",
68
68
  "./src/__lib__/LegendStudioUserDataHelper.ts",
69
69
  "./src/__lib__/STO_Relational_LegendStudioCommand.ts",
70
+ "./src/application/LegendIngestionConfiguration.ts",
70
71
  "./src/application/LegendStudioApplicationConfig.ts",
71
72
  "./src/application/LegendStudioPluginManager.ts",
72
73
  "./src/components/__test-utils__/EmbeddedQueryBuilderTestUtils.ts",
@@ -108,6 +109,7 @@
108
109
  "./src/stores/editor/editor-state/diff-viewer-state/ProjectConfigurationDiffEditorState.ts",
109
110
  "./src/stores/editor/editor-state/element-editor-state/ClassEditorState.ts",
110
111
  "./src/stores/editor/editor-state/element-editor-state/ClassState.ts",
112
+ "./src/stores/editor/editor-state/element-editor-state/ElementEditorInitialConfiguration.ts",
111
113
  "./src/stores/editor/editor-state/element-editor-state/ElementEditorState.ts",
112
114
  "./src/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.ts",
113
115
  "./src/stores/editor/editor-state/element-editor-state/ElementFileGenerationState.ts",
@@ -134,6 +136,7 @@
134
136
  "./src/stores/editor/editor-state/element-editor-state/function-activator/PostDeploymentActionEditorState.ts",
135
137
  "./src/stores/editor/editor-state/element-editor-state/function-activator/SnowflakeAppFunctionActivatorEditorState.ts",
136
138
  "./src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts",
139
+ "./src/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.ts",
137
140
  "./src/stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.ts",
138
141
  "./src/stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.ts",
139
142
  "./src/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.ts",
@@ -202,6 +205,10 @@
202
205
  "./src/stores/graph-modifier/STO_FlatData_GraphModifierHelper.ts",
203
206
  "./src/stores/graph-modifier/STO_Relational_GraphModifierHelper.ts",
204
207
  "./src/stores/graph-modifier/Testable_GraphModifierHelper.ts",
208
+ "./src/stores/ingestion/IngestDeploymentServerClient.ts",
209
+ "./src/stores/ingestion/IngestDiscoveryServerClient.ts",
210
+ "./src/stores/ingestion/IngestionDeploymentResponse.ts",
211
+ "./src/stores/ingestion/IngestionManager.ts",
205
212
  "./src/stores/lazy-text-editor/LazyTextEditorStore.ts",
206
213
  "./src/stores/project-reviewer/ProjectReviewerStore.ts",
207
214
  "./src/stores/project-view/ProjectViewerEditorMode.ts",
@@ -267,6 +274,7 @@
267
274
  "./src/components/editor/editor-group/function-activator/INTERNAL__UnknownFunctionActivatorEdtior.tsx",
268
275
  "./src/components/editor/editor-group/function-activator/SnowflakeAppFunctionActivatorEditor.tsx",
269
276
  "./src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx",
277
+ "./src/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.tsx",
270
278
  "./src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx",
271
279
  "./src/components/editor/editor-group/mapping-editor/EnumerationMappingEditor.tsx",
272
280
  "./src/components/editor/editor-group/mapping-editor/FlatDataPropertyMappingEditor.tsx",