@finos/legend-application-data-cube 0.3.14 → 0.3.16
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/Core_LegendDataCube_LegendApplicationPlugin.d.ts +7 -1
- package/lib/application/Core_LegendDataCube_LegendApplicationPlugin.d.ts.map +1 -1
- package/lib/application/Core_LegendDataCube_LegendApplicationPlugin.js +10 -1
- package/lib/application/Core_LegendDataCube_LegendApplicationPlugin.js.map +1 -1
- package/lib/application/LegendDataCube.d.ts.map +1 -1
- package/lib/application/LegendDataCube.js +2 -0
- package/lib/application/LegendDataCube.js.map +1 -1
- package/lib/application/LegendDataCubeApplicationPlugin.d.ts +9 -0
- package/lib/application/LegendDataCubeApplicationPlugin.d.ts.map +1 -1
- package/lib/application/LegendDataCubeApplicationPlugin.js.map +1 -1
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.d.ts.map +1 -1
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.js +2 -0
- package/lib/components/__test-utils__/LegendDataCubeStoreTestUtils.js.map +1 -1
- package/lib/components/builder/LegendDataCubeBuilder.d.ts.map +1 -1
- package/lib/components/builder/LegendDataCubeBuilder.js +10 -2
- package/lib/components/builder/LegendDataCubeBuilder.js.map +1 -1
- package/lib/components/builder/LegendDataCubeCreator.js +4 -4
- package/lib/components/builder/LegendDataCubeCreator.js.map +1 -1
- package/lib/components/builder/LegendDataCubeSourceViewer.d.ts.map +1 -1
- package/lib/components/builder/LegendDataCubeSourceViewer.js +134 -18
- package/lib/components/builder/LegendDataCubeSourceViewer.js.map +1 -1
- package/lib/components/builder/source/{AdhocQueryDataCubeSourceBuilder.d.ts → FreeformTDSExpressionDataCubeSourceBuilder.d.ts} +4 -4
- package/lib/components/builder/source/FreeformTDSExpressionDataCubeSourceBuilder.d.ts.map +1 -0
- package/lib/components/builder/source/{AdhocQueryDataCubeSourceBuilder.js → FreeformTDSExpressionDataCubeSourceBuilder.js} +2 -2
- package/lib/components/builder/source/FreeformTDSExpressionDataCubeSourceBuilder.js.map +1 -0
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder.d.ts.map +1 -1
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder.js +30 -4
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder.js.map +1 -1
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder_DataCubeApplicationPlugin.d.ts +24 -0
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder_DataCubeApplicationPlugin.d.ts.map +1 -0
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder_DataCubeApplicationPlugin.js +67 -0
- package/lib/components/builder/source/LegendQueryDataCubeSourceBuilder_DataCubeApplicationPlugin.js.map +1 -0
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +3 -2
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts +6 -1
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeDataCubeEngine.js +81 -50
- package/lib/stores/LegendDataCubeDataCubeEngine.js.map +1 -1
- package/lib/stores/builder/LegendDataCubeBuilderStore.d.ts +2 -1
- package/lib/stores/builder/LegendDataCubeBuilderStore.d.ts.map +1 -1
- package/lib/stores/builder/LegendDataCubeBuilderStore.js +4 -2
- package/lib/stores/builder/LegendDataCubeBuilderStore.js.map +1 -1
- package/lib/stores/builder/LegendDataCubeCreatorState.d.ts.map +1 -1
- package/lib/stores/builder/LegendDataCubeCreatorState.js +5 -5
- package/lib/stores/builder/LegendDataCubeCreatorState.js.map +1 -1
- package/lib/stores/builder/source/{AdHocCodeEditorState.d.ts → FreeformExpressionCodeEditorState.d.ts} +2 -2
- package/lib/stores/builder/source/FreeformExpressionCodeEditorState.d.ts.map +1 -0
- package/lib/stores/builder/source/{AdHocCodeEditorState.js → FreeformExpressionCodeEditorState.js} +2 -2
- package/lib/stores/builder/source/FreeformExpressionCodeEditorState.js.map +1 -0
- package/lib/stores/builder/source/{AdhocQueryDataCubeSourceBuilderState.d.ts → FreeformTDSExpressionDataCubeSourceBuilderState.d.ts} +4 -4
- package/lib/stores/builder/source/FreeformTDSExpressionDataCubeSourceBuilderState.d.ts.map +1 -0
- package/lib/stores/builder/source/{AdhocQueryDataCubeSourceBuilderState.js → FreeformTDSExpressionDataCubeSourceBuilderState.js} +8 -8
- package/lib/stores/builder/source/FreeformTDSExpressionDataCubeSourceBuilderState.js.map +1 -0
- package/lib/stores/builder/source/LegendDataCubeSourceBuilderState.d.ts +1 -1
- package/lib/stores/builder/source/LegendDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/builder/source/LegendDataCubeSourceBuilderState.js +1 -1
- package/lib/stores/builder/source/LegendDataCubeSourceBuilderState.js.map +1 -1
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderState.d.ts +21 -3
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderState.js +73 -7
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderState.js.map +1 -1
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.d.ts +20 -0
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.d.ts.map +1 -0
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.js +61 -0
- package/lib/stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.js.map +1 -0
- package/lib/stores/model/LegendQueryDataCubeSource.d.ts +6 -3
- package/lib/stores/model/LegendQueryDataCubeSource.d.ts.map +1 -1
- package/lib/stores/model/LegendQueryDataCubeSource.js +3 -2
- package/lib/stores/model/LegendQueryDataCubeSource.js.map +1 -1
- package/package.json +12 -11
- package/src/application/Core_LegendDataCube_LegendApplicationPlugin.ts +21 -2
- package/src/application/LegendDataCube.tsx +2 -0
- package/src/application/LegendDataCubeApplicationPlugin.ts +15 -0
- package/src/components/__test-utils__/LegendDataCubeStoreTestUtils.tsx +2 -0
- package/src/components/builder/LegendDataCubeBuilder.tsx +34 -20
- package/src/components/builder/LegendDataCubeCreator.tsx +5 -5
- package/src/components/builder/LegendDataCubeSourceViewer.tsx +426 -78
- package/src/components/builder/source/{AdhocQueryDataCubeSourceBuilder.tsx → FreeformTDSExpressionDataCubeSourceBuilder.tsx} +3 -3
- package/src/components/builder/source/LegendQueryDataCubeSourceBuilder.tsx +92 -1
- package/src/components/builder/source/LegendQueryDataCubeSourceBuilder_DataCubeApplicationPlugin.tsx +128 -0
- package/src/stores/LegendDataCubeDataCubeEngine.ts +138 -75
- package/src/stores/builder/LegendDataCubeBuilderStore.tsx +4 -1
- package/src/stores/builder/LegendDataCubeCreatorState.tsx +7 -4
- package/src/stores/builder/source/{AdHocCodeEditorState.tsx → FreeformExpressionCodeEditorState.tsx} +1 -1
- package/src/stores/builder/source/{AdhocQueryDataCubeSourceBuilderState.ts → FreeformTDSExpressionDataCubeSourceBuilderState.ts} +8 -8
- package/src/stores/builder/source/LegendDataCubeSourceBuilderState.ts +1 -1
- package/src/stores/builder/source/LegendQueryDataCubeSourceBuilderState.ts +161 -8
- package/src/stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.ts +121 -0
- package/src/stores/model/LegendQueryDataCubeSource.ts +8 -4
- package/tsconfig.json +5 -3
- package/lib/components/builder/source/AdhocQueryDataCubeSourceBuilder.d.ts.map +0 -1
- package/lib/components/builder/source/AdhocQueryDataCubeSourceBuilder.js.map +0 -1
- package/lib/stores/builder/source/AdHocCodeEditorState.d.ts.map +0 -1
- package/lib/stores/builder/source/AdHocCodeEditorState.js.map +0 -1
- package/lib/stores/builder/source/AdhocQueryDataCubeSourceBuilderState.d.ts.map +0 -1
- package/lib/stores/builder/source/AdhocQueryDataCubeSourceBuilderState.js.map +0 -1
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { observer } from 'mobx-react-lite';
|
|
18
18
|
import { useLegendDataCubeBuilderStore } from './LegendDataCubeBuilderStoreProvider.js';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
LegendQueryDataCubeSource,
|
|
21
|
+
RawLegendQueryDataCubeSource,
|
|
22
|
+
} from '../../stores/model/LegendQueryDataCubeSource.js';
|
|
20
23
|
import { useLegendDataCubeApplicationStore } from '../LegendDataCubeFrameworkProvider.js';
|
|
21
24
|
import {
|
|
22
25
|
EXTERNAL_APPLICATION_NAVIGATION__generateQueryViewUrl,
|
|
@@ -24,20 +27,437 @@ import {
|
|
|
24
27
|
EXTERNAL_APPLICATION_NAVIGATION__generateStudioViewUrl,
|
|
25
28
|
} from '../../__lib__/LegendDataCubeNavigation.js';
|
|
26
29
|
import { DataCubeIcon } from '@finos/legend-art';
|
|
27
|
-
import {
|
|
28
|
-
|
|
30
|
+
import {
|
|
31
|
+
_defaultPrimitiveTypeValue,
|
|
32
|
+
_elementPtr,
|
|
33
|
+
_primitiveValue,
|
|
34
|
+
_property,
|
|
35
|
+
AlertType,
|
|
36
|
+
FormAlert,
|
|
37
|
+
FormButton,
|
|
38
|
+
isPrimitiveType,
|
|
39
|
+
UserDefinedFunctionDataCubeSource,
|
|
40
|
+
} from '@finos/legend-data-cube';
|
|
41
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
29
42
|
import {
|
|
30
43
|
type DepotServerClient,
|
|
31
44
|
DepotScope,
|
|
32
45
|
StoreProjectData,
|
|
33
46
|
} from '@finos/legend-server-depot';
|
|
34
|
-
import { returnUndefOnError } from '@finos/legend-shared';
|
|
35
47
|
import {
|
|
48
|
+
deepClone,
|
|
49
|
+
guaranteeIsString,
|
|
50
|
+
guaranteeNonNullable,
|
|
51
|
+
guaranteeType,
|
|
52
|
+
isNonNullable,
|
|
53
|
+
returnUndefOnError,
|
|
54
|
+
} from '@finos/legend-shared';
|
|
55
|
+
import {
|
|
56
|
+
type LightQuery,
|
|
57
|
+
type PureProtocolProcessorPlugin,
|
|
58
|
+
type V1_Enumeration,
|
|
59
|
+
type V1_PureModelContext,
|
|
60
|
+
type V1_PureModelContextData,
|
|
61
|
+
type V1_Variable,
|
|
62
|
+
PRIMITIVE_TYPE,
|
|
63
|
+
V1_CORE_SYSTEM_MODELS,
|
|
36
64
|
V1_deserializePureModelContext,
|
|
65
|
+
V1_deserializePureModelContextData,
|
|
37
66
|
V1_LegendSDLC,
|
|
67
|
+
V1_observe_ValueSpecification,
|
|
68
|
+
V1_PackageableType,
|
|
38
69
|
V1_PureModelContextPointer,
|
|
39
|
-
|
|
70
|
+
V1_serializeValueSpecification,
|
|
71
|
+
V1_ValueSpecification,
|
|
40
72
|
} from '@finos/legend-graph';
|
|
73
|
+
import {
|
|
74
|
+
isValidV1_ValueSpecification,
|
|
75
|
+
V1_BasicValueSpecificationEditor,
|
|
76
|
+
} from '@finos/legend-query-builder';
|
|
77
|
+
import { LegendDataCubeBuilderState } from '../../stores/builder/LegendDataCubeBuilderStore.js';
|
|
78
|
+
import {
|
|
79
|
+
fetchV1Enumeration,
|
|
80
|
+
isVariableEnumerationType,
|
|
81
|
+
} from '../../stores/builder/source/LegendQueryDataCubeSourceBuilderStateHelper.js';
|
|
82
|
+
|
|
83
|
+
const handleFetchEnumerations = async (
|
|
84
|
+
enumerationVariables: V1_Variable[],
|
|
85
|
+
query: LightQuery,
|
|
86
|
+
systemModel: V1_PureModelContextData,
|
|
87
|
+
depotServerClient: DepotServerClient,
|
|
88
|
+
plugins: PureProtocolProcessorPlugin[],
|
|
89
|
+
updateCallback: (val: { [name: string]: V1_Enumeration }) => void,
|
|
90
|
+
) => {
|
|
91
|
+
await Promise.all(
|
|
92
|
+
enumerationVariables.map(async (variable) => {
|
|
93
|
+
const packageableType = guaranteeType(
|
|
94
|
+
variable.genericType?.rawType,
|
|
95
|
+
V1_PackageableType,
|
|
96
|
+
'Can only edit parameters with packageable type',
|
|
97
|
+
);
|
|
98
|
+
const enumeration = await fetchV1Enumeration(
|
|
99
|
+
packageableType.fullPath,
|
|
100
|
+
query,
|
|
101
|
+
systemModel,
|
|
102
|
+
depotServerClient,
|
|
103
|
+
plugins,
|
|
104
|
+
);
|
|
105
|
+
return { variable, enumeration };
|
|
106
|
+
}),
|
|
107
|
+
).then((response) => {
|
|
108
|
+
const result = response.reduce(
|
|
109
|
+
(acc, { variable, enumeration }) => {
|
|
110
|
+
acc[variable.name] = enumeration;
|
|
111
|
+
return acc;
|
|
112
|
+
},
|
|
113
|
+
{} as { [name: string]: V1_Enumeration },
|
|
114
|
+
);
|
|
115
|
+
updateCallback(result);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const LegendQuerySourceViewer = observer(
|
|
120
|
+
(props: { source: LegendQueryDataCubeSource }) => {
|
|
121
|
+
const { source } = props;
|
|
122
|
+
const store = useLegendDataCubeBuilderStore();
|
|
123
|
+
const application = useLegendDataCubeApplicationStore();
|
|
124
|
+
|
|
125
|
+
const systemModel = useMemo(
|
|
126
|
+
() => V1_deserializePureModelContextData(V1_CORE_SYSTEM_MODELS),
|
|
127
|
+
[],
|
|
128
|
+
);
|
|
129
|
+
const [params, setParams] = useState<
|
|
130
|
+
{ variable: V1_Variable; valueSpec: V1_ValueSpecification }[]
|
|
131
|
+
>(source.parameterValues.map(deepClone));
|
|
132
|
+
const [enumerations, setEnumerations] = useState<{
|
|
133
|
+
[name: string]: V1_Enumeration;
|
|
134
|
+
}>({});
|
|
135
|
+
const [isUpdatingParameters, setIsUpdatingParameters] = useState(false);
|
|
136
|
+
|
|
137
|
+
// If caching is enabled on the grid, we disable editing the query parameters.
|
|
138
|
+
// User will need to disable caching to be able to edit parameters.
|
|
139
|
+
const isCachingEnabled =
|
|
140
|
+
store.builder?.dataCube?.isCachingEnabled() ?? false;
|
|
141
|
+
|
|
142
|
+
const _handleFetchEnumerations = useCallback(async () => {
|
|
143
|
+
const enumerationVariables = source.parameterValues
|
|
144
|
+
.map((parameter) =>
|
|
145
|
+
source.lambda.parameters.find(
|
|
146
|
+
(_param) => parameter.variable.name === _param.name,
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
.filter(isNonNullable)
|
|
150
|
+
.filter(isVariableEnumerationType);
|
|
151
|
+
await handleFetchEnumerations(
|
|
152
|
+
enumerationVariables,
|
|
153
|
+
source.info,
|
|
154
|
+
systemModel,
|
|
155
|
+
store.depotServerClient,
|
|
156
|
+
application.pluginManager.getPureProtocolProcessorPlugins(),
|
|
157
|
+
setEnumerations,
|
|
158
|
+
);
|
|
159
|
+
}, [
|
|
160
|
+
application.pluginManager,
|
|
161
|
+
source,
|
|
162
|
+
store.depotServerClient,
|
|
163
|
+
systemModel,
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
// eslint-disable-next-line no-void
|
|
168
|
+
void void _handleFetchEnumerations();
|
|
169
|
+
}, [_handleFetchEnumerations]);
|
|
170
|
+
|
|
171
|
+
const updateParameterValue = (
|
|
172
|
+
name: string,
|
|
173
|
+
valueSpec: V1_ValueSpecification,
|
|
174
|
+
): void => {
|
|
175
|
+
setParams(
|
|
176
|
+
params.map((param) => {
|
|
177
|
+
if (param.variable.name === name) {
|
|
178
|
+
param.valueSpec = valueSpec;
|
|
179
|
+
}
|
|
180
|
+
return param;
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const updateBuilderWithNewSpecification = async () => {
|
|
186
|
+
// Verify that all params are valid
|
|
187
|
+
if (
|
|
188
|
+
params.some(
|
|
189
|
+
(param) =>
|
|
190
|
+
!isValidV1_ValueSpecification(
|
|
191
|
+
param.valueSpec,
|
|
192
|
+
param.variable.multiplicity,
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
setIsUpdatingParameters(true);
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// Create the new raw source with new parameter values
|
|
203
|
+
const newRawSource = new RawLegendQueryDataCubeSource();
|
|
204
|
+
newRawSource.queryId = source.info.id;
|
|
205
|
+
newRawSource.parameterValues = params.map((param) => {
|
|
206
|
+
const parameterVariable = source.lambda.parameters.find(
|
|
207
|
+
(_param) => _param.name === param.variable.name,
|
|
208
|
+
);
|
|
209
|
+
return [
|
|
210
|
+
JSON.stringify(
|
|
211
|
+
V1_serializeValueSpecification(
|
|
212
|
+
guaranteeNonNullable(parameterVariable),
|
|
213
|
+
application.pluginManager.getPureProtocolProcessorPlugins(),
|
|
214
|
+
),
|
|
215
|
+
),
|
|
216
|
+
JSON.stringify(
|
|
217
|
+
V1_serializeValueSpecification(
|
|
218
|
+
guaranteeType(param.valueSpec, V1_ValueSpecification),
|
|
219
|
+
application.pluginManager.getPureProtocolProcessorPlugins(),
|
|
220
|
+
),
|
|
221
|
+
),
|
|
222
|
+
];
|
|
223
|
+
});
|
|
224
|
+
const newRawSourceData =
|
|
225
|
+
RawLegendQueryDataCubeSource.serialization.toJson(newRawSource);
|
|
226
|
+
|
|
227
|
+
// Process the new raw source and create the new specification
|
|
228
|
+
const newSource = await store.engine.processSource(newRawSourceData);
|
|
229
|
+
const newSpecification = await store.engine.generateBaseSpecification(
|
|
230
|
+
RawLegendQueryDataCubeSource.serialization.toJson(newRawSource),
|
|
231
|
+
newSource,
|
|
232
|
+
);
|
|
233
|
+
newSpecification.configuration =
|
|
234
|
+
store.builder?.initialSpecification.configuration;
|
|
235
|
+
|
|
236
|
+
// Update the builder with a new state containing the new specification
|
|
237
|
+
// We pass in the existing persistent data cube so we don't lose the
|
|
238
|
+
// saved state of the data cube, if it exists.
|
|
239
|
+
store.setBuilder(
|
|
240
|
+
new LegendDataCubeBuilderState(
|
|
241
|
+
store,
|
|
242
|
+
newSpecification,
|
|
243
|
+
store.builder?.persistentDataCube,
|
|
244
|
+
),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
store.sourceViewerDisplay.close();
|
|
248
|
+
} finally {
|
|
249
|
+
setIsUpdatingParameters(false);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const link = application.config.queryApplicationUrl
|
|
254
|
+
? EXTERNAL_APPLICATION_NAVIGATION__generateQueryViewUrl(
|
|
255
|
+
application.config.queryApplicationUrl,
|
|
256
|
+
source.info.id,
|
|
257
|
+
)
|
|
258
|
+
: undefined;
|
|
259
|
+
|
|
260
|
+
const queryHasParameters = params.length > 0;
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<div className="h-full w-full px-2 pt-2">
|
|
264
|
+
<div
|
|
265
|
+
className={`h-[calc(100%_-_${queryHasParameters ? 40 : 8}px)] w-full border border-neutral-300 bg-white`}
|
|
266
|
+
>
|
|
267
|
+
<div className="h-full w-full select-none overflow-auto p-2">
|
|
268
|
+
<div className="flex h-6">
|
|
269
|
+
<div className="flex h-6 items-center text-xl font-medium">
|
|
270
|
+
<DataCubeIcon.Table />
|
|
271
|
+
</div>
|
|
272
|
+
<div className="ml-1 flex h-6 items-center text-xl font-medium">
|
|
273
|
+
Legend Query
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
{link && (
|
|
277
|
+
<div className="mt-2 flex h-6 w-full">
|
|
278
|
+
<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">
|
|
279
|
+
<a
|
|
280
|
+
href={link}
|
|
281
|
+
target="_blank"
|
|
282
|
+
rel="noopener noreferrer"
|
|
283
|
+
className="overflow-hidden overflow-ellipsis whitespace-nowrap"
|
|
284
|
+
>
|
|
285
|
+
{link}
|
|
286
|
+
</a>
|
|
287
|
+
</div>
|
|
288
|
+
<button
|
|
289
|
+
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
290
|
+
onClick={() => {
|
|
291
|
+
store.application.clipboardService
|
|
292
|
+
.copyTextToClipboard(link)
|
|
293
|
+
.catch((error) =>
|
|
294
|
+
store.alertService.alertUnhandledError(error),
|
|
295
|
+
);
|
|
296
|
+
}}
|
|
297
|
+
title="Copy Link"
|
|
298
|
+
>
|
|
299
|
+
<DataCubeIcon.Clipboard />
|
|
300
|
+
</button>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
{!link && (
|
|
304
|
+
<div className="mt-2 flex h-6 w-full">
|
|
305
|
+
<div className="flex h-full w-[calc(100%_-_20px)] items-center border border-r-0 border-neutral-400 bg-neutral-200 px-1.5">
|
|
306
|
+
<div className="overflow-hidden overflow-ellipsis whitespace-nowrap">
|
|
307
|
+
{source.info.id}
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
<button
|
|
311
|
+
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
312
|
+
onClick={() => {
|
|
313
|
+
application.clipboardService
|
|
314
|
+
.copyTextToClipboard(source.info.id)
|
|
315
|
+
.catch((error) =>
|
|
316
|
+
store.alertService.alertUnhandledError(error),
|
|
317
|
+
);
|
|
318
|
+
}}
|
|
319
|
+
title="Copy ID"
|
|
320
|
+
>
|
|
321
|
+
<DataCubeIcon.Clipboard />
|
|
322
|
+
</button>
|
|
323
|
+
</div>
|
|
324
|
+
)}
|
|
325
|
+
{queryHasParameters && (
|
|
326
|
+
<div className="h-50 mt-2 w-full overflow-auto">
|
|
327
|
+
<div>Parameters:</div>
|
|
328
|
+
{params.map(
|
|
329
|
+
(parameter: {
|
|
330
|
+
variable: V1_Variable;
|
|
331
|
+
valueSpec: V1_ValueSpecification;
|
|
332
|
+
}) => {
|
|
333
|
+
const parameterVariable = guaranteeNonNullable(
|
|
334
|
+
source.lambda.parameters.find(
|
|
335
|
+
(param) => param.name === parameter.variable.name,
|
|
336
|
+
),
|
|
337
|
+
`Unable to find parameter with name ${parameter.variable.name} in source lambda`,
|
|
338
|
+
);
|
|
339
|
+
const packageableType = guaranteeType(
|
|
340
|
+
parameterVariable.genericType?.rawType,
|
|
341
|
+
V1_PackageableType,
|
|
342
|
+
'Can only edit parameters with packageable type',
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const resetValue = (): void => {
|
|
346
|
+
if (isPrimitiveType(packageableType.fullPath)) {
|
|
347
|
+
updateParameterValue(
|
|
348
|
+
parameter.variable.name,
|
|
349
|
+
V1_observe_ValueSpecification(
|
|
350
|
+
_primitiveValue(
|
|
351
|
+
packageableType.fullPath,
|
|
352
|
+
_defaultPrimitiveTypeValue(
|
|
353
|
+
packageableType.fullPath,
|
|
354
|
+
),
|
|
355
|
+
),
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
} else {
|
|
359
|
+
// If not a primitive, assume it is an enum
|
|
360
|
+
const typeParam = _elementPtr(
|
|
361
|
+
guaranteeIsString(packageableType.fullPath),
|
|
362
|
+
);
|
|
363
|
+
const valueSpec = _property('', [typeParam]);
|
|
364
|
+
updateParameterValue(
|
|
365
|
+
parameter.variable.name,
|
|
366
|
+
V1_observe_ValueSpecification(valueSpec),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<div
|
|
373
|
+
key={parameter.variable.name}
|
|
374
|
+
className="mt-1 flex h-fit min-h-5 w-full"
|
|
375
|
+
>
|
|
376
|
+
<div className="my-auto">
|
|
377
|
+
{parameter.variable.name}
|
|
378
|
+
{': '}
|
|
379
|
+
</div>
|
|
380
|
+
<V1_BasicValueSpecificationEditor
|
|
381
|
+
valueSpecification={guaranteeType(
|
|
382
|
+
parameter.valueSpec,
|
|
383
|
+
V1_ValueSpecification,
|
|
384
|
+
)}
|
|
385
|
+
multiplicity={parameterVariable.multiplicity}
|
|
386
|
+
typeCheckOption={{
|
|
387
|
+
expectedType: packageableType,
|
|
388
|
+
match:
|
|
389
|
+
packageableType.fullPath ===
|
|
390
|
+
PRIMITIVE_TYPE.DATETIME,
|
|
391
|
+
}}
|
|
392
|
+
setValueSpecification={(
|
|
393
|
+
val: V1_ValueSpecification,
|
|
394
|
+
) => {
|
|
395
|
+
updateParameterValue(
|
|
396
|
+
parameter.variable.name,
|
|
397
|
+
V1_observe_ValueSpecification(val),
|
|
398
|
+
);
|
|
399
|
+
}}
|
|
400
|
+
resetValue={resetValue}
|
|
401
|
+
className="ml-2 flex flex-auto"
|
|
402
|
+
enumeration={enumerations[parameter.variable.name]}
|
|
403
|
+
selectorConfig={{
|
|
404
|
+
optionCustomization: { rowHeight: 20 },
|
|
405
|
+
}}
|
|
406
|
+
lightMode={true}
|
|
407
|
+
readOnly={isCachingEnabled}
|
|
408
|
+
/>
|
|
409
|
+
</div>
|
|
410
|
+
);
|
|
411
|
+
},
|
|
412
|
+
)}
|
|
413
|
+
{isCachingEnabled && (
|
|
414
|
+
<FormAlert
|
|
415
|
+
message="Parameter editing disabled"
|
|
416
|
+
type={AlertType.WARNING}
|
|
417
|
+
text="Parameter editing is disabled while caching is enabled. To update query parameter values, disable caching first."
|
|
418
|
+
className="mt-3"
|
|
419
|
+
/>
|
|
420
|
+
)}
|
|
421
|
+
</div>
|
|
422
|
+
)}
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
{queryHasParameters && (
|
|
426
|
+
<div className="flex h-10 items-center justify-end px-2">
|
|
427
|
+
<FormButton
|
|
428
|
+
disabled={isUpdatingParameters}
|
|
429
|
+
onClick={() => store.sourceViewerDisplay.close()}
|
|
430
|
+
>
|
|
431
|
+
Cancel
|
|
432
|
+
</FormButton>
|
|
433
|
+
<FormButton
|
|
434
|
+
className="ml-2"
|
|
435
|
+
disabled={
|
|
436
|
+
params.some(
|
|
437
|
+
(param) =>
|
|
438
|
+
!isValidV1_ValueSpecification(
|
|
439
|
+
param.valueSpec,
|
|
440
|
+
param.variable.multiplicity,
|
|
441
|
+
),
|
|
442
|
+
) ||
|
|
443
|
+
isCachingEnabled ||
|
|
444
|
+
isUpdatingParameters
|
|
445
|
+
}
|
|
446
|
+
onClick={() => {
|
|
447
|
+
// eslint-disable-next-line no-void
|
|
448
|
+
void (async () => {
|
|
449
|
+
await updateBuilderWithNewSpecification();
|
|
450
|
+
})();
|
|
451
|
+
}}
|
|
452
|
+
>
|
|
453
|
+
Update Query Parameters
|
|
454
|
+
</FormButton>
|
|
455
|
+
</div>
|
|
456
|
+
)}
|
|
457
|
+
</div>
|
|
458
|
+
);
|
|
459
|
+
},
|
|
460
|
+
);
|
|
41
461
|
|
|
42
462
|
const handleFetchProject = (
|
|
43
463
|
depotServerClient: DepotServerClient,
|
|
@@ -191,84 +611,12 @@ const UserDefinedFunctionSourceViewer = observer(
|
|
|
191
611
|
export const LegendDataCubeSourceViewer = observer(() => {
|
|
192
612
|
const store = useLegendDataCubeBuilderStore();
|
|
193
613
|
const source = store.builder?.source;
|
|
194
|
-
const application = useLegendDataCubeApplicationStore();
|
|
195
614
|
|
|
196
615
|
if (!source) {
|
|
197
616
|
return null;
|
|
198
617
|
}
|
|
199
618
|
if (source instanceof LegendQueryDataCubeSource) {
|
|
200
|
-
|
|
201
|
-
? EXTERNAL_APPLICATION_NAVIGATION__generateQueryViewUrl(
|
|
202
|
-
application.config.queryApplicationUrl,
|
|
203
|
-
source.info.id,
|
|
204
|
-
)
|
|
205
|
-
: undefined;
|
|
206
|
-
|
|
207
|
-
return (
|
|
208
|
-
<div className="h-full w-full px-2 pt-2">
|
|
209
|
-
<div className="h-[calc(100%_-_8px)] w-full border border-neutral-300 bg-white">
|
|
210
|
-
<div className="h-full w-full select-none p-2">
|
|
211
|
-
<div className="flex h-6">
|
|
212
|
-
<div className="flex h-6 items-center text-xl font-medium">
|
|
213
|
-
<DataCubeIcon.Table />
|
|
214
|
-
</div>
|
|
215
|
-
<div className="ml-1 flex h-6 items-center text-xl font-medium">
|
|
216
|
-
Legend Query
|
|
217
|
-
</div>
|
|
218
|
-
</div>
|
|
219
|
-
{link && (
|
|
220
|
-
<div className="mt-2 flex h-6 w-full">
|
|
221
|
-
<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">
|
|
222
|
-
<a
|
|
223
|
-
href={link}
|
|
224
|
-
target="_blank"
|
|
225
|
-
rel="noopener noreferrer"
|
|
226
|
-
className="overflow-hidden overflow-ellipsis whitespace-nowrap"
|
|
227
|
-
>
|
|
228
|
-
{link}
|
|
229
|
-
</a>
|
|
230
|
-
</div>
|
|
231
|
-
<button
|
|
232
|
-
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
233
|
-
onClick={() => {
|
|
234
|
-
store.application.clipboardService
|
|
235
|
-
.copyTextToClipboard(link)
|
|
236
|
-
.catch((error) =>
|
|
237
|
-
store.alertService.alertUnhandledError(error),
|
|
238
|
-
);
|
|
239
|
-
}}
|
|
240
|
-
title="Copy Link"
|
|
241
|
-
>
|
|
242
|
-
<DataCubeIcon.Clipboard />
|
|
243
|
-
</button>
|
|
244
|
-
</div>
|
|
245
|
-
)}
|
|
246
|
-
{!link && (
|
|
247
|
-
<div className="mt-2 flex h-6 w-full">
|
|
248
|
-
<div className="flex h-full w-[calc(100%_-_20px)] items-center border border-r-0 border-neutral-400 bg-neutral-200 px-1.5">
|
|
249
|
-
<div className="overflow-hidden overflow-ellipsis whitespace-nowrap">
|
|
250
|
-
{source.info.id}
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
<button
|
|
254
|
-
className="flex aspect-square h-full w-6 items-center justify-center border border-neutral-400 bg-neutral-300 hover:brightness-95"
|
|
255
|
-
onClick={() => {
|
|
256
|
-
application.clipboardService
|
|
257
|
-
.copyTextToClipboard(source.info.id)
|
|
258
|
-
.catch((error) =>
|
|
259
|
-
store.alertService.alertUnhandledError(error),
|
|
260
|
-
);
|
|
261
|
-
}}
|
|
262
|
-
title="Copy ID"
|
|
263
|
-
>
|
|
264
|
-
<DataCubeIcon.Clipboard />
|
|
265
|
-
</button>
|
|
266
|
-
</div>
|
|
267
|
-
)}
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
271
|
-
);
|
|
619
|
+
return <LegendQuerySourceViewer source={source} />;
|
|
272
620
|
} else if (source instanceof UserDefinedFunctionDataCubeSource) {
|
|
273
621
|
return <UserDefinedFunctionSourceViewer source={source} />;
|
|
274
622
|
}
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
V1_deserializePackageableElement,
|
|
34
34
|
} from '@finos/legend-graph';
|
|
35
35
|
import type { Entity } from '@finos/legend-storage';
|
|
36
|
-
import type {
|
|
36
|
+
import type { FreeformTDSExpressionDataCubeSourceBuilderState } from '../../../stores/builder/source/FreeformTDSExpressionDataCubeSourceBuilderState.js';
|
|
37
37
|
import {
|
|
38
38
|
buildProjectOption,
|
|
39
39
|
buildRuntimeOption,
|
|
@@ -53,9 +53,9 @@ export const buildMappingOption = (mapping: V1_Mapping): MappingOption => ({
|
|
|
53
53
|
value: mapping,
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
export const
|
|
56
|
+
export const FreeformTDSExpressionDataCubeSourceBuilder = observer(
|
|
57
57
|
(props: {
|
|
58
|
-
sourceBuilder:
|
|
58
|
+
sourceBuilder: FreeformTDSExpressionDataCubeSourceBuilderState;
|
|
59
59
|
store: LegendDataCubeBuilderStore;
|
|
60
60
|
}) => {
|
|
61
61
|
const { sourceBuilder, store } = props;
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { observer } from 'mobx-react-lite';
|
|
18
18
|
import {
|
|
19
|
+
type QueryLoaderState,
|
|
19
20
|
QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT,
|
|
20
21
|
SORT_BY_OPTIONS,
|
|
21
|
-
|
|
22
|
+
V1_BasicValueSpecificationEditor,
|
|
22
23
|
} from '@finos/legend-query-builder';
|
|
23
24
|
import type { LegendQueryDataCubeSourceBuilderState } from '../../../stores/builder/source/LegendQueryDataCubeSourceBuilderState.js';
|
|
24
25
|
import { generateGAVCoordinates } from '@finos/legend-storage';
|
|
@@ -26,11 +27,17 @@ import { cn, DataCubeIcon, useDropdownMenu } from '@finos/legend-art';
|
|
|
26
27
|
import {
|
|
27
28
|
debounce,
|
|
28
29
|
formatDistanceToNow,
|
|
30
|
+
guaranteeIsString,
|
|
31
|
+
guaranteeType,
|
|
29
32
|
quantifyList,
|
|
30
33
|
} from '@finos/legend-shared';
|
|
31
34
|
import { flowResult } from 'mobx';
|
|
32
35
|
import { useRef, useState, useMemo, useEffect } from 'react';
|
|
33
36
|
import {
|
|
37
|
+
_defaultPrimitiveTypeValue,
|
|
38
|
+
_elementPtr,
|
|
39
|
+
_primitiveValue,
|
|
40
|
+
_property,
|
|
34
41
|
FormButton,
|
|
35
42
|
FormCheckbox,
|
|
36
43
|
FormCodeEditor,
|
|
@@ -38,10 +45,17 @@ import {
|
|
|
38
45
|
FormDropdownMenuItem,
|
|
39
46
|
FormDropdownMenuTrigger,
|
|
40
47
|
FormTextInput,
|
|
48
|
+
isPrimitiveType,
|
|
41
49
|
} from '@finos/legend-data-cube';
|
|
42
50
|
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
|
|
43
51
|
import { useLegendDataCubeBuilderStore } from '../LegendDataCubeBuilderStoreProvider.js';
|
|
44
52
|
import { useApplicationStore } from '@finos/legend-application';
|
|
53
|
+
import {
|
|
54
|
+
type V1_ValueSpecification,
|
|
55
|
+
PRIMITIVE_TYPE,
|
|
56
|
+
V1_observe_ValueSpecification,
|
|
57
|
+
V1_PackageableType,
|
|
58
|
+
} from '@finos/legend-graph';
|
|
45
59
|
|
|
46
60
|
const LegendQuerySearcher = observer((props: { state: QueryLoaderState }) => {
|
|
47
61
|
const { state } = props;
|
|
@@ -319,6 +333,83 @@ export const LegendQueryDataCubeSourceBuilder = observer(
|
|
|
319
333
|
/>
|
|
320
334
|
</div>
|
|
321
335
|
)}
|
|
336
|
+
{sourceBuilder.queryParameters &&
|
|
337
|
+
sourceBuilder.queryParameters.length > 0 && (
|
|
338
|
+
<div className="h-50 mt-2 w-full overflow-auto">
|
|
339
|
+
{sourceBuilder.queryParameterValues &&
|
|
340
|
+
Object.entries(sourceBuilder.queryParameterValues).map(
|
|
341
|
+
([name, { variable, valueSpec }]) => {
|
|
342
|
+
const packageableType = guaranteeType(
|
|
343
|
+
variable.genericType?.rawType,
|
|
344
|
+
V1_PackageableType,
|
|
345
|
+
'Can only edit parameters with packageable type',
|
|
346
|
+
);
|
|
347
|
+
const enumeration = sourceBuilder.queryEnumerations?.[name];
|
|
348
|
+
const resetValue = (): void => {
|
|
349
|
+
if (isPrimitiveType(packageableType.fullPath)) {
|
|
350
|
+
sourceBuilder.setQueryParameterValue(
|
|
351
|
+
name,
|
|
352
|
+
V1_observe_ValueSpecification(
|
|
353
|
+
_primitiveValue(
|
|
354
|
+
packageableType.fullPath,
|
|
355
|
+
_defaultPrimitiveTypeValue(
|
|
356
|
+
packageableType.fullPath,
|
|
357
|
+
),
|
|
358
|
+
),
|
|
359
|
+
),
|
|
360
|
+
);
|
|
361
|
+
} else {
|
|
362
|
+
// If not a primitive, assume it is an enum
|
|
363
|
+
const typeParam = _elementPtr(
|
|
364
|
+
guaranteeIsString(packageableType.fullPath),
|
|
365
|
+
);
|
|
366
|
+
const enumValueSpec = _property('', [typeParam]);
|
|
367
|
+
sourceBuilder.setQueryParameterValue(
|
|
368
|
+
name,
|
|
369
|
+
V1_observe_ValueSpecification(enumValueSpec),
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
return (
|
|
374
|
+
<div
|
|
375
|
+
key={name}
|
|
376
|
+
className="mt-1 flex h-fit min-h-5 w-full"
|
|
377
|
+
>
|
|
378
|
+
<div className="my-auto">
|
|
379
|
+
{name}
|
|
380
|
+
{': '}
|
|
381
|
+
</div>
|
|
382
|
+
<V1_BasicValueSpecificationEditor
|
|
383
|
+
valueSpecification={valueSpec}
|
|
384
|
+
multiplicity={variable.multiplicity}
|
|
385
|
+
typeCheckOption={{
|
|
386
|
+
expectedType: packageableType,
|
|
387
|
+
match:
|
|
388
|
+
packageableType.fullPath ===
|
|
389
|
+
PRIMITIVE_TYPE.DATETIME,
|
|
390
|
+
}}
|
|
391
|
+
setValueSpecification={(
|
|
392
|
+
val: V1_ValueSpecification,
|
|
393
|
+
) => {
|
|
394
|
+
sourceBuilder.setQueryParameterValue(
|
|
395
|
+
name,
|
|
396
|
+
V1_observe_ValueSpecification(val),
|
|
397
|
+
);
|
|
398
|
+
}}
|
|
399
|
+
resetValue={resetValue}
|
|
400
|
+
className="ml-2 flex flex-auto"
|
|
401
|
+
enumeration={enumeration}
|
|
402
|
+
selectorConfig={{
|
|
403
|
+
optionCustomization: { rowHeight: 20 },
|
|
404
|
+
}}
|
|
405
|
+
lightMode={true}
|
|
406
|
+
/>
|
|
407
|
+
</div>
|
|
408
|
+
);
|
|
409
|
+
},
|
|
410
|
+
)}
|
|
411
|
+
</div>
|
|
412
|
+
)}
|
|
322
413
|
<FormButton
|
|
323
414
|
className="mt-2 flex items-center pl-1"
|
|
324
415
|
onClick={() => sourceBuilder.unsetQuery()}
|