@finos/legend-application-data-cube 0.3.2 → 0.3.3
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/__lib__/LegendDataCubeNavigation.d.ts +2 -0
- package/lib/__lib__/LegendDataCubeNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendDataCubeNavigation.js +2 -0
- package/lib/__lib__/LegendDataCubeNavigation.js.map +1 -1
- package/lib/application/LegendDataCubeApplicationConfig.d.ts +4 -0
- package/lib/application/LegendDataCubeApplicationConfig.d.ts.map +1 -1
- package/lib/application/LegendDataCubeApplicationConfig.js +5 -0
- package/lib/application/LegendDataCubeApplicationConfig.js.map +1 -1
- package/lib/application/__test-utils__/LegendDataCubeApplicationTestUtils.d.ts +18 -0
- package/lib/application/__test-utils__/LegendDataCubeApplicationTestUtils.d.ts.map +1 -0
- package/lib/application/__test-utils__/LegendDataCubeApplicationTestUtils.js +48 -0
- package/lib/application/__test-utils__/LegendDataCubeApplicationTestUtils.js.map +1 -0
- package/lib/components/LegendDataCubeBlockingWindow.d.ts +2 -1
- package/lib/components/LegendDataCubeBlockingWindow.d.ts.map +1 -1
- package/lib/components/LegendDataCubeBlockingWindow.js +8 -3
- package/lib/components/LegendDataCubeBlockingWindow.js.map +1 -1
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.d.ts +42 -0
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.d.ts.map +1 -0
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.js +104 -0
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.js.map +1 -0
- package/lib/components/builder/LegendDataCubeBuilder.d.ts +5 -0
- package/lib/components/builder/LegendDataCubeBuilder.d.ts.map +1 -1
- package/lib/components/builder/LegendDataCubeBuilder.js +26 -5
- package/lib/components/builder/LegendDataCubeBuilder.js.map +1 -1
- package/lib/components/builder/LegendDataCubeBuilderStoreProvider.d.ts.map +1 -1
- package/lib/components/builder/LegendDataCubeBuilderStoreProvider.js +1 -1
- package/lib/components/builder/LegendDataCubeBuilderStoreProvider.js.map +1 -1
- package/lib/components/builder/LegendDataCubePartialSourceLoader.d.ts +19 -0
- package/lib/components/builder/LegendDataCubePartialSourceLoader.d.ts.map +1 -0
- package/lib/components/builder/LegendDataCubePartialSourceLoader.js +50 -0
- package/lib/components/builder/LegendDataCubePartialSourceLoader.js.map +1 -0
- package/lib/components/builder/LegendDataCubeSourceViewer.d.ts.map +1 -1
- package/lib/components/builder/LegendDataCubeSourceViewer.js +61 -1
- package/lib/components/builder/LegendDataCubeSourceViewer.js.map +1 -1
- package/lib/components/builder/source/LocalFileDataCubeSourceBuilder.d.ts.map +1 -1
- package/lib/components/builder/source/LocalFileDataCubeSourceBuilder.js +1 -2
- package/lib/components/builder/source/LocalFileDataCubeSourceBuilder.js.map +1 -1
- package/lib/components/builder/source/loader/LocalFileDataCubePartialSourceLoader.d.ts +22 -0
- package/lib/components/builder/source/loader/LocalFileDataCubePartialSourceLoader.d.ts.map +1 -0
- package/lib/components/builder/source/loader/LocalFileDataCubePartialSourceLoader.js +28 -0
- package/lib/components/builder/source/loader/LocalFileDataCubePartialSourceLoader.js.map +1 -0
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +3 -1
- package/lib/stores/LegendDataCubeBaseStore.d.ts +2 -1
- package/lib/stores/LegendDataCubeBaseStore.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeBaseStore.js +6 -3
- package/lib/stores/LegendDataCubeBaseStore.js.map +1 -1
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts +6 -3
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeDataCubeEngine.js +127 -106
- package/lib/stores/LegendDataCubeDataCubeEngine.js.map +1 -1
- package/lib/stores/LegendDataCubeDuckDBEngine.d.ts +11 -4
- package/lib/stores/LegendDataCubeDuckDBEngine.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeDuckDBEngine.js +83 -16
- package/lib/stores/LegendDataCubeDuckDBEngine.js.map +1 -1
- package/lib/stores/builder/LegendDataCubeBuilderStore.d.ts +4 -0
- package/lib/stores/builder/LegendDataCubeBuilderStore.d.ts.map +1 -1
- package/lib/stores/builder/LegendDataCubeBuilderStore.js +58 -17
- package/lib/stores/builder/LegendDataCubeBuilderStore.js.map +1 -1
- package/lib/stores/builder/LegendDataCubeLoaderState.d.ts +11 -2
- package/lib/stores/builder/LegendDataCubeLoaderState.d.ts.map +1 -1
- package/lib/stores/builder/LegendDataCubeLoaderState.js +28 -1
- package/lib/stores/builder/LegendDataCubeLoaderState.js.map +1 -1
- package/lib/stores/builder/LegendDataCubeSourceLoaderState.d.ts +44 -0
- package/lib/stores/builder/LegendDataCubeSourceLoaderState.d.ts.map +1 -0
- package/lib/stores/builder/LegendDataCubeSourceLoaderState.js +101 -0
- package/lib/stores/builder/LegendDataCubeSourceLoaderState.js.map +1 -0
- package/lib/stores/builder/source/LocalFileDataCubeSourceBuilderState.d.ts +3 -2
- package/lib/stores/builder/source/LocalFileDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/builder/source/LocalFileDataCubeSourceBuilderState.js +7 -10
- package/lib/stores/builder/source/LocalFileDataCubeSourceBuilderState.js.map +1 -1
- package/lib/stores/builder/source/loader/LegendDataCubePartialSourceLoaderState.d.ts +29 -0
- package/lib/stores/builder/source/loader/LegendDataCubePartialSourceLoaderState.d.ts.map +1 -0
- package/lib/stores/builder/source/loader/LegendDataCubePartialSourceLoaderState.js +25 -0
- package/lib/stores/builder/source/loader/LegendDataCubePartialSourceLoaderState.js.map +1 -0
- package/lib/stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.d.ts +43 -0
- package/lib/stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.d.ts.map +1 -0
- package/lib/stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.js +142 -0
- package/lib/stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.js.map +1 -0
- package/lib/stores/model/LegendQueryDataCubeSource.d.ts +2 -1
- package/lib/stores/model/LegendQueryDataCubeSource.d.ts.map +1 -1
- package/lib/stores/model/LegendQueryDataCubeSource.js +1 -0
- package/lib/stores/model/LegendQueryDataCubeSource.js.map +1 -1
- package/lib/stores/model/LocalFileDataCubeSource.d.ts +3 -8
- package/lib/stores/model/LocalFileDataCubeSource.d.ts.map +1 -1
- package/lib/stores/model/LocalFileDataCubeSource.js +5 -15
- package/lib/stores/model/LocalFileDataCubeSource.js.map +1 -1
- package/package.json +13 -11
- package/src/__lib__/LegendDataCubeNavigation.ts +21 -0
- package/src/application/LegendDataCubeApplicationConfig.ts +10 -0
- package/src/application/__test-utils__/LegendDataCubeApplicationTestUtils.ts +52 -0
- package/src/components/LegendDataCubeBlockingWindow.tsx +8 -2
- package/src/components/__test-utils__/LegendDataCubeStoreTestUtils.tsx +231 -0
- package/src/components/builder/LegendDataCubeBuilder.tsx +51 -6
- package/src/components/builder/LegendDataCubeBuilderStoreProvider.tsx +3 -0
- package/src/components/builder/LegendDataCubePartialSourceLoader.tsx +108 -0
- package/src/components/builder/LegendDataCubeSourceViewer.tsx +171 -1
- package/src/components/builder/source/LocalFileDataCubeSourceBuilder.tsx +1 -2
- package/src/components/builder/source/loader/LocalFileDataCubePartialSourceLoader.tsx +60 -0
- package/src/stores/LegendDataCubeBaseStore.ts +13 -6
- package/src/stores/LegendDataCubeDataCubeEngine.ts +161 -120
- package/src/stores/LegendDataCubeDuckDBEngine.ts +101 -17
- package/src/stores/builder/LegendDataCubeBuilderStore.tsx +96 -24
- package/src/stores/builder/LegendDataCubeLoaderState.tsx +44 -1
- package/src/stores/builder/LegendDataCubeSourceLoaderState.tsx +145 -0
- package/src/stores/builder/source/LocalFileDataCubeSourceBuilderState.ts +9 -14
- package/src/stores/builder/source/loader/LegendDataCubePartialSourceLoaderState.ts +41 -0
- package/src/stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.ts +217 -0
- package/src/stores/model/LegendQueryDataCubeSource.ts +2 -0
- package/src/stores/model/LocalFileDataCubeSource.ts +6 -15
- package/tsconfig.json +8 -1
|
@@ -27,6 +27,9 @@ import { useRef } from 'react';
|
|
|
27
27
|
export const LegendDataCubeBlockingWindow = observer(
|
|
28
28
|
(props: { windowState: LegendDataCubeBlockingWindowState }) => {
|
|
29
29
|
const { windowState } = props;
|
|
30
|
+
const closeModal = !windowState.onClose
|
|
31
|
+
? (): void => windowState.close()
|
|
32
|
+
: windowState.onClose;
|
|
30
33
|
const ref = useRef<HTMLDivElement>(null);
|
|
31
34
|
|
|
32
35
|
// set the width and height of the dialog to make sure content overflow works properly
|
|
@@ -45,7 +48,7 @@ export const LegendDataCubeBlockingWindow = observer(
|
|
|
45
48
|
return (
|
|
46
49
|
<Dialog
|
|
47
50
|
open={windowState.isOpen}
|
|
48
|
-
onClose={
|
|
51
|
+
onClose={closeModal}
|
|
49
52
|
slotProps={{
|
|
50
53
|
transition: {
|
|
51
54
|
onEnter: handleEnter,
|
|
@@ -72,7 +75,7 @@ export const LegendDataCubeBlockingWindow = observer(
|
|
|
72
75
|
<div className="px-2">{windowState.configuration.title}</div>
|
|
73
76
|
<button
|
|
74
77
|
className="flex h-[23px] w-6 items-center justify-center hover:bg-red-500 hover:text-white"
|
|
75
|
-
onClick={
|
|
78
|
+
onClick={closeModal}
|
|
76
79
|
>
|
|
77
80
|
<DataCubeIcon.X />
|
|
78
81
|
</button>
|
|
@@ -91,11 +94,13 @@ export const LegendDataCubeBlockingWindow = observer(
|
|
|
91
94
|
export class LegendDataCubeBlockingWindowState {
|
|
92
95
|
isOpen = false;
|
|
93
96
|
readonly configuration: LayoutConfiguration;
|
|
97
|
+
readonly onClose: (() => void) | undefined;
|
|
94
98
|
|
|
95
99
|
constructor(
|
|
96
100
|
title: string,
|
|
97
101
|
contentRenderer: (config: LayoutConfiguration) => React.ReactNode,
|
|
98
102
|
windowConfiguration?: WindowConfiguration | undefined,
|
|
103
|
+
closeModal?: (() => void) | undefined,
|
|
99
104
|
) {
|
|
100
105
|
makeObservable(this, {
|
|
101
106
|
isOpen: observable,
|
|
@@ -108,6 +113,7 @@ export class LegendDataCubeBlockingWindowState {
|
|
|
108
113
|
if (windowConfiguration) {
|
|
109
114
|
this.configuration.window = windowConfiguration;
|
|
110
115
|
}
|
|
116
|
+
this.onClose = closeModal;
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
open() {
|
|
@@ -0,0 +1,231 @@
|
|
|
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 RenderResult, render, waitFor } from '@testing-library/react';
|
|
18
|
+
import {
|
|
19
|
+
type AbstractPlugin,
|
|
20
|
+
type AbstractPreset,
|
|
21
|
+
type PlainObject,
|
|
22
|
+
} from '@finos/legend-shared';
|
|
23
|
+
import { createMock, createSpy } from '@finos/legend-shared/test';
|
|
24
|
+
import {
|
|
25
|
+
ApplicationStore,
|
|
26
|
+
ApplicationStoreProvider,
|
|
27
|
+
} from '@finos/legend-application';
|
|
28
|
+
import { LegendDataCubePluginManager } from '../../application/LegendDataCubePluginManager.js';
|
|
29
|
+
import { Core_LegendDataCubeApplicationPlugin } from '../../application/Core_LegendDataCubeApplicationPlugin.js';
|
|
30
|
+
import { TEST__getTestLegendDataCubeApplicationConfig } from '../../application/__test-utils__/LegendDataCubeApplicationTestUtils.js';
|
|
31
|
+
import {
|
|
32
|
+
type LegendDataCubeBuilderState,
|
|
33
|
+
LegendDataCubeBuilderStore,
|
|
34
|
+
} from '../../stores/builder/LegendDataCubeBuilderStore.js';
|
|
35
|
+
import {
|
|
36
|
+
type LegendDataCubeApplicationStore,
|
|
37
|
+
LegendDataCubeBaseStore,
|
|
38
|
+
} from '../../stores/LegendDataCubeBaseStore.js';
|
|
39
|
+
import { TEST__BrowserEnvironmentProvider } from '@finos/legend-application/test';
|
|
40
|
+
import { LegendDataCubeFrameworkProvider } from '../LegendDataCubeFrameworkProvider.js';
|
|
41
|
+
import { Route, Routes } from '@finos/legend-application/browser';
|
|
42
|
+
import { LEGEND_DATA_CUBE_ROUTE_PATTERN } from '../../__lib__/LegendDataCubeNavigation.js';
|
|
43
|
+
import { LegendDataCubeBuilder } from '../builder/LegendDataCubeBuilder.js';
|
|
44
|
+
import { LEGEND_DATACUBE_TEST_ID } from '@finos/legend-data-cube';
|
|
45
|
+
import { Core_LegendDataCube_LegendApplicationPlugin } from '../../application/Core_LegendDataCube_LegendApplicationPlugin.js';
|
|
46
|
+
import {
|
|
47
|
+
type PersistentDataCube,
|
|
48
|
+
type V1_LambdaReturnTypeInput,
|
|
49
|
+
type V1_Query,
|
|
50
|
+
type V1_RawLambda,
|
|
51
|
+
type V1_ValueSpecification,
|
|
52
|
+
V1_entitiesToPureModelContextData,
|
|
53
|
+
V1_ExecuteInput,
|
|
54
|
+
V1_PureModelContextData,
|
|
55
|
+
V1_serializePureModelContext,
|
|
56
|
+
} from '@finos/legend-graph';
|
|
57
|
+
import { DSL_DataSpace_GraphManagerPreset } from '@finos/legend-extension-dsl-data-space/graph';
|
|
58
|
+
import {
|
|
59
|
+
ENGINE_TEST_SUPPORT__execute,
|
|
60
|
+
ENGINE_TEST_SUPPORT__getLambdaRelationType,
|
|
61
|
+
ENGINE_TEST_SUPPORT__grammarToJSON_lambda,
|
|
62
|
+
ENGINE_TEST_SUPPORT__grammarToJSON_valueSpecification,
|
|
63
|
+
ENGINE_TEST_SUPPORT__JSONToGrammar_valueSpecification,
|
|
64
|
+
} from '@finos/legend-graph/test';
|
|
65
|
+
import type { Entity } from '@finos/legend-storage';
|
|
66
|
+
|
|
67
|
+
export const TEST__provideMockedLegendDataCubeBaseStore =
|
|
68
|
+
async (customization?: {
|
|
69
|
+
mock?: LegendDataCubeBaseStore | undefined;
|
|
70
|
+
applicationStore?: LegendDataCubeApplicationStore | undefined;
|
|
71
|
+
pluginManager?: LegendDataCubePluginManager | undefined;
|
|
72
|
+
extraPlugins?: AbstractPlugin[] | undefined;
|
|
73
|
+
extraPresets?: AbstractPreset[] | undefined;
|
|
74
|
+
}): Promise<LegendDataCubeBaseStore> => {
|
|
75
|
+
const pluginManager =
|
|
76
|
+
customization?.pluginManager ?? LegendDataCubePluginManager.create();
|
|
77
|
+
pluginManager
|
|
78
|
+
.usePlugins([
|
|
79
|
+
new Core_LegendDataCube_LegendApplicationPlugin(),
|
|
80
|
+
new Core_LegendDataCubeApplicationPlugin(),
|
|
81
|
+
...(customization?.extraPlugins ?? []),
|
|
82
|
+
])
|
|
83
|
+
.usePresets([
|
|
84
|
+
new DSL_DataSpace_GraphManagerPreset(),
|
|
85
|
+
...(customization?.extraPresets ?? []),
|
|
86
|
+
])
|
|
87
|
+
.install();
|
|
88
|
+
const applicationStore =
|
|
89
|
+
customization?.applicationStore ??
|
|
90
|
+
new ApplicationStore(
|
|
91
|
+
TEST__getTestLegendDataCubeApplicationConfig(),
|
|
92
|
+
pluginManager,
|
|
93
|
+
);
|
|
94
|
+
const value =
|
|
95
|
+
customization?.mock ?? new LegendDataCubeBaseStore(applicationStore);
|
|
96
|
+
await value.initialize();
|
|
97
|
+
const MOCK__LegendDataCubeBaseStoreProvider = require('../LegendDataCubeFrameworkProvider.js'); // eslint-disable-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
|
|
98
|
+
MOCK__LegendDataCubeBaseStoreProvider.useLegendDataCubeBaseStore =
|
|
99
|
+
createMock();
|
|
100
|
+
MOCK__LegendDataCubeBaseStoreProvider.useLegendDataCubeBaseStore.mockReturnValue(
|
|
101
|
+
value,
|
|
102
|
+
);
|
|
103
|
+
return value;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const TEST__provideMockedLegendDataCubeBuilderStore =
|
|
107
|
+
async (customization?: {
|
|
108
|
+
mock?: LegendDataCubeBuilderStore;
|
|
109
|
+
mockBaseStore?: LegendDataCubeBaseStore;
|
|
110
|
+
applicationStore?: LegendDataCubeApplicationStore;
|
|
111
|
+
pluginManager?: LegendDataCubePluginManager;
|
|
112
|
+
extraPlugins?: AbstractPlugin[];
|
|
113
|
+
extraPresets?: AbstractPreset[];
|
|
114
|
+
}): Promise<LegendDataCubeBuilderStore> => {
|
|
115
|
+
const value =
|
|
116
|
+
customization?.mock ??
|
|
117
|
+
new LegendDataCubeBuilderStore(
|
|
118
|
+
await TEST__provideMockedLegendDataCubeBaseStore({
|
|
119
|
+
mock: customization?.mockBaseStore,
|
|
120
|
+
applicationStore: customization?.applicationStore,
|
|
121
|
+
pluginManager: customization?.pluginManager,
|
|
122
|
+
extraPlugins: customization?.extraPlugins,
|
|
123
|
+
extraPresets: customization?.extraPresets,
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
const MOCK__LegendDataCubeBuilderStoreProvider = require('../builder/LegendDataCubeBuilderStoreProvider.js'); // eslint-disable-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
|
|
127
|
+
MOCK__LegendDataCubeBuilderStoreProvider.useLegendDataCubeBuilderStore =
|
|
128
|
+
createMock();
|
|
129
|
+
MOCK__LegendDataCubeBuilderStoreProvider.useLegendDataCubeBuilderStore.mockReturnValue(
|
|
130
|
+
value,
|
|
131
|
+
);
|
|
132
|
+
return value;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const TEST__setUpDataCubeBuilder = async (
|
|
136
|
+
MOCK__builderStore: LegendDataCubeBuilderStore,
|
|
137
|
+
mockDataCube?: PersistentDataCube,
|
|
138
|
+
mockQuery?: V1_Query,
|
|
139
|
+
mockEntities?: PlainObject<Entity>[],
|
|
140
|
+
): Promise<{
|
|
141
|
+
renderResult: RenderResult;
|
|
142
|
+
legendDataCubeBuilderState: LegendDataCubeBuilderState | undefined;
|
|
143
|
+
}> => {
|
|
144
|
+
if (mockDataCube) {
|
|
145
|
+
createSpy(MOCK__builderStore.graphManager, 'getDataCube').mockResolvedValue(
|
|
146
|
+
mockDataCube,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (mockQuery) {
|
|
150
|
+
createSpy(
|
|
151
|
+
MOCK__builderStore.graphManager.engine,
|
|
152
|
+
'getQuery',
|
|
153
|
+
).mockResolvedValue(mockQuery);
|
|
154
|
+
}
|
|
155
|
+
if (mockEntities) {
|
|
156
|
+
const pmcd = new V1_PureModelContextData();
|
|
157
|
+
await V1_entitiesToPureModelContextData(
|
|
158
|
+
mockEntities as unknown as Entity[],
|
|
159
|
+
pmcd,
|
|
160
|
+
MOCK__builderStore.application.pluginManager.getPureProtocolProcessorPlugins(),
|
|
161
|
+
undefined,
|
|
162
|
+
undefined,
|
|
163
|
+
);
|
|
164
|
+
createSpy(
|
|
165
|
+
MOCK__builderStore.depotServerClient,
|
|
166
|
+
'getVersionEntities',
|
|
167
|
+
).mockResolvedValue(mockEntities);
|
|
168
|
+
createSpy(
|
|
169
|
+
MOCK__builderStore.engineServerClient,
|
|
170
|
+
'lambdaRelationType',
|
|
171
|
+
).mockImplementation(
|
|
172
|
+
async (input: PlainObject<V1_LambdaReturnTypeInput>) => {
|
|
173
|
+
return ENGINE_TEST_SUPPORT__getLambdaRelationType(
|
|
174
|
+
input.lambda as PlainObject<V1_RawLambda>,
|
|
175
|
+
V1_serializePureModelContext(pmcd),
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
);
|
|
179
|
+
createSpy(
|
|
180
|
+
MOCK__builderStore.engineServerClient,
|
|
181
|
+
'runQuery',
|
|
182
|
+
).mockImplementation(async (input: PlainObject<V1_ExecuteInput>) => {
|
|
183
|
+
const executeInput = V1_ExecuteInput.serialization.fromJson(input);
|
|
184
|
+
executeInput.model = pmcd;
|
|
185
|
+
return ENGINE_TEST_SUPPORT__execute(executeInput);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
createSpy(
|
|
189
|
+
MOCK__builderStore.engineServerClient,
|
|
190
|
+
'grammarToJSON_lambda',
|
|
191
|
+
).mockImplementation(async (input: string) =>
|
|
192
|
+
ENGINE_TEST_SUPPORT__grammarToJSON_lambda(input),
|
|
193
|
+
);
|
|
194
|
+
createSpy(
|
|
195
|
+
MOCK__builderStore.engineServerClient,
|
|
196
|
+
'grammarToJSON_valueSpecification',
|
|
197
|
+
).mockImplementation(async (input: string) =>
|
|
198
|
+
ENGINE_TEST_SUPPORT__grammarToJSON_valueSpecification(input),
|
|
199
|
+
);
|
|
200
|
+
createSpy(
|
|
201
|
+
MOCK__builderStore.engineServerClient,
|
|
202
|
+
'JSONToGrammar_valueSpecification',
|
|
203
|
+
).mockImplementation(async (input: PlainObject<V1_ValueSpecification>) =>
|
|
204
|
+
ENGINE_TEST_SUPPORT__JSONToGrammar_valueSpecification(input),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const renderResult = render(
|
|
208
|
+
<ApplicationStoreProvider store={MOCK__builderStore.application}>
|
|
209
|
+
<TEST__BrowserEnvironmentProvider
|
|
210
|
+
initialEntries={[mockDataCube?.id ? `/${mockDataCube.id}` : '/']}
|
|
211
|
+
>
|
|
212
|
+
<LegendDataCubeFrameworkProvider>
|
|
213
|
+
<Routes>
|
|
214
|
+
<Route
|
|
215
|
+
path={LEGEND_DATA_CUBE_ROUTE_PATTERN.BUILDER}
|
|
216
|
+
element={<LegendDataCubeBuilder />}
|
|
217
|
+
/>
|
|
218
|
+
</Routes>
|
|
219
|
+
</LegendDataCubeFrameworkProvider>
|
|
220
|
+
</TEST__BrowserEnvironmentProvider>
|
|
221
|
+
</ApplicationStoreProvider>,
|
|
222
|
+
);
|
|
223
|
+
await waitFor(() =>
|
|
224
|
+
renderResult.getByTestId(LEGEND_DATACUBE_TEST_ID.PLACEHOLDER),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
renderResult,
|
|
229
|
+
legendDataCubeBuilderState: MOCK__builderStore.builder,
|
|
230
|
+
};
|
|
231
|
+
};
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
import { useEffect } from 'react';
|
|
39
39
|
import { LegendDataCubeSettingStorageKey } from '../../__lib__/LegendDataCubeSetting.js';
|
|
40
40
|
import type { LegendDataCubeBuilderStore } from '../../stores/builder/LegendDataCubeBuilderStore.js';
|
|
41
|
-
import {
|
|
41
|
+
import { ReleaseViewer } from '@finos/legend-application';
|
|
42
42
|
|
|
43
43
|
const LegendDataCubeBuilderHeader = observer(() => {
|
|
44
44
|
const store = useLegendDataCubeBuilderStore();
|
|
@@ -58,11 +58,7 @@ const LegendDataCubeBuilderHeader = observer(() => {
|
|
|
58
58
|
<FormButton
|
|
59
59
|
compact={true}
|
|
60
60
|
className="ml-1.5"
|
|
61
|
-
disabled={
|
|
62
|
-
!store.builder?.dataCube ||
|
|
63
|
-
/* TODO: @gs-gunjan we should allow saving DataCube using CSV file source */
|
|
64
|
-
store.builder.source instanceof LocalFileDataCubeSource
|
|
65
|
-
}
|
|
61
|
+
disabled={!store.builder?.dataCube}
|
|
66
62
|
onClick={() => store.saverDisplay.open()}
|
|
67
63
|
>
|
|
68
64
|
Save DataCube
|
|
@@ -71,8 +67,37 @@ const LegendDataCubeBuilderHeader = observer(() => {
|
|
|
71
67
|
);
|
|
72
68
|
});
|
|
73
69
|
|
|
70
|
+
export const LegendDataCubeReleaseLogManager = observer(
|
|
71
|
+
(props: { showOnlyLatestNotes: boolean }) => {
|
|
72
|
+
const { showOnlyLatestNotes } = props;
|
|
73
|
+
const store = useLegendDataCubeBuilderStore();
|
|
74
|
+
const applicationStore = store.application;
|
|
75
|
+
const releaseService = applicationStore.releaseNotesService;
|
|
76
|
+
const releaseNotes =
|
|
77
|
+
(showOnlyLatestNotes
|
|
78
|
+
? releaseService.showableVersions()
|
|
79
|
+
: releaseService.releaseNotes) ?? [];
|
|
80
|
+
|
|
81
|
+
applicationStore.releaseNotesService.updateViewedVersion();
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div className="legend-datacube-release-notes h-full items-center p-3">
|
|
85
|
+
<div className="my-0.5 flex font-mono">
|
|
86
|
+
New features, enhancements and bug fixes that were released
|
|
87
|
+
</div>
|
|
88
|
+
<div className="p-2">
|
|
89
|
+
{releaseNotes.map((e) => (
|
|
90
|
+
<ReleaseViewer key={e.version} releaseNotes={e} />
|
|
91
|
+
))}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
74
98
|
export const LegendDataCubeAbout = observer(() => {
|
|
75
99
|
const store = useLegendDataCubeBuilderStore();
|
|
100
|
+
const releaseService = store.application.releaseNotesService;
|
|
76
101
|
const config = store.application.config;
|
|
77
102
|
|
|
78
103
|
return (
|
|
@@ -93,6 +118,14 @@ export const LegendDataCubeAbout = observer(() => {
|
|
|
93
118
|
<div>Build Time:</div>
|
|
94
119
|
<div className="ml-1 font-bold">{config.appVersionBuildTime}</div>
|
|
95
120
|
</div>
|
|
121
|
+
{releaseService.isConfigured && (
|
|
122
|
+
<div
|
|
123
|
+
onClick={() => store.releaseLogDisplay.open()}
|
|
124
|
+
className="my-0.5 flex cursor-pointer font-bold text-sky-500 underline"
|
|
125
|
+
>
|
|
126
|
+
<div>Details of Released Versions</div>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
96
129
|
<div className="mt-3 rounded-sm bg-white px-4 py-2">
|
|
97
130
|
<div className="my-0.5 flex font-mono">
|
|
98
131
|
<div>Engine Server:</div>
|
|
@@ -255,6 +288,18 @@ export const LegendDataCubeBuilder = withLegendDataCubeBuilderStore(
|
|
|
255
288
|
.catch((error) => store.alertService.alertUnhandledError(error));
|
|
256
289
|
}, [store, dataCubeId]);
|
|
257
290
|
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
const releaseService = application.releaseNotesService;
|
|
293
|
+
const releaseNotes = releaseService.showableVersions();
|
|
294
|
+
const isOpen = releaseService.showCurrentReleaseModal;
|
|
295
|
+
|
|
296
|
+
if (releaseService.isConfigured && isOpen && releaseNotes?.length) {
|
|
297
|
+
store.releaseNotesDisplay.open();
|
|
298
|
+
} else {
|
|
299
|
+
releaseService.updateViewedVersion();
|
|
300
|
+
}
|
|
301
|
+
}, [application, store.releaseNotesDisplay]);
|
|
302
|
+
|
|
258
303
|
if (!store.initializeState.hasSucceeded) {
|
|
259
304
|
return (
|
|
260
305
|
<DataCubePlaceholder
|
|
@@ -39,6 +39,9 @@ const LegendDataCubeBuilderStoreProvider = (props: {
|
|
|
39
39
|
<LegendDataCubeBlockingWindow
|
|
40
40
|
windowState={store.deleteConfirmationDisplay}
|
|
41
41
|
/>
|
|
42
|
+
<LegendDataCubeBlockingWindow
|
|
43
|
+
windowState={store.loader.sourceLoader.display}
|
|
44
|
+
/>
|
|
42
45
|
</LegendDataCubeBuilderStoreContext.Provider>
|
|
43
46
|
);
|
|
44
47
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
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 { FormButton } from '@finos/legend-data-cube';
|
|
19
|
+
import { useLegendDataCubeBuilderStore } from './LegendDataCubeBuilderStoreProvider.js';
|
|
20
|
+
import { LocalFileDataCubePartialSourceLoaderState } from '../../stores/builder/source/loader/LocalFileDataCubePartialSourceLoaderState.js';
|
|
21
|
+
import { LocalFileDataCubePartialSourceLoader } from './source/loader/LocalFileDataCubePartialSourceLoader.js';
|
|
22
|
+
import { useEffect } from 'react';
|
|
23
|
+
import { DataCubeIcon } from '@finos/legend-art';
|
|
24
|
+
import { formatDistanceToNow } from '@finos/legend-shared';
|
|
25
|
+
|
|
26
|
+
export const LegendDataCubePartialSourceLoader = observer(() => {
|
|
27
|
+
const store = useLegendDataCubeBuilderStore();
|
|
28
|
+
const state = store.loader.sourceLoader;
|
|
29
|
+
const sourceLoader = state.partialSourceLoader;
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
sourceLoader.initialize();
|
|
33
|
+
}, [sourceLoader]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<div className="h-[calc(100%_-_40px)] w-full px-2 pt-2">
|
|
38
|
+
<div className="h-full w-full border border-neutral-300 bg-white">
|
|
39
|
+
<div className="h-full w-full select-none p-2">
|
|
40
|
+
<div className="relative mb-0.5 flex h-[42px] w-full border border-neutral-200 bg-neutral-100">
|
|
41
|
+
<div className="w-full">
|
|
42
|
+
<div className="h-6 w-4/5 overflow-hidden text-ellipsis whitespace-nowrap px-1.5 leading-6">
|
|
43
|
+
{state.persistentDataCube?.name}
|
|
44
|
+
</div>
|
|
45
|
+
<div className="flex h-[18px] items-start justify-between px-1.5">
|
|
46
|
+
<div className="flex">
|
|
47
|
+
<DataCubeIcon.ClockEdit className="text-sm text-neutral-500" />
|
|
48
|
+
<div className="ml-1 text-sm text-neutral-500">
|
|
49
|
+
{state.persistentDataCube?.lastUpdatedAt
|
|
50
|
+
? formatDistanceToNow(
|
|
51
|
+
new Date(state.persistentDataCube.lastUpdatedAt),
|
|
52
|
+
{
|
|
53
|
+
includeSeconds: true,
|
|
54
|
+
addSuffix: true,
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
: '(unknown)'}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div className="flex">
|
|
61
|
+
<DataCubeIcon.User className="text-sm text-neutral-500" />
|
|
62
|
+
<div className="ml-1 text-sm text-neutral-500">
|
|
63
|
+
{state.persistentDataCube?.owner}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="flex h-10 w-full items-center">
|
|
70
|
+
<div className="flex h-full w-32 flex-shrink-0 items-center text-sm">
|
|
71
|
+
Source Type:
|
|
72
|
+
<div className="pl-3">{sourceLoader.label}</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<div className="h-[calc(100%_-_41px)] w-full overflow-auto">
|
|
76
|
+
{sourceLoader instanceof
|
|
77
|
+
LocalFileDataCubePartialSourceLoaderState && (
|
|
78
|
+
<LocalFileDataCubePartialSourceLoader
|
|
79
|
+
partialSourceLoader={sourceLoader}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex h-10 items-center justify-end px-2">
|
|
87
|
+
<FormButton onClick={state.display.onClose}>Cancel</FormButton>
|
|
88
|
+
<FormButton
|
|
89
|
+
className="ml-2"
|
|
90
|
+
disabled={!sourceLoader.isValid || state.finalizeState.isInProgress}
|
|
91
|
+
onClick={() => {
|
|
92
|
+
state
|
|
93
|
+
.finalize()
|
|
94
|
+
.then(() => store.loadPartialSourceDataCube())
|
|
95
|
+
.catch((error) => {
|
|
96
|
+
store.alertService.alertUnhandledError(error);
|
|
97
|
+
})
|
|
98
|
+
.finally(() => {
|
|
99
|
+
state.display.close();
|
|
100
|
+
});
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
OK
|
|
104
|
+
</FormButton>
|
|
105
|
+
</div>
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
});
|
|
@@ -18,8 +18,175 @@ import { observer } from 'mobx-react-lite';
|
|
|
18
18
|
import { useLegendDataCubeBuilderStore } from './LegendDataCubeBuilderStoreProvider.js';
|
|
19
19
|
import { LegendQueryDataCubeSource } from '../../stores/model/LegendQueryDataCubeSource.js';
|
|
20
20
|
import { useLegendDataCubeApplicationStore } from '../LegendDataCubeFrameworkProvider.js';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
EXTERNAL_APPLICATION_NAVIGATION__generateQueryViewUrl,
|
|
23
|
+
EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCViewUrl,
|
|
24
|
+
EXTERNAL_APPLICATION_NAVIGATION__generateStudioViewUrl,
|
|
25
|
+
} from '../../__lib__/LegendDataCubeNavigation.js';
|
|
22
26
|
import { DataCubeIcon } from '@finos/legend-art';
|
|
27
|
+
import { UserDefinedFunctionDataCubeSource } from '@finos/legend-data-cube';
|
|
28
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
29
|
+
import {
|
|
30
|
+
type DepotServerClient,
|
|
31
|
+
DepotScope,
|
|
32
|
+
StoreProjectData,
|
|
33
|
+
} from '@finos/legend-server-depot';
|
|
34
|
+
import { returnUndefOnError } from '@finos/legend-shared';
|
|
35
|
+
import {
|
|
36
|
+
V1_deserializePureModelContext,
|
|
37
|
+
V1_LegendSDLC,
|
|
38
|
+
V1_PureModelContextPointer,
|
|
39
|
+
type V1_PureModelContext,
|
|
40
|
+
} from '@finos/legend-graph';
|
|
41
|
+
|
|
42
|
+
const handleFetchProject = (
|
|
43
|
+
depotServerClient: DepotServerClient,
|
|
44
|
+
model: V1_PureModelContext,
|
|
45
|
+
handleProjectChange: (val: StoreProjectData | undefined) => void,
|
|
46
|
+
) => {
|
|
47
|
+
if (
|
|
48
|
+
model instanceof V1_PureModelContextPointer &&
|
|
49
|
+
model.sdlcInfo instanceof V1_LegendSDLC
|
|
50
|
+
) {
|
|
51
|
+
depotServerClient
|
|
52
|
+
.getProject(model.sdlcInfo.groupId, model.sdlcInfo.artifactId)
|
|
53
|
+
.then((e) => {
|
|
54
|
+
handleProjectChange(
|
|
55
|
+
returnUndefOnError(() => StoreProjectData.serialization.fromJson(e)),
|
|
56
|
+
);
|
|
57
|
+
})
|
|
58
|
+
.catch((e) => {
|
|
59
|
+
// ignore
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const generateStudioViewLink = (
|
|
65
|
+
studio: string,
|
|
66
|
+
project: StoreProjectData,
|
|
67
|
+
version: string,
|
|
68
|
+
element: string | undefined,
|
|
69
|
+
): string => {
|
|
70
|
+
if (version.endsWith(DepotScope.SNAPSHOT)) {
|
|
71
|
+
return EXTERNAL_APPLICATION_NAVIGATION__generateStudioViewUrl(
|
|
72
|
+
studio,
|
|
73
|
+
project.groupId,
|
|
74
|
+
project.artifactId,
|
|
75
|
+
version,
|
|
76
|
+
element,
|
|
77
|
+
);
|
|
78
|
+
} else {
|
|
79
|
+
return EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCViewUrl(
|
|
80
|
+
studio,
|
|
81
|
+
project.projectId,
|
|
82
|
+
version,
|
|
83
|
+
element,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const UserDefinedFunctionSourceViewer = observer(
|
|
89
|
+
(props: { source: UserDefinedFunctionDataCubeSource }) => {
|
|
90
|
+
const { source } = props;
|
|
91
|
+
const sourceModel = returnUndefOnError(() =>
|
|
92
|
+
V1_deserializePureModelContext(source.model),
|
|
93
|
+
);
|
|
94
|
+
const version =
|
|
95
|
+
sourceModel instanceof V1_PureModelContextPointer &&
|
|
96
|
+
sourceModel.sdlcInfo instanceof V1_LegendSDLC
|
|
97
|
+
? sourceModel.sdlcInfo.version
|
|
98
|
+
: undefined;
|
|
99
|
+
const store = useLegendDataCubeBuilderStore();
|
|
100
|
+
const application = useLegendDataCubeApplicationStore();
|
|
101
|
+
const [project, setProject] = useState<StoreProjectData | undefined>(
|
|
102
|
+
undefined,
|
|
103
|
+
);
|
|
104
|
+
const link =
|
|
105
|
+
project?.projectId && application.config.studioApplicationUrl && version
|
|
106
|
+
? generateStudioViewLink(
|
|
107
|
+
application.config.studioApplicationUrl,
|
|
108
|
+
project,
|
|
109
|
+
version,
|
|
110
|
+
source.functionPath,
|
|
111
|
+
)
|
|
112
|
+
: undefined;
|
|
113
|
+
const _handleFetchProject = useCallback(() => {
|
|
114
|
+
if (sourceModel) {
|
|
115
|
+
handleFetchProject(store.depotServerClient, sourceModel, setProject);
|
|
116
|
+
}
|
|
117
|
+
}, [sourceModel, store.depotServerClient]);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
_handleFetchProject();
|
|
121
|
+
}, [_handleFetchProject]);
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div className="h-full w-full px-2 pt-2">
|
|
125
|
+
<div className="h-[calc(100%_-_8px)] w-full border border-neutral-300 bg-white">
|
|
126
|
+
<div className="h-full w-full select-none p-2">
|
|
127
|
+
<div className="flex h-6">
|
|
128
|
+
<div className="flex h-6 items-center text-xl font-medium">
|
|
129
|
+
<DataCubeIcon.Table />
|
|
130
|
+
</div>
|
|
131
|
+
<div className="ml-1 flex h-6 items-center text-xl font-medium">
|
|
132
|
+
User Defined Function
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
{link && (
|
|
136
|
+
<div className="mt-2 flex h-6 w-full">
|
|
137
|
+
<div className="flex h-full w-[calc(100%_-_20px)] items-center border border-r-0 border-neutral-400 px-1.5 font-bold text-sky-500 underline">
|
|
138
|
+
<a
|
|
139
|
+
href={link}
|
|
140
|
+
target="_blank"
|
|
141
|
+
rel="noopener noreferrer"
|
|
142
|
+
className="overflow-hidden overflow-ellipsis whitespace-nowrap"
|
|
143
|
+
>
|
|
144
|
+
{source.functionPath}
|
|
145
|
+
</a>
|
|
146
|
+
</div>
|
|
147
|
+
<button
|
|
148
|
+
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
149
|
+
onClick={() => {
|
|
150
|
+
store.application.clipboardService
|
|
151
|
+
.copyTextToClipboard(link)
|
|
152
|
+
.catch((error) =>
|
|
153
|
+
store.alertService.alertUnhandledError(error),
|
|
154
|
+
);
|
|
155
|
+
}}
|
|
156
|
+
title="Copy Link"
|
|
157
|
+
>
|
|
158
|
+
<DataCubeIcon.Clipboard />
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
{!link && (
|
|
163
|
+
<div className="mt-2 flex h-6 w-full">
|
|
164
|
+
<div className="flex h-full w-[calc(100%_-_20px)] items-center border border-r-0 border-neutral-400 bg-neutral-200 px-1.5">
|
|
165
|
+
<div className="overflow-hidden overflow-ellipsis whitespace-nowrap">
|
|
166
|
+
{source.functionPath}
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
<button
|
|
170
|
+
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
171
|
+
onClick={() => {
|
|
172
|
+
application.clipboardService
|
|
173
|
+
.copyTextToClipboard(source.functionPath)
|
|
174
|
+
.catch((error) =>
|
|
175
|
+
store.alertService.alertUnhandledError(error),
|
|
176
|
+
);
|
|
177
|
+
}}
|
|
178
|
+
title="Copy ID"
|
|
179
|
+
>
|
|
180
|
+
<DataCubeIcon.Clipboard />
|
|
181
|
+
</button>
|
|
182
|
+
</div>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
},
|
|
189
|
+
);
|
|
23
190
|
|
|
24
191
|
export const LegendDataCubeSourceViewer = observer(() => {
|
|
25
192
|
const store = useLegendDataCubeBuilderStore();
|
|
@@ -36,6 +203,7 @@ export const LegendDataCubeSourceViewer = observer(() => {
|
|
|
36
203
|
source.info.id,
|
|
37
204
|
)
|
|
38
205
|
: undefined;
|
|
206
|
+
|
|
39
207
|
return (
|
|
40
208
|
<div className="h-full w-full px-2 pt-2">
|
|
41
209
|
<div className="h-[calc(100%_-_8px)] w-full border border-neutral-300 bg-white">
|
|
@@ -101,6 +269,8 @@ export const LegendDataCubeSourceViewer = observer(() => {
|
|
|
101
269
|
</div>
|
|
102
270
|
</div>
|
|
103
271
|
);
|
|
272
|
+
} else if (source instanceof UserDefinedFunctionDataCubeSource) {
|
|
273
|
+
return <UserDefinedFunctionSourceViewer source={source} />;
|
|
104
274
|
}
|
|
105
275
|
return (
|
|
106
276
|
<div className="h-full w-full px-2 pt-2">{`Can't display source`}</div>
|