@finos/legend-application-studio 19.1.0 → 20.0.1
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.
- package/lib/application/LegendStudioApplicationConfig.d.ts +6 -0
- package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
- package/lib/application/LegendStudioApplicationConfig.js +7 -0
- package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
- package/lib/components/EditorComponentTestUtils.d.ts +1 -1
- package/lib/components/EditorComponentTestUtils.d.ts.map +1 -1
- package/lib/components/EditorComponentTestUtils.js +23 -50
- package/lib/components/EditorComponentTestUtils.js.map +1 -1
- package/lib/components/editor/StatusBar.d.ts.map +1 -1
- package/lib/components/editor/StatusBar.js +10 -3
- package/lib/components/editor/StatusBar.js.map +1 -1
- package/lib/components/editor/aux-panel/AuxiliaryPanel.d.ts.map +1 -1
- package/lib/components/editor/aux-panel/AuxiliaryPanel.js +11 -3
- package/lib/components/editor/aux-panel/AuxiliaryPanel.js.map +1 -1
- package/lib/components/editor/aux-panel/Console.d.ts.map +1 -1
- package/lib/components/editor/aux-panel/Console.js +2 -1
- package/lib/components/editor/aux-panel/Console.js.map +1 -1
- package/lib/components/editor/aux-panel/DevTool.d.ts.map +1 -1
- package/lib/components/editor/aux-panel/DevTool.js +4 -7
- package/lib/components/editor/aux-panel/DevTool.js.map +1 -1
- package/lib/components/editor/aux-panel/Problems.d.ts +20 -0
- package/lib/components/editor/aux-panel/Problems.d.ts.map +1 -0
- package/lib/components/editor/aux-panel/Problems.js +48 -0
- package/lib/components/editor/aux-panel/Problems.js.map +1 -0
- package/lib/components/editor/edit-panel/GrammarTextEditor.d.ts.map +1 -1
- package/lib/components/editor/edit-panel/GrammarTextEditor.js +36 -25
- package/lib/components/editor/edit-panel/GrammarTextEditor.js.map +1 -1
- package/lib/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.js +16 -16
- package/lib/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.js.map +1 -1
- package/lib/components/editor/edit-panel/connection-editor/post-processor-editor/MapperPostProcessorEditor.d.ts.map +1 -1
- package/lib/components/editor/edit-panel/connection-editor/post-processor-editor/MapperPostProcessorEditor.js +4 -4
- package/lib/components/editor/edit-panel/connection-editor/post-processor-editor/MapperPostProcessorEditor.js.map +1 -1
- package/lib/components/editor/edit-panel/diff-editor/EntityChangeConflictEditor.js +20 -6
- package/lib/components/editor/edit-panel/diff-editor/EntityChangeConflictEditor.js.map +1 -1
- package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.d.ts.map +1 -1
- package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.js +2 -2
- package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.js.map +1 -1
- package/lib/components/editor/edit-panel/project-configuration-editor/ProjectConfigurationEditor.d.ts.map +1 -1
- package/lib/components/editor/edit-panel/project-configuration-editor/ProjectConfigurationEditor.js +2 -2
- package/lib/components/editor/edit-panel/project-configuration-editor/ProjectConfigurationEditor.js.map +1 -1
- package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
- package/lib/components/editor/side-bar/Explorer.js +3 -3
- package/lib/components/editor/side-bar/Explorer.js.map +1 -1
- package/lib/components/editor/side-bar/ProjectOverview.d.ts.map +1 -1
- package/lib/components/editor/side-bar/ProjectOverview.js +3 -3
- package/lib/components/editor/side-bar/ProjectOverview.js.map +1 -1
- package/lib/components/shared/DiffView.js +2 -2
- package/lib/components/shared/DiffView.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +6 -6
- package/lib/stores/ChangeDetectionState.d.ts +2 -0
- package/lib/stores/ChangeDetectionState.d.ts.map +1 -1
- package/lib/stores/ChangeDetectionState.js +12 -6
- package/lib/stores/ChangeDetectionState.js.map +1 -1
- package/lib/stores/EditorConfig.d.ts +2 -1
- package/lib/stores/EditorConfig.d.ts.map +1 -1
- package/lib/stores/EditorConfig.js +1 -0
- package/lib/stores/EditorConfig.js.map +1 -1
- package/lib/stores/EditorGraphState.d.ts +17 -16
- package/lib/stores/EditorGraphState.d.ts.map +1 -1
- package/lib/stores/EditorGraphState.js +152 -94
- package/lib/stores/EditorGraphState.js.map +1 -1
- package/lib/stores/EditorSDLCState.d.ts +6 -6
- package/lib/stores/EditorSDLCState.d.ts.map +1 -1
- package/lib/stores/EditorSDLCState.js +52 -27
- package/lib/stores/EditorSDLCState.js.map +1 -1
- package/lib/stores/EditorStore.js +1 -1
- package/lib/stores/EditorStore.js.map +1 -1
- package/lib/stores/EmbeddedQueryBuilderState.js +1 -1
- package/lib/stores/EmbeddedQueryBuilderState.js.map +1 -1
- package/lib/stores/editor/NewElementState.d.ts.map +1 -1
- package/lib/stores/editor/NewElementState.js +14 -5
- package/lib/stores/editor/NewElementState.js.map +1 -1
- package/lib/stores/editor/StandardEditorMode.d.ts.map +1 -1
- package/lib/stores/editor/StandardEditorMode.js +2 -2
- package/lib/stores/editor/StandardEditorMode.js.map +1 -1
- package/lib/stores/editor-state/FileGenerationState.d.ts +3 -3
- package/lib/stores/editor-state/FileGenerationState.d.ts.map +1 -1
- package/lib/stores/editor-state/FileGenerationState.js +9 -5
- package/lib/stores/editor-state/FileGenerationState.js.map +1 -1
- package/lib/stores/editor-state/GrammarTextEditorState.d.ts +6 -4
- package/lib/stores/editor-state/GrammarTextEditorState.d.ts.map +1 -1
- package/lib/stores/editor-state/GrammarTextEditorState.js +14 -8
- package/lib/stores/editor-state/GrammarTextEditorState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ClassEditorState.d.ts +0 -1
- package/lib/stores/editor-state/element-editor-state/ClassEditorState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ClassEditorState.js +0 -5
- package/lib/stores/editor-state/element-editor-state/ClassEditorState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ElementEditorState.d.ts +0 -1
- package/lib/stores/editor-state/element-editor-state/ElementEditorState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ElementEditorState.js +0 -3
- package/lib/stores/editor-state/element-editor-state/ElementEditorState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ElementFileGenerationState.d.ts +2 -2
- package/lib/stores/editor-state/element-editor-state/ElementFileGenerationState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/ElementFileGenerationState.js +5 -4
- package/lib/stores/editor-state/element-editor-state/ElementFileGenerationState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/FunctionEditorState.d.ts +0 -1
- package/lib/stores/editor-state/element-editor-state/FunctionEditorState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/FunctionEditorState.js +0 -4
- package/lib/stores/editor-state/element-editor-state/FunctionEditorState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.d.ts +0 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.js +0 -6
- package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.d.ts +6 -6
- package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.js +24 -14
- package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingTestState.d.ts +6 -6
- package/lib/stores/editor-state/element-editor-state/mapping/MappingTestState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/mapping/MappingTestState.js +30 -15
- package/lib/stores/editor-state/element-editor-state/mapping/MappingTestState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.js +1 -1
- package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.js.map +1 -1
- package/lib/stores/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts +4 -4
- package/lib/stores/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
- package/lib/stores/editor-state/element-editor-state/service/ServiceRegistrationState.js +54 -44
- package/lib/stores/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
- package/lib/stores/project-viewer/ProjectViewerStore.d.ts.map +1 -1
- package/lib/stores/project-viewer/ProjectViewerStore.js +1 -1
- package/lib/stores/project-viewer/ProjectViewerStore.js.map +1 -1
- package/lib/stores/sidebar-state/LocalChangesState.d.ts +13 -13
- package/lib/stores/sidebar-state/LocalChangesState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/LocalChangesState.js +71 -63
- package/lib/stores/sidebar-state/LocalChangesState.js.map +1 -1
- package/lib/stores/sidebar-state/ProjectOverviewState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/ProjectOverviewState.js +19 -4
- package/lib/stores/sidebar-state/ProjectOverviewState.js.map +1 -1
- package/lib/stores/sidebar-state/WorkflowManagerState.d.ts +8 -8
- package/lib/stores/sidebar-state/WorkflowManagerState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/WorkflowManagerState.js +15 -11
- package/lib/stores/sidebar-state/WorkflowManagerState.js.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceReviewState.d.ts +3 -3
- package/lib/stores/sidebar-state/WorkspaceReviewState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceReviewState.js +21 -6
- package/lib/stores/sidebar-state/WorkspaceReviewState.js.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceSyncState.d.ts +2 -2
- package/lib/stores/sidebar-state/WorkspaceSyncState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceSyncState.js +9 -7
- package/lib/stores/sidebar-state/WorkspaceSyncState.js.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceUpdaterState.d.ts +2 -2
- package/lib/stores/sidebar-state/WorkspaceUpdaterState.d.ts.map +1 -1
- package/lib/stores/sidebar-state/WorkspaceUpdaterState.js +8 -4
- package/lib/stores/sidebar-state/WorkspaceUpdaterState.js.map +1 -1
- package/lib/stores/workspace-review/WorkspaceReviewStore.d.ts +2 -2
- package/lib/stores/workspace-review/WorkspaceReviewStore.d.ts.map +1 -1
- package/lib/stores/workspace-review/WorkspaceReviewStore.js +27 -10
- package/lib/stores/workspace-review/WorkspaceReviewStore.js.map +1 -1
- package/package.json +15 -15
- package/src/application/LegendStudioApplicationConfig.ts +7 -0
- package/src/components/EditorComponentTestUtils.tsx +64 -60
- package/src/components/editor/StatusBar.tsx +38 -3
- package/src/components/editor/aux-panel/AuxiliaryPanel.tsx +32 -10
- package/src/components/editor/aux-panel/Console.tsx +4 -3
- package/src/components/editor/aux-panel/DevTool.tsx +47 -79
- package/src/components/editor/aux-panel/Problems.tsx +103 -0
- package/src/components/editor/edit-panel/GrammarTextEditor.tsx +48 -36
- package/src/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.tsx +61 -61
- package/src/components/editor/edit-panel/connection-editor/post-processor-editor/MapperPostProcessorEditor.tsx +21 -25
- package/src/components/editor/edit-panel/diff-editor/EntityChangeConflictEditor.tsx +23 -23
- package/src/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.tsx +2 -1
- package/src/components/editor/edit-panel/project-configuration-editor/ProjectConfigurationEditor.tsx +19 -22
- package/src/components/editor/side-bar/Explorer.tsx +5 -3
- package/src/components/editor/side-bar/ProjectOverview.tsx +5 -3
- package/src/components/shared/DiffView.tsx +2 -2
- package/src/stores/ChangeDetectionState.ts +17 -8
- package/src/stores/EditorConfig.ts +1 -0
- package/src/stores/EditorGraphState.ts +223 -136
- package/src/stores/EditorSDLCState.ts +65 -30
- package/src/stores/EditorStore.ts +1 -1
- package/src/stores/EmbeddedQueryBuilderState.ts +1 -1
- package/src/stores/editor/NewElementState.ts +24 -5
- package/src/stores/editor/StandardEditorMode.ts +4 -2
- package/src/stores/editor-state/FileGenerationState.ts +19 -8
- package/src/stores/editor-state/GrammarTextEditorState.ts +18 -10
- package/src/stores/editor-state/element-editor-state/ClassEditorState.ts +0 -12
- package/src/stores/editor-state/element-editor-state/ElementEditorState.ts +0 -4
- package/src/stores/editor-state/element-editor-state/ElementFileGenerationState.ts +8 -6
- package/src/stores/editor-state/element-editor-state/FunctionEditorState.ts +0 -5
- package/src/stores/editor-state/element-editor-state/mapping/MappingEditorState.ts +0 -11
- package/src/stores/editor-state/element-editor-state/mapping/MappingExecutionState.ts +29 -15
- package/src/stores/editor-state/element-editor-state/mapping/MappingTestState.ts +37 -23
- package/src/stores/editor-state/element-editor-state/service/ServiceExecutionState.ts +4 -3
- package/src/stores/editor-state/element-editor-state/service/ServiceRegistrationState.ts +63 -48
- package/src/stores/project-viewer/ProjectViewerStore.ts +5 -3
- package/src/stores/sidebar-state/LocalChangesState.ts +130 -115
- package/src/stores/sidebar-state/ProjectOverviewState.ts +19 -4
- package/src/stores/sidebar-state/WorkflowManagerState.ts +28 -31
- package/src/stores/sidebar-state/WorkspaceReviewState.ts +24 -8
- package/src/stores/sidebar-state/WorkspaceSyncState.ts +11 -16
- package/src/stores/sidebar-state/WorkspaceUpdaterState.ts +11 -7
- package/src/stores/workspace-review/WorkspaceReviewStore.ts +39 -12
- package/tsconfig.json +1 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { expect } from '@jest/globals';
|
|
18
18
|
import {
|
|
19
19
|
type RenderResult,
|
|
20
20
|
render,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
generateEditorRoute,
|
|
30
30
|
LEGEND_STUDIO_ROUTE_PATTERN,
|
|
31
31
|
} from '../stores/LegendStudioRouter.js';
|
|
32
|
-
import
|
|
32
|
+
import { createMock, createSpy, type PlainObject } from '@finos/legend-shared';
|
|
33
33
|
import { LegendStudioPluginManager } from '../application/LegendStudioPluginManager.js';
|
|
34
34
|
import type { Entity } from '@finos/legend-storage';
|
|
35
35
|
import {
|
|
@@ -165,7 +165,7 @@ export const TEST__provideMockedEditorStore = (customization?: {
|
|
|
165
165
|
TEST__getTestGraphManagerState(customization?.pluginManager),
|
|
166
166
|
);
|
|
167
167
|
const MockedEditorStoreProvider = require('./editor/EditorStoreProvider.js'); // eslint-disable-line @typescript-eslint/no-unsafe-assignment
|
|
168
|
-
MockedEditorStoreProvider.useEditorStore =
|
|
168
|
+
MockedEditorStoreProvider.useEditorStore = createMock();
|
|
169
169
|
MockedEditorStoreProvider.useEditorStore.mockReturnValue(value);
|
|
170
170
|
return value;
|
|
171
171
|
};
|
|
@@ -247,39 +247,41 @@ export const TEST__setUpEditor = async (
|
|
|
247
247
|
} = data;
|
|
248
248
|
|
|
249
249
|
// SDLC
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
.
|
|
250
|
+
createSpy(MOCK__editorStore.sdlcServerClient, 'getProject').mockResolvedValue(
|
|
251
|
+
project,
|
|
252
|
+
);
|
|
253
|
+
createSpy(
|
|
254
|
+
MOCK__editorStore.sdlcServerClient,
|
|
255
|
+
'getWorkspace',
|
|
256
|
+
).mockResolvedValue(workspace);
|
|
257
|
+
createSpy(
|
|
258
|
+
MOCK__editorStore.sdlcServerClient,
|
|
259
|
+
'getVersions',
|
|
260
|
+
).mockResolvedValue(projectVersions);
|
|
261
|
+
createSpy(
|
|
262
|
+
MOCK__editorStore.sdlcServerClient,
|
|
263
|
+
'getRevision',
|
|
264
|
+
).mockResolvedValue(curentRevision);
|
|
265
|
+
createSpy(
|
|
266
|
+
MOCK__editorStore.sdlcServerClient,
|
|
267
|
+
'checkIfWorkspaceIsInConflictResolutionMode',
|
|
268
|
+
).mockResolvedValue(false);
|
|
269
|
+
createSpy(
|
|
270
|
+
MOCK__editorStore.sdlcServerClient,
|
|
271
|
+
'isWorkspaceOutdated',
|
|
272
|
+
).mockResolvedValue(false);
|
|
273
|
+
createSpy(
|
|
274
|
+
MOCK__editorStore.sdlcServerClient,
|
|
275
|
+
'getEntities',
|
|
276
|
+
).mockResolvedValue(entities);
|
|
277
|
+
createSpy(
|
|
278
|
+
MOCK__editorStore.sdlcServerClient,
|
|
279
|
+
'getConfiguration',
|
|
280
|
+
).mockResolvedValue(projectConfiguration);
|
|
281
|
+
createSpy(
|
|
282
|
+
MOCK__editorStore.sdlcServerClient,
|
|
283
|
+
'getLatestProjectStructureVersion',
|
|
284
|
+
).mockResolvedValue(latestProjectStructureVersion);
|
|
283
285
|
MOCK__editorStore.sdlcServerClient._setFeatures(
|
|
284
286
|
SDLCServerFeaturesConfiguration.serialization.fromJson({
|
|
285
287
|
canCreateProject: true,
|
|
@@ -288,40 +290,42 @@ export const TEST__setUpEditor = async (
|
|
|
288
290
|
);
|
|
289
291
|
|
|
290
292
|
// depot
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
293
|
+
createSpy(
|
|
294
|
+
MOCK__editorStore.depotServerClient,
|
|
295
|
+
'getProjects',
|
|
296
|
+
).mockResolvedValue(projects);
|
|
297
|
+
createSpy(
|
|
298
|
+
MOCK__editorStore.depotServerClient,
|
|
299
|
+
'getProjectById',
|
|
300
|
+
).mockResolvedValue(projectData);
|
|
301
|
+
createSpy(
|
|
302
|
+
MOCK__editorStore.depotServerClient,
|
|
303
|
+
'collectDependencyEntities',
|
|
304
|
+
).mockResolvedValue(projectDependency);
|
|
305
|
+
createSpy(
|
|
306
|
+
MOCK__editorStore.depotServerClient,
|
|
307
|
+
'analyzeDependencyTree',
|
|
308
|
+
).mockResolvedValue(projectDependencyInfo);
|
|
303
309
|
|
|
304
310
|
// TODO: we need to think of how we will mock these calls when we modularize
|
|
305
311
|
const graphManagerState = MOCK__editorStore.graphManagerState;
|
|
306
|
-
graphManagerState.graphManager.initialize =
|
|
307
|
-
|
|
308
|
-
.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
)
|
|
312
|
-
.mockReturnValue(Promise.resolve(availableGenerationDescriptions));
|
|
312
|
+
graphManagerState.graphManager.initialize = createMock();
|
|
313
|
+
createSpy(
|
|
314
|
+
graphManagerState.graphManager,
|
|
315
|
+
'getAvailableGenerationConfigurationDescriptions',
|
|
316
|
+
).mockResolvedValue(availableGenerationDescriptions);
|
|
313
317
|
|
|
314
318
|
// mock change detections (since we do not test them now)
|
|
315
319
|
MOCK__editorStore.changeDetectionState.workspaceLocalLatestRevisionState.buildEntityHashesIndex =
|
|
316
|
-
|
|
320
|
+
createMock();
|
|
317
321
|
MOCK__editorStore.sdlcState.buildWorkspaceBaseRevisionEntityHashesIndex =
|
|
318
|
-
|
|
322
|
+
createMock();
|
|
319
323
|
MOCK__editorStore.sdlcState.buildProjectLatestRevisionEntityHashesIndex =
|
|
320
|
-
|
|
324
|
+
createMock();
|
|
321
325
|
MOCK__editorStore.workspaceReviewState.fetchCurrentWorkspaceReview =
|
|
322
|
-
|
|
326
|
+
createMock();
|
|
323
327
|
MOCK__editorStore.workspaceUpdaterState.fetchLatestCommittedReviews =
|
|
324
|
-
|
|
328
|
+
createMock();
|
|
325
329
|
|
|
326
330
|
const history = createMemoryHistory({
|
|
327
331
|
initialEntries: [
|
|
@@ -26,9 +26,11 @@ import {
|
|
|
26
26
|
BrushIcon,
|
|
27
27
|
CloudUploadIcon,
|
|
28
28
|
AssistantIcon,
|
|
29
|
+
ErrorIcon,
|
|
30
|
+
WarningIcon,
|
|
29
31
|
} from '@finos/legend-art';
|
|
30
32
|
import { LEGEND_STUDIO_TEST_ID } from '../LegendStudioTestID.js';
|
|
31
|
-
import { ACTIVITY_MODE } from '../../stores/EditorConfig.js';
|
|
33
|
+
import { ACTIVITY_MODE, AUX_PANEL_MODE } from '../../stores/EditorConfig.js';
|
|
32
34
|
import {
|
|
33
35
|
generateSetupRoute,
|
|
34
36
|
type WorkspaceEditorPathParams,
|
|
@@ -62,12 +64,14 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
62
64
|
? ACTIVITY_MODE.CONFLICT_RESOLUTION
|
|
63
65
|
: ACTIVITY_MODE.WORKSPACE_UPDATER,
|
|
64
66
|
);
|
|
67
|
+
|
|
65
68
|
const goToLocalChanges = (): void =>
|
|
66
69
|
editorStore.setActiveActivity(ACTIVITY_MODE.LOCAL_CHANGES);
|
|
67
70
|
// Change Detection
|
|
68
71
|
const changes =
|
|
69
72
|
editorStore.changeDetectionState.workspaceLocalLatestRevisionState.changes
|
|
70
73
|
.length;
|
|
74
|
+
|
|
71
75
|
const configurationState = editorStore.projectConfigurationEditorState;
|
|
72
76
|
const pushLocalChanges = applicationStore.guardUnhandledError(() =>
|
|
73
77
|
flowResult(editorStore.localChangesState.pushLocalChanges()),
|
|
@@ -92,6 +96,11 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
92
96
|
: 'no changes detected';
|
|
93
97
|
const workspaceOutOfSync =
|
|
94
98
|
!actionsDisabled && editorStore.sdlcState.isWorkspaceOutOfSync;
|
|
99
|
+
|
|
100
|
+
// Problems
|
|
101
|
+
const error = editorStore.graphState.error;
|
|
102
|
+
const warnings = editorStore.graphState.warnings;
|
|
103
|
+
|
|
95
104
|
// Conflict resolution
|
|
96
105
|
const conflicts = editorStore.conflictResolutionState.conflicts.length;
|
|
97
106
|
const acceptConflictResolution = applicationStore.guardUnhandledError(() =>
|
|
@@ -118,6 +127,12 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
118
127
|
|
|
119
128
|
// Other actions
|
|
120
129
|
const toggleAuxPanel = (): void => editorStore.auxPanelDisplayState.toggle();
|
|
130
|
+
|
|
131
|
+
const showCompilationWarnings = (): void => {
|
|
132
|
+
editorStore.auxPanelDisplayState.open();
|
|
133
|
+
editorStore.setActiveAuxPanelMode(AUX_PANEL_MODE.PROBLEMS);
|
|
134
|
+
};
|
|
135
|
+
|
|
121
136
|
const handleTextModeClick = applicationStore.guardUnhandledError(() =>
|
|
122
137
|
flowResult(editorStore.toggleTextMode()),
|
|
123
138
|
);
|
|
@@ -177,10 +192,11 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
177
192
|
}
|
|
178
193
|
>
|
|
179
194
|
{workspaceId}
|
|
195
|
+
{editorStore.localChangesState.hasUnpushedChanges ? '*' : ''}
|
|
180
196
|
</button>
|
|
181
197
|
{workspaceOutOfSync && (
|
|
182
198
|
<button
|
|
183
|
-
className="editor__status-
|
|
199
|
+
className="editor__status-bar__workspace__status__btn"
|
|
184
200
|
tabIndex={-1}
|
|
185
201
|
onClick={goToLocalChanges}
|
|
186
202
|
title={
|
|
@@ -192,7 +208,7 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
192
208
|
)}
|
|
193
209
|
{editorStore.sdlcState.isWorkspaceOutdated && !workspaceOutOfSync && (
|
|
194
210
|
<button
|
|
195
|
-
className="editor__status-
|
|
211
|
+
className="editor__status-bar__workspace__status__btn"
|
|
196
212
|
tabIndex={-1}
|
|
197
213
|
onClick={goToWorkspaceUpdater}
|
|
198
214
|
title={
|
|
@@ -202,6 +218,25 @@ export const StatusBar = observer((props: { actionsDisabled: boolean }) => {
|
|
|
202
218
|
OUTDATED
|
|
203
219
|
</button>
|
|
204
220
|
)}
|
|
221
|
+
<button
|
|
222
|
+
className="editor__status-bar__problems"
|
|
223
|
+
tabIndex={-1}
|
|
224
|
+
onClick={showCompilationWarnings}
|
|
225
|
+
title={`${error ? 'Error: 1, ' : ''}Warnings: ${warnings.length}`}
|
|
226
|
+
>
|
|
227
|
+
<div className="editor__status-bar__problems__icon">
|
|
228
|
+
<ErrorIcon />
|
|
229
|
+
</div>
|
|
230
|
+
<div className="editor__status-bar__problems__counter">
|
|
231
|
+
{error ? 1 : 0}
|
|
232
|
+
</div>
|
|
233
|
+
<div className="editor__status-bar__problems__icon">
|
|
234
|
+
<WarningIcon />
|
|
235
|
+
</div>
|
|
236
|
+
<div className="editor__status-bar__problems__counter">
|
|
237
|
+
{warnings.length}
|
|
238
|
+
</div>
|
|
239
|
+
</button>
|
|
205
240
|
</div>
|
|
206
241
|
</div>
|
|
207
242
|
<div
|
|
@@ -22,12 +22,17 @@ import {
|
|
|
22
22
|
ChevronDownIcon,
|
|
23
23
|
XIcon,
|
|
24
24
|
PanelContent,
|
|
25
|
+
Badge,
|
|
26
|
+
PanelHeader,
|
|
27
|
+
PanelHeaderActions,
|
|
28
|
+
PanelHeaderActionItem,
|
|
25
29
|
} from '@finos/legend-art';
|
|
26
30
|
import { Console } from './Console.js';
|
|
27
31
|
import { AUX_PANEL_MODE } from '../../../stores/EditorConfig.js';
|
|
28
32
|
import { isNonNullable } from '@finos/legend-shared';
|
|
29
33
|
import { DevTool } from './DevTool.js';
|
|
30
34
|
import { useEditorStore } from '../EditorStoreProvider.js';
|
|
35
|
+
import { Problems } from './Problems.js';
|
|
31
36
|
|
|
32
37
|
export const AuxiliaryPanel = observer(() => {
|
|
33
38
|
const editorStore = useEditorStore();
|
|
@@ -45,6 +50,7 @@ export const AuxiliaryPanel = observer(() => {
|
|
|
45
50
|
name: string;
|
|
46
51
|
icon?: React.ReactNode;
|
|
47
52
|
isVisible: boolean;
|
|
53
|
+
counter?: number;
|
|
48
54
|
};
|
|
49
55
|
} = {
|
|
50
56
|
[AUX_PANEL_MODE.CONSOLE]: {
|
|
@@ -59,6 +65,13 @@ export const AuxiliaryPanel = observer(() => {
|
|
|
59
65
|
icon: undefined,
|
|
60
66
|
isVisible: true,
|
|
61
67
|
},
|
|
68
|
+
[AUX_PANEL_MODE.PROBLEMS]: {
|
|
69
|
+
mode: AUX_PANEL_MODE.PROBLEMS,
|
|
70
|
+
name: 'PROBLEMS',
|
|
71
|
+
icon: undefined,
|
|
72
|
+
isVisible: true,
|
|
73
|
+
counter: editorStore.graphState.problems.length,
|
|
74
|
+
},
|
|
62
75
|
};
|
|
63
76
|
|
|
64
77
|
const tabsToShow = Object.values(AUX_PANEL_MODE).filter(
|
|
@@ -75,7 +88,7 @@ export const AuxiliaryPanel = observer(() => {
|
|
|
75
88
|
|
|
76
89
|
return (
|
|
77
90
|
<div className="panel auxiliary-panel">
|
|
78
|
-
<
|
|
91
|
+
<PanelHeader>
|
|
79
92
|
<div className="auxiliary-panel__header__tabs">
|
|
80
93
|
{tabsToShow
|
|
81
94
|
.map((tab) => auxTabMap[tab])
|
|
@@ -97,15 +110,20 @@ export const AuxiliaryPanel = observer(() => {
|
|
|
97
110
|
)}
|
|
98
111
|
<div className="auxiliary-panel__header__tab__title">
|
|
99
112
|
{tab.name}
|
|
113
|
+
{tab.counter !== undefined && (
|
|
114
|
+
<Badge
|
|
115
|
+
title={tab.counter.toString()}
|
|
116
|
+
className="auxiliary-panel__header__tab__title__problem__count"
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
100
119
|
</div>
|
|
101
120
|
</button>
|
|
102
121
|
))}
|
|
103
122
|
</div>
|
|
104
|
-
<
|
|
105
|
-
<
|
|
123
|
+
<PanelHeaderActions>
|
|
124
|
+
<PanelHeaderActionItem
|
|
106
125
|
className="auxiliary-panel__header__action"
|
|
107
126
|
onClick={toggleExpandAuxPanel}
|
|
108
|
-
tabIndex={-1}
|
|
109
127
|
title="Toggle expand/collapse"
|
|
110
128
|
>
|
|
111
129
|
{editorStore.auxPanelDisplayState.isMaximized ? (
|
|
@@ -113,18 +131,22 @@ export const AuxiliaryPanel = observer(() => {
|
|
|
113
131
|
) : (
|
|
114
132
|
<ChevronUpIcon />
|
|
115
133
|
)}
|
|
116
|
-
</
|
|
117
|
-
<
|
|
134
|
+
</PanelHeaderActionItem>
|
|
135
|
+
<PanelHeaderActionItem
|
|
118
136
|
className="auxiliary-panel__header__action"
|
|
119
137
|
onClick={closePanel}
|
|
120
|
-
tabIndex={-1}
|
|
121
138
|
title="Close"
|
|
122
139
|
>
|
|
123
140
|
<XIcon />
|
|
124
|
-
</
|
|
125
|
-
</
|
|
126
|
-
</
|
|
141
|
+
</PanelHeaderActionItem>
|
|
142
|
+
</PanelHeaderActions>
|
|
143
|
+
</PanelHeader>
|
|
127
144
|
<PanelContent>
|
|
145
|
+
{isTabVisible(AUX_PANEL_MODE.PROBLEMS) && (
|
|
146
|
+
<div className="auxiliary-panel__content__tab">
|
|
147
|
+
<Problems />
|
|
148
|
+
</div>
|
|
149
|
+
)}
|
|
128
150
|
{isTabVisible(AUX_PANEL_MODE.CONSOLE) && (
|
|
129
151
|
<div className="auxiliary-panel__content__tab">
|
|
130
152
|
<Console />
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { Panel, PanelContent } from '@finos/legend-art';
|
|
17
18
|
import { observer } from 'mobx-react-lite';
|
|
18
19
|
|
|
19
20
|
// TODO: add `xterm` so we have a stream/log
|
|
20
21
|
// See https://github.com/finos/legend-studio/issues/273
|
|
21
22
|
export const Console = observer(() => (
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
</
|
|
23
|
+
<Panel className="console-panel">
|
|
24
|
+
<PanelContent className="console-panel__content"></PanelContent>
|
|
25
|
+
</Panel>
|
|
25
26
|
));
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { observer } from 'mobx-react-lite';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
PanelFormBooleanField,
|
|
20
|
+
Panel,
|
|
21
|
+
PanelFormTextField,
|
|
22
|
+
PanelForm,
|
|
23
|
+
} from '@finos/legend-art';
|
|
19
24
|
import { isValidUrl } from '@finos/legend-shared';
|
|
20
25
|
import { useEditorStore } from '../EditorStoreProvider.js';
|
|
21
26
|
import { observe_TEMPORARY__AbstractEngineConfig } from '@finos/legend-graph';
|
|
@@ -26,12 +31,6 @@ export const DevTool = observer(() => {
|
|
|
26
31
|
const engineConfig = observe_TEMPORARY__AbstractEngineConfig(
|
|
27
32
|
editorStore.graphManagerState.graphManager.TEMPORARY__getEngineConfig(),
|
|
28
33
|
);
|
|
29
|
-
const changeEngineClientBaseUrl: React.ChangeEventHandler<
|
|
30
|
-
HTMLInputElement
|
|
31
|
-
> = (event) =>
|
|
32
|
-
engineConfig.setBaseUrl(
|
|
33
|
-
event.target.value === '' ? undefined : event.target.value,
|
|
34
|
-
);
|
|
35
34
|
const toggleEngineClientRequestPayloadCompression = (): void =>
|
|
36
35
|
engineConfig.setUseClientRequestPayloadCompression(
|
|
37
36
|
!engineConfig.useClientRequestPayloadCompression,
|
|
@@ -40,79 +39,48 @@ export const DevTool = observer(() => {
|
|
|
40
39
|
engineConfig.setUseBase64ForAdhocConnectionDataUrls(
|
|
41
40
|
!engineConfig.useBase64ForAdhocConnectionDataUrls,
|
|
42
41
|
);
|
|
42
|
+
// Graph Manager
|
|
43
|
+
const toggleStrictMode = (): void =>
|
|
44
|
+
editorStore.graphState.setEnableStrictMode(
|
|
45
|
+
!editorStore.graphState.enableStrictMode,
|
|
46
|
+
);
|
|
43
47
|
|
|
44
48
|
return (
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
value={engineConfig.baseUrl ?? ''}
|
|
82
|
-
onChange={changeEngineClientBaseUrl}
|
|
83
|
-
/>
|
|
84
|
-
{!isValidUrl(engineConfig.baseUrl ?? '') && (
|
|
85
|
-
<div className="input-group__error-message">Invalid URL</div>
|
|
86
|
-
)}
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
<div className="panel__content__form__section">
|
|
90
|
-
<div className="panel__content__form__section__header__label">
|
|
91
|
-
Engine execution runner
|
|
92
|
-
</div>
|
|
93
|
-
<div
|
|
94
|
-
className={clsx('panel__content__form__section__toggler')}
|
|
95
|
-
onClick={toggleDataUrlEncoding}
|
|
96
|
-
>
|
|
97
|
-
<button
|
|
98
|
-
className={clsx('panel__content__form__section__toggler__btn', {
|
|
99
|
-
'panel__content__form__section__toggler__btn--toggled':
|
|
100
|
-
engineConfig.useBase64ForAdhocConnectionDataUrls,
|
|
101
|
-
})}
|
|
102
|
-
>
|
|
103
|
-
{engineConfig.useBase64ForAdhocConnectionDataUrls ? (
|
|
104
|
-
<CheckSquareIcon />
|
|
105
|
-
) : (
|
|
106
|
-
<SquareIcon />
|
|
107
|
-
)}
|
|
108
|
-
</button>
|
|
109
|
-
<div className="panel__content__form__section__toggler__prompt">
|
|
110
|
-
Use Base64 encoding for adhoc connection data URLs
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
49
|
+
<Panel>
|
|
50
|
+
<PanelForm>
|
|
51
|
+
<PanelFormBooleanField
|
|
52
|
+
name="Engine client request payload compression"
|
|
53
|
+
prompt="Specifies if request payload should be compressed"
|
|
54
|
+
value={engineConfig.useClientRequestPayloadCompression}
|
|
55
|
+
isReadOnly={false}
|
|
56
|
+
update={toggleEngineClientRequestPayloadCompression}
|
|
57
|
+
/>
|
|
58
|
+
<PanelFormTextField
|
|
59
|
+
name="Engine client base URL"
|
|
60
|
+
value={engineConfig.baseUrl ?? ''}
|
|
61
|
+
isReadOnly={false}
|
|
62
|
+
update={(value: string | undefined): void =>
|
|
63
|
+
engineConfig.setBaseUrl(value === '' ? undefined : value)
|
|
64
|
+
}
|
|
65
|
+
errorMessage={
|
|
66
|
+
!isValidUrl(engineConfig.baseUrl ?? '') ? 'Invalid URL' : ''
|
|
67
|
+
}
|
|
68
|
+
/>
|
|
69
|
+
<PanelFormBooleanField
|
|
70
|
+
name="Engine execution runner"
|
|
71
|
+
prompt="Use Base64 encoding for adhoc connection data URLs"
|
|
72
|
+
value={engineConfig.useBase64ForAdhocConnectionDataUrls}
|
|
73
|
+
isReadOnly={false}
|
|
74
|
+
update={toggleDataUrlEncoding}
|
|
75
|
+
/>
|
|
76
|
+
<PanelFormBooleanField
|
|
77
|
+
name="Graph builder strict mode"
|
|
78
|
+
prompt="Use strict-mode when building the graph (some warnings will be treated as errors)"
|
|
79
|
+
value={editorStore.graphState.enableStrictMode}
|
|
80
|
+
isReadOnly={false}
|
|
81
|
+
update={toggleStrictMode}
|
|
82
|
+
/>
|
|
83
|
+
</PanelForm>
|
|
84
|
+
</Panel>
|
|
117
85
|
);
|
|
118
86
|
});
|
|
@@ -0,0 +1,103 @@
|
|
|
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 { observer } from 'mobx-react-lite';
|
|
18
|
+
import {
|
|
19
|
+
PanelList,
|
|
20
|
+
PanelListItem,
|
|
21
|
+
clsx,
|
|
22
|
+
Panel,
|
|
23
|
+
ErrorIcon,
|
|
24
|
+
WarningIcon,
|
|
25
|
+
} from '@finos/legend-art';
|
|
26
|
+
import { useEditorStore } from '../EditorStoreProvider.js';
|
|
27
|
+
import type { Problem } from '../../../stores/EditorGraphState.js';
|
|
28
|
+
import { CompilationWarning, EngineError } from '@finos/legend-graph';
|
|
29
|
+
|
|
30
|
+
const ProblemItem = observer((props: { problem: Problem }) => {
|
|
31
|
+
const { problem } = props;
|
|
32
|
+
const editorStore = useEditorStore();
|
|
33
|
+
const isStale = editorStore.graphState.areProblemsStale;
|
|
34
|
+
const goToSource = (): void => {
|
|
35
|
+
// NOTE: in text mode, we allow click to go to position even when the problems might already be stale
|
|
36
|
+
if (editorStore.isInGrammarTextMode && problem.sourceInformation) {
|
|
37
|
+
editorStore.grammarTextEditorState.setForcedCursorPosition({
|
|
38
|
+
lineNumber: problem.sourceInformation.startLine,
|
|
39
|
+
column: problem.sourceInformation.startColumn,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<PanelListItem>
|
|
46
|
+
<button
|
|
47
|
+
className={clsx([
|
|
48
|
+
'auxiliary-panel__problem',
|
|
49
|
+
{
|
|
50
|
+
'auxiliary-panel__problem--stale': isStale,
|
|
51
|
+
},
|
|
52
|
+
])}
|
|
53
|
+
title={problem.message}
|
|
54
|
+
onClick={goToSource}
|
|
55
|
+
>
|
|
56
|
+
{problem instanceof EngineError && (
|
|
57
|
+
<ErrorIcon className="auxiliary-panel__problem__icon auxiliary-panel__problem__icon--error" />
|
|
58
|
+
)}
|
|
59
|
+
{problem instanceof CompilationWarning && (
|
|
60
|
+
<WarningIcon className="auxiliary-panel__problem__icon auxiliary-panel__problem__icon--warning" />
|
|
61
|
+
)}
|
|
62
|
+
<div className="auxiliary-panel__problem__message">
|
|
63
|
+
{problem.message}
|
|
64
|
+
</div>
|
|
65
|
+
{problem.sourceInformation && (
|
|
66
|
+
<div className="auxiliary-panel__problem__source">
|
|
67
|
+
{editorStore.isInGrammarTextMode &&
|
|
68
|
+
`[Ln ${problem.sourceInformation.startLine}, Col ${problem.sourceInformation.startColumn}]`}
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
</button>
|
|
72
|
+
</PanelListItem>
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export const Problems = observer(() => {
|
|
77
|
+
const editorStore = useEditorStore();
|
|
78
|
+
const problems = editorStore.graphState.problems;
|
|
79
|
+
const isStale = editorStore.graphState.areProblemsStale;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Panel>
|
|
83
|
+
{isStale && (
|
|
84
|
+
<div className="auxiliary-panel__problems__stale-warning">
|
|
85
|
+
The following result might be stale - please run compilation (F9) to
|
|
86
|
+
check for the latest problems
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
{problems.length === 0 && (
|
|
90
|
+
<div className="auxiliary-panel__problems__placeholder">
|
|
91
|
+
No problems have been detected in the workspace.
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
{problems.length !== 0 && (
|
|
95
|
+
<PanelList>
|
|
96
|
+
{problems.map((problem) => (
|
|
97
|
+
<ProblemItem key={problem.uuid} problem={problem} />
|
|
98
|
+
))}
|
|
99
|
+
</PanelList>
|
|
100
|
+
)}
|
|
101
|
+
</Panel>
|
|
102
|
+
);
|
|
103
|
+
});
|