@finos/legend-query-builder 3.1.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/__lib__/QueryBuilderColorTheme.d.ts +23 -0
- package/lib/__lib__/QueryBuilderColorTheme.d.ts.map +1 -0
- package/lib/__lib__/QueryBuilderColorTheme.js +24 -0
- package/lib/__lib__/QueryBuilderColorTheme.js.map +1 -0
- package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts +20 -20
- package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderTelemetryHelper.js +40 -40
- package/lib/__lib__/QueryBuilderTelemetryHelper.js.map +1 -1
- package/lib/components/QueryBuilder.d.ts.map +1 -1
- package/lib/components/QueryBuilder.js +17 -15
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.d.ts.map +1 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js +3 -0
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js.map +1 -1
- package/lib/components/QueryLoader.d.ts +30 -0
- package/lib/components/QueryLoader.d.ts.map +1 -0
- package/lib/components/QueryLoader.js +164 -0
- package/lib/components/QueryLoader.js.map +1 -0
- package/lib/components/data-access/DataAccessOverview.d.ts +23 -0
- package/lib/components/data-access/DataAccessOverview.d.ts.map +1 -0
- package/lib/components/data-access/DataAccessOverview.js +146 -0
- package/lib/components/data-access/DataAccessOverview.js.map +1 -0
- package/lib/components/execution-plan/ExecutionPlanViewer.d.ts.map +1 -1
- package/lib/components/execution-plan/ExecutionPlanViewer.js +3 -3
- package/lib/components/execution-plan/ExecutionPlanViewer.js.map +1 -1
- package/lib/components/execution-plan/SQLExecutionNodeViewer.js +1 -1
- package/lib/components/execution-plan/SQLExecutionNodeViewer.js.map +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +1 -1
- package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts +0 -18
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +34 -36
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
- package/lib/components/shared/LambdaEditor.d.ts.map +1 -1
- package/lib/components/shared/LambdaEditor.js +7 -19
- package/lib/components/shared/LambdaEditor.js.map +1 -1
- package/lib/components/shared/QueryBuilderPanelIssueCountBadge.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderPanelIssueCountBadge.js +2 -1
- package/lib/components/shared/QueryBuilderPanelIssueCountBadge.js.map +1 -1
- package/lib/index.css +1 -17
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -1
- package/lib/package.json +4 -2
- package/lib/stores/QueryBuilderState.d.ts +3 -3
- package/lib/stores/QueryBuilderState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderState.js +34 -18
- package/lib/stores/QueryBuilderState.js.map +1 -1
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts +39 -0
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts.map +1 -0
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.js +17 -0
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.js.map +1 -0
- package/lib/stores/QueryLoaderState.d.ts +67 -0
- package/lib/stores/QueryLoaderState.d.ts.map +1 -0
- package/lib/stores/QueryLoaderState.js +205 -0
- package/lib/stores/QueryLoaderState.js.map +1 -0
- package/lib/stores/data-access/DataAccessState.d.ts +56 -0
- package/lib/stores/data-access/DataAccessState.d.ts.map +1 -0
- package/lib/stores/data-access/DataAccessState.js +212 -0
- package/lib/stores/data-access/DataAccessState.js.map +1 -0
- package/lib/stores/entitlements/QueryBuilderCheckEntitlementsState.d.ts +4 -2
- package/lib/stores/entitlements/QueryBuilderCheckEntitlementsState.d.ts.map +1 -1
- package/lib/stores/entitlements/QueryBuilderCheckEntitlementsState.js +20 -6
- package/lib/stores/entitlements/QueryBuilderCheckEntitlementsState.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +3 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +7 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +12 -10
- package/src/__lib__/QueryBuilderColorTheme.ts +23 -0
- package/src/__lib__/QueryBuilderTelemetryHelper.ts +40 -59
- package/src/components/QueryBuilder.tsx +63 -47
- package/src/components/QueryBuilder_LegendApplicationPlugin.ts +4 -0
- package/src/components/QueryLoader.tsx +504 -0
- package/src/components/data-access/DataAccessOverview.tsx +308 -0
- package/src/components/execution-plan/ExecutionPlanViewer.tsx +1 -3
- package/src/components/execution-plan/SQLExecutionNodeViewer.tsx +1 -1
- package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +1 -1
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +99 -102
- package/src/components/shared/LambdaEditor.tsx +4 -21
- package/src/components/shared/QueryBuilderPanelIssueCountBadge.tsx +2 -1
- package/src/index.ts +7 -0
- package/src/stores/QueryBuilderState.ts +65 -19
- package/src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts +46 -0
- package/src/stores/QueryLoaderState.ts +298 -0
- package/src/stores/data-access/DataAccessState.ts +322 -0
- package/src/stores/entitlements/QueryBuilderCheckEntitlementsState.ts +53 -6
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +39 -2
- package/tsconfig.json +6 -0
@@ -0,0 +1,308 @@
|
|
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 { useEffect } from 'react';
|
18
|
+
import { observer } from 'mobx-react-lite';
|
19
|
+
import { useApplicationStore } from '@finos/legend-application';
|
20
|
+
import type {
|
21
|
+
DataAccessState,
|
22
|
+
DatasetAccessInfo,
|
23
|
+
} from '../../stores/data-access/DataAccessState.js';
|
24
|
+
import {
|
25
|
+
CheckCircleIcon,
|
26
|
+
ExclamationCircleIcon,
|
27
|
+
MinusCircleIcon,
|
28
|
+
PanelLoadingIndicator,
|
29
|
+
RefreshIcon,
|
30
|
+
TimesCircleIcon,
|
31
|
+
clsx,
|
32
|
+
} from '@finos/legend-art';
|
33
|
+
import {
|
34
|
+
DataGrid,
|
35
|
+
type DataGridCellRendererParams,
|
36
|
+
} from '@finos/legend-lego/data-grid';
|
37
|
+
import {
|
38
|
+
DatasetEntitlementAccessApprovedReport,
|
39
|
+
DatasetEntitlementAccessGrantedReport,
|
40
|
+
DatasetEntitlementAccessNotGrantedReport,
|
41
|
+
DatasetEntitlementAccessRequestedReport,
|
42
|
+
DatasetEntitlementUnsupportedReport,
|
43
|
+
} from '@finos/legend-graph';
|
44
|
+
import { Doughnut } from 'react-chartjs-2';
|
45
|
+
import { getNullableFirstEntry } from '@finos/legend-shared';
|
46
|
+
import type { QueryBuilder_LegendApplicationPlugin_Extension } from '../../stores/QueryBuilder_LegendApplicationPlugin_Extension.js';
|
47
|
+
|
48
|
+
const DataAccessOverviewChart = observer(
|
49
|
+
(props: { dataAccessState: DataAccessState }) => {
|
50
|
+
const { dataAccessState } = props;
|
51
|
+
const applicationStore = useApplicationStore();
|
52
|
+
const entitlementCheckInfo = dataAccessState.entitlementCheckInfo;
|
53
|
+
const total = entitlementCheckInfo.total;
|
54
|
+
const accessGrantedCount =
|
55
|
+
getNullableFirstEntry(entitlementCheckInfo.data)?.count ?? 0;
|
56
|
+
const accessGrantedPercentage =
|
57
|
+
getNullableFirstEntry(entitlementCheckInfo.data)?.percentage ?? 0;
|
58
|
+
|
59
|
+
return (
|
60
|
+
<div className="data-access-overview__chart">
|
61
|
+
<div className="data-access-overview__chart__actions">
|
62
|
+
<button
|
63
|
+
className="data-access-overview__chart__actions__refresh-btn btn--dark"
|
64
|
+
tabIndex={-1}
|
65
|
+
title="Refresh"
|
66
|
+
onClick={() => {
|
67
|
+
dataAccessState
|
68
|
+
.refresh()
|
69
|
+
.catch(applicationStore.alertUnhandledError);
|
70
|
+
}}
|
71
|
+
>
|
72
|
+
<RefreshIcon />
|
73
|
+
</button>
|
74
|
+
</div>
|
75
|
+
<div className="data-access-overview__chart__container">
|
76
|
+
<Doughnut
|
77
|
+
data={{
|
78
|
+
labels: entitlementCheckInfo.data.map((item) => item.label),
|
79
|
+
datasets: [
|
80
|
+
{
|
81
|
+
data: entitlementCheckInfo.data.map((item) => item.count),
|
82
|
+
backgroundColor: entitlementCheckInfo.data.map(
|
83
|
+
(item) => item.color,
|
84
|
+
),
|
85
|
+
hoverBorderWidth: 0,
|
86
|
+
borderWidth: 0,
|
87
|
+
},
|
88
|
+
],
|
89
|
+
}}
|
90
|
+
options={{
|
91
|
+
responsive: true,
|
92
|
+
resizeDelay: 0,
|
93
|
+
maintainAspectRatio: false,
|
94
|
+
cutout: '75%',
|
95
|
+
plugins: {
|
96
|
+
tooltip: {
|
97
|
+
enabled: total !== 0,
|
98
|
+
usePointStyle: false,
|
99
|
+
boxPadding: 5,
|
100
|
+
callbacks: {
|
101
|
+
labelPointStyle: () => ({
|
102
|
+
pointStyle: 'rectRounded',
|
103
|
+
rotation: 0,
|
104
|
+
}),
|
105
|
+
},
|
106
|
+
},
|
107
|
+
},
|
108
|
+
}}
|
109
|
+
/>
|
110
|
+
<div className="data-access-overview__chart__stats">
|
111
|
+
<div className="data-access-overview__chart__stats__percentage">
|
112
|
+
{accessGrantedPercentage}%
|
113
|
+
</div>
|
114
|
+
<div className="data-access-overview__chart__stats__tally">
|
115
|
+
{total === 0 ? 0 : accessGrantedCount}/{total}
|
116
|
+
</div>
|
117
|
+
</div>
|
118
|
+
</div>
|
119
|
+
</div>
|
120
|
+
);
|
121
|
+
},
|
122
|
+
);
|
123
|
+
|
124
|
+
const AccessStatusCellRenderer = observer(
|
125
|
+
(
|
126
|
+
params: DataGridCellRendererParams<DatasetAccessInfo> & {
|
127
|
+
dataAccessState: DataAccessState;
|
128
|
+
},
|
129
|
+
) => {
|
130
|
+
const { data } = params;
|
131
|
+
const applicationStore = useApplicationStore();
|
132
|
+
|
133
|
+
if (!data) {
|
134
|
+
return null;
|
135
|
+
}
|
136
|
+
|
137
|
+
if (
|
138
|
+
data.entitlementReport instanceof DatasetEntitlementAccessGrantedReport
|
139
|
+
) {
|
140
|
+
return (
|
141
|
+
<div className="data-access-overview__grid__access-status-cell">
|
142
|
+
<div className="data-access-overview__grid__access-status-cell__content">
|
143
|
+
<div className="data-access-overview__grid__access-status-cell__icon data-access-overview__grid__access-status-cell__icon--access-granted">
|
144
|
+
<CheckCircleIcon />
|
145
|
+
</div>
|
146
|
+
<div className="data-access-overview__grid__access-status-cell__text">
|
147
|
+
Access Granted
|
148
|
+
</div>
|
149
|
+
</div>
|
150
|
+
</div>
|
151
|
+
);
|
152
|
+
} else if (
|
153
|
+
data.entitlementReport instanceof DatasetEntitlementAccessApprovedReport
|
154
|
+
) {
|
155
|
+
return (
|
156
|
+
<div className="data-access-overview__grid__access-status-cell">
|
157
|
+
<div className="data-access-overview__grid__access-status-cell__content">
|
158
|
+
<div className="data-access-overview__grid__access-status-cell__icon data-access-overview__grid__access-status-cell__icon--access-approved">
|
159
|
+
<MinusCircleIcon />
|
160
|
+
</div>
|
161
|
+
<div className="data-access-overview__grid__access-status-cell__text">
|
162
|
+
Access Approved
|
163
|
+
</div>
|
164
|
+
</div>
|
165
|
+
</div>
|
166
|
+
);
|
167
|
+
} else if (
|
168
|
+
data.entitlementReport instanceof DatasetEntitlementAccessRequestedReport
|
169
|
+
) {
|
170
|
+
return (
|
171
|
+
<div className="data-access-overview__grid__access-status-cell">
|
172
|
+
<div className="data-access-overview__grid__access-status-cell__content">
|
173
|
+
<div className="data-access-overview__grid__access-status-cell__icon data-access-overview__grid__access-status-cell__icon--access-requested">
|
174
|
+
<ExclamationCircleIcon />
|
175
|
+
</div>
|
176
|
+
<div className="data-access-overview__grid__access-status-cell__text">
|
177
|
+
Access Requested
|
178
|
+
</div>
|
179
|
+
</div>
|
180
|
+
</div>
|
181
|
+
);
|
182
|
+
} else if (
|
183
|
+
data.entitlementReport instanceof DatasetEntitlementAccessNotGrantedReport
|
184
|
+
) {
|
185
|
+
const plugins = applicationStore.pluginManager
|
186
|
+
.getApplicationPlugins()
|
187
|
+
.flatMap(
|
188
|
+
(plugin) =>
|
189
|
+
(
|
190
|
+
plugin as QueryBuilder_LegendApplicationPlugin_Extension
|
191
|
+
).getExtraDatasetEntitlementAccessNotGrantedReportActionConfigurations?.() ??
|
192
|
+
[],
|
193
|
+
);
|
194
|
+
let action: React.ReactNode | undefined;
|
195
|
+
for (const plugin of plugins) {
|
196
|
+
action = plugin.renderer(data);
|
197
|
+
if (action) {
|
198
|
+
break;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
return (
|
202
|
+
<div className="data-access-overview__grid__access-status-cell">
|
203
|
+
<div className="data-access-overview__grid__access-status-cell__content">
|
204
|
+
<div className="data-access-overview__grid__access-status-cell__icon data-access-overview__grid__access-status-cell__icon--access-not-granted">
|
205
|
+
<TimesCircleIcon />
|
206
|
+
</div>
|
207
|
+
<div className="data-access-overview__grid__access-status-cell__text">
|
208
|
+
Access Not Granted
|
209
|
+
</div>
|
210
|
+
</div>
|
211
|
+
{action && (
|
212
|
+
<div className="data-access-overview__grid__access-status-cell__action">
|
213
|
+
{action}
|
214
|
+
</div>
|
215
|
+
)}
|
216
|
+
</div>
|
217
|
+
);
|
218
|
+
} else if (
|
219
|
+
data.entitlementReport instanceof DatasetEntitlementUnsupportedReport
|
220
|
+
) {
|
221
|
+
return (
|
222
|
+
<div className="data-access-overview__grid__empty-cell">
|
223
|
+
(unsupported)
|
224
|
+
</div>
|
225
|
+
);
|
226
|
+
}
|
227
|
+
|
228
|
+
return null;
|
229
|
+
},
|
230
|
+
);
|
231
|
+
|
232
|
+
const DataAccessOverviewGrid = observer(
|
233
|
+
(props: { dataAccessState: DataAccessState }) => {
|
234
|
+
const { dataAccessState } = props;
|
235
|
+
|
236
|
+
return (
|
237
|
+
<div className="data-access-overview__grid ag-theme-balham-dark">
|
238
|
+
<DataGrid
|
239
|
+
rowData={dataAccessState.datasets}
|
240
|
+
gridOptions={{
|
241
|
+
suppressScrollOnNewData: true,
|
242
|
+
getRowId: (rowData) => rowData.data.uuid,
|
243
|
+
}}
|
244
|
+
columnDefs={[
|
245
|
+
{
|
246
|
+
minWidth: 50,
|
247
|
+
sortable: true,
|
248
|
+
resizable: true,
|
249
|
+
field: 'specification.name',
|
250
|
+
headerName: 'Dataset',
|
251
|
+
flex: 1,
|
252
|
+
},
|
253
|
+
{
|
254
|
+
minWidth: 50,
|
255
|
+
sortable: true,
|
256
|
+
resizable: true,
|
257
|
+
field: 'specification.type',
|
258
|
+
headerName: 'Type',
|
259
|
+
flex: 1,
|
260
|
+
},
|
261
|
+
{
|
262
|
+
minWidth: 50,
|
263
|
+
sortable: true,
|
264
|
+
resizable: true,
|
265
|
+
headerName: 'Access Status',
|
266
|
+
cellRendererParams: {
|
267
|
+
dataAccessState,
|
268
|
+
},
|
269
|
+
cellRenderer: AccessStatusCellRenderer,
|
270
|
+
flex: 1,
|
271
|
+
},
|
272
|
+
]}
|
273
|
+
/>
|
274
|
+
</div>
|
275
|
+
);
|
276
|
+
},
|
277
|
+
);
|
278
|
+
|
279
|
+
export const DataAccessOverview = observer(
|
280
|
+
(props: {
|
281
|
+
dataAccessState: DataAccessState;
|
282
|
+
compact?: boolean | undefined;
|
283
|
+
}) => {
|
284
|
+
const { dataAccessState, compact } = props;
|
285
|
+
const applicationStore = useApplicationStore();
|
286
|
+
|
287
|
+
useEffect(() => {
|
288
|
+
dataAccessState.intialize().catch(applicationStore.alertUnhandledError);
|
289
|
+
}, [applicationStore, dataAccessState]);
|
290
|
+
|
291
|
+
return (
|
292
|
+
<div
|
293
|
+
className={clsx('data-access-overview', {
|
294
|
+
'data-access-overview--compact': Boolean(compact),
|
295
|
+
})}
|
296
|
+
>
|
297
|
+
<PanelLoadingIndicator
|
298
|
+
isLoading={
|
299
|
+
dataAccessState.surveyDatasetsState.isInProgress ||
|
300
|
+
dataAccessState.checkEntitlementsState.isInProgress
|
301
|
+
}
|
302
|
+
/>
|
303
|
+
<DataAccessOverviewChart dataAccessState={dataAccessState} />
|
304
|
+
<DataAccessOverviewGrid dataAccessState={dataAccessState} />
|
305
|
+
</div>
|
306
|
+
);
|
307
|
+
},
|
308
|
+
);
|
@@ -380,7 +380,7 @@ const ExecutionPlanViewPanel = observer(
|
|
380
380
|
inputValue={displayData}
|
381
381
|
isReadOnly={true}
|
382
382
|
language={CODE_EDITOR_LANGUAGE.JSON}
|
383
|
-
|
383
|
+
hideMinimap={true}
|
384
384
|
/>
|
385
385
|
)}
|
386
386
|
{executionPlanState.viewMode ===
|
@@ -462,7 +462,6 @@ const ExecutionPlanViewerContent = observer(
|
|
462
462
|
inputValue={JSON.stringify(rawPlan, undefined, DEFAULT_TAB_SIZE)}
|
463
463
|
isReadOnly={true}
|
464
464
|
language={CODE_EDITOR_LANGUAGE.JSON}
|
465
|
-
showMiniMap={true}
|
466
465
|
/>
|
467
466
|
)}
|
468
467
|
</div>
|
@@ -523,7 +522,6 @@ export const ExecutionPlanViewer = observer(
|
|
523
522
|
inputValue={executionPlanState.debugText}
|
524
523
|
isReadOnly={true}
|
525
524
|
language={CODE_EDITOR_LANGUAGE.TEXT}
|
526
|
-
showMiniMap={true}
|
527
525
|
/>
|
528
526
|
</PanelContent>
|
529
527
|
</div>
|
@@ -39,8 +39,8 @@ import {
|
|
39
39
|
CalendarIcon,
|
40
40
|
CalendarClockIcon,
|
41
41
|
CustomSelectorInput,
|
42
|
-
PURE_FunctionIcon,
|
43
42
|
PanelEntryDropZonePlaceholder,
|
43
|
+
FunctionIcon,
|
44
44
|
} from '@finos/legend-art';
|
45
45
|
import {
|
46
46
|
type QueryBuilderExplorerTreeDragSource,
|
@@ -102,62 +102,6 @@ import { getPropertyChainName } from '../../stores/QueryBuilderPropertyEditorSta
|
|
102
102
|
import { generateDefaultValueForPrimitiveType } from '../../stores/QueryBuilderValueSpecificationHelper.js';
|
103
103
|
import { QUERY_BUILDER_CALENDAR_TYPE } from '../../graph-manager/QueryBuilderConst.js';
|
104
104
|
|
105
|
-
export type CalendarFunctionOption = {
|
106
|
-
label: string | React.ReactNode;
|
107
|
-
value: QueryBuilderAggregateCalendarFunction;
|
108
|
-
};
|
109
|
-
|
110
|
-
export const buildCalendarFunctionOption = (
|
111
|
-
calendarFunction: QueryBuilderAggregateCalendarFunction,
|
112
|
-
): CalendarFunctionOption => ({
|
113
|
-
label: (
|
114
|
-
<div
|
115
|
-
className="query-builder__projection__calendar__function__label"
|
116
|
-
title={calendarFunction.getLabel()}
|
117
|
-
>
|
118
|
-
<PURE_FunctionIcon />
|
119
|
-
<div className="query-builder__projection__calendar__function__label__title">
|
120
|
-
{calendarFunction.getLabel()}
|
121
|
-
</div>
|
122
|
-
</div>
|
123
|
-
),
|
124
|
-
value: calendarFunction,
|
125
|
-
});
|
126
|
-
|
127
|
-
export type CalendarFunctionDateColumnOption = {
|
128
|
-
label: string;
|
129
|
-
value: AbstractPropertyExpression;
|
130
|
-
};
|
131
|
-
|
132
|
-
export const buildCalendarFunctionDateColumnOption = (
|
133
|
-
dateColumn: Property | AbstractPropertyExpression,
|
134
|
-
parameter: VariableExpression,
|
135
|
-
humanizeLabel: boolean,
|
136
|
-
): CalendarFunctionDateColumnOption => {
|
137
|
-
if (dateColumn instanceof Property) {
|
138
|
-
const propertyExpression = new AbstractPropertyExpression('');
|
139
|
-
propertyExpression_setFunc(
|
140
|
-
propertyExpression,
|
141
|
-
PropertyExplicitReference.create(guaranteeNonNullable(dateColumn)),
|
142
|
-
);
|
143
|
-
propertyExpression.parametersValues = [parameter];
|
144
|
-
return {
|
145
|
-
label: getPropertyChainName(propertyExpression, humanizeLabel),
|
146
|
-
value: propertyExpression,
|
147
|
-
};
|
148
|
-
} else {
|
149
|
-
return {
|
150
|
-
label: getPropertyChainName(dateColumn, humanizeLabel),
|
151
|
-
value: dateColumn,
|
152
|
-
};
|
153
|
-
}
|
154
|
-
};
|
155
|
-
|
156
|
-
export type CalendarTypeOption = {
|
157
|
-
label: string;
|
158
|
-
value: QUERY_BUILDER_CALENDAR_TYPE;
|
159
|
-
};
|
160
|
-
|
161
105
|
const QueryBuilderProjectionColumnContextMenu = observer(
|
162
106
|
forwardRef<
|
163
107
|
HTMLDivElement,
|
@@ -304,6 +248,76 @@ const QueryBuilderDerivationProjectionColumnEditor = observer(
|
|
304
248
|
},
|
305
249
|
);
|
306
250
|
|
251
|
+
type CalendarFunctionOption = {
|
252
|
+
label: string | React.ReactNode;
|
253
|
+
value: QueryBuilderAggregateCalendarFunction;
|
254
|
+
};
|
255
|
+
|
256
|
+
const buildCalendarFunctionOption = (
|
257
|
+
calendarFunction: QueryBuilderAggregateCalendarFunction,
|
258
|
+
): CalendarFunctionOption => ({
|
259
|
+
label: (
|
260
|
+
<div
|
261
|
+
className="query-builder__projection__calendar__function__label"
|
262
|
+
title={calendarFunction.getLabel()}
|
263
|
+
>
|
264
|
+
<FunctionIcon className="query-builder__projection__calendar__function__label__icon" />
|
265
|
+
<div className="query-builder__projection__calendar__function__label__title">
|
266
|
+
{calendarFunction.getLabel()}
|
267
|
+
</div>
|
268
|
+
</div>
|
269
|
+
),
|
270
|
+
value: calendarFunction,
|
271
|
+
});
|
272
|
+
|
273
|
+
type CalendarFunctionDateColumnOption = {
|
274
|
+
label: React.ReactNode;
|
275
|
+
value: AbstractPropertyExpression;
|
276
|
+
};
|
277
|
+
|
278
|
+
const buildCalendarFunctionDateColumnOption = (
|
279
|
+
dateColumn: Property | AbstractPropertyExpression,
|
280
|
+
parameter: VariableExpression,
|
281
|
+
humanizeLabel: boolean,
|
282
|
+
): CalendarFunctionDateColumnOption => {
|
283
|
+
if (dateColumn instanceof Property) {
|
284
|
+
const propertyExpression = new AbstractPropertyExpression('');
|
285
|
+
propertyExpression_setFunc(
|
286
|
+
propertyExpression,
|
287
|
+
PropertyExplicitReference.create(guaranteeNonNullable(dateColumn)),
|
288
|
+
);
|
289
|
+
propertyExpression.parametersValues = [parameter];
|
290
|
+
return {
|
291
|
+
label: getPropertyChainName(propertyExpression, humanizeLabel),
|
292
|
+
value: propertyExpression,
|
293
|
+
};
|
294
|
+
} else {
|
295
|
+
return {
|
296
|
+
label: getPropertyChainName(dateColumn, humanizeLabel),
|
297
|
+
value: dateColumn,
|
298
|
+
};
|
299
|
+
}
|
300
|
+
};
|
301
|
+
|
302
|
+
type CalendarTypeOption = {
|
303
|
+
label: React.ReactNode;
|
304
|
+
value: QUERY_BUILDER_CALENDAR_TYPE;
|
305
|
+
};
|
306
|
+
|
307
|
+
const buildCalendarTypeOption = (
|
308
|
+
val: QUERY_BUILDER_CALENDAR_TYPE,
|
309
|
+
): CalendarTypeOption => ({
|
310
|
+
label: (
|
311
|
+
<div className="query-builder__projection__calendar__type__option">
|
312
|
+
<CalendarIcon className="query-builder__projection__calendar__type__option__icon" />
|
313
|
+
<div className="query-builder__projection__calendar__type__option__title">
|
314
|
+
{val}
|
315
|
+
</div>
|
316
|
+
</div>
|
317
|
+
),
|
318
|
+
value: val,
|
319
|
+
});
|
320
|
+
|
307
321
|
const QueryBuilderProjectionColumnEditor = observer(
|
308
322
|
(props: { projectionColumnState: QueryBuilderProjectionColumnState }) => {
|
309
323
|
const handleRef = useRef<HTMLDivElement>(null);
|
@@ -369,31 +383,13 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
369
383
|
),
|
370
384
|
);
|
371
385
|
const calendarTypeOptions = Object.values(QUERY_BUILDER_CALENDAR_TYPE).map(
|
372
|
-
|
373
|
-
label: (
|
374
|
-
<div className="query-builder__projection__calendar__type__option">
|
375
|
-
<CalendarIcon />
|
376
|
-
<div className="query-builder__projection__calendar__type__option__title">
|
377
|
-
{ct}
|
378
|
-
</div>
|
379
|
-
</div>
|
380
|
-
),
|
381
|
-
value: ct,
|
382
|
-
}),
|
386
|
+
buildCalendarTypeOption,
|
383
387
|
);
|
384
388
|
const selectedCalendarTypeOption = aggregateColumnState?.calendarFunction
|
385
389
|
?.calendarType
|
386
|
-
?
|
387
|
-
|
388
|
-
|
389
|
-
<CalendarIcon />
|
390
|
-
<div className="query-builder__projection__calendar__type__option__title">
|
391
|
-
{aggregateColumnState.calendarFunction.calendarType}
|
392
|
-
</div>
|
393
|
-
</div>
|
394
|
-
),
|
395
|
-
value: aggregateColumnState.calendarFunction.calendarType,
|
396
|
-
}
|
390
|
+
? buildCalendarTypeOption(
|
391
|
+
aggregateColumnState.calendarFunction.calendarType,
|
392
|
+
)
|
397
393
|
: null;
|
398
394
|
const onCalendarTypeOptionChange = (option: CalendarTypeOption): void => {
|
399
395
|
if (
|
@@ -661,13 +657,15 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
661
657
|
aggregateColumnState &&
|
662
658
|
aggregateCalendarFunctions.length > 0 && (
|
663
659
|
<div
|
664
|
-
className={
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
660
|
+
className={clsx(
|
661
|
+
'query-builder__projection__column__aggregate__calendar__toggler',
|
662
|
+
{
|
663
|
+
'query-builder__projection__column__aggregate__calendar__toggler--active':
|
664
|
+
!aggregateColumnState.hideCalendarColumnState,
|
665
|
+
},
|
666
|
+
)}
|
669
667
|
onClick={toggleHideCalendarColumnState}
|
670
|
-
title="
|
668
|
+
title="Toggle calendar aggregation"
|
671
669
|
>
|
672
670
|
<CalendarClockIcon />
|
673
671
|
</div>
|
@@ -749,21 +747,19 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
749
747
|
},
|
750
748
|
)}
|
751
749
|
>
|
752
|
-
<
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
/>
|
766
|
-
</div>
|
750
|
+
<CustomSelectorInput
|
751
|
+
className="query-builder__projection__calendar__function"
|
752
|
+
options={calendarFunctionOptions}
|
753
|
+
onChange={onCalendarFunctionOptionChange}
|
754
|
+
value={selectedCalendarFunctionOption}
|
755
|
+
placeholder="Select Calendar Function"
|
756
|
+
isClearable={true}
|
757
|
+
escapeClearsValue={true}
|
758
|
+
darkMode={
|
759
|
+
!applicationStore.layoutService
|
760
|
+
.TEMPORARY__isLightColorThemeEnabled
|
761
|
+
}
|
762
|
+
/>
|
767
763
|
<div className="query-builder__projection__calendar__value">
|
768
764
|
<BasicValueSpecificationEditor
|
769
765
|
valueSpecification={
|
@@ -807,7 +803,7 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
807
803
|
</div>
|
808
804
|
</div>
|
809
805
|
) : (
|
810
|
-
<div className="query-
|
806
|
+
<div className="query-builder__projection__calendar__date__column__placeholder">
|
811
807
|
Drag and drop date column here
|
812
808
|
</div>
|
813
809
|
)}
|
@@ -818,7 +814,8 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
818
814
|
options={calendarTypeOptions}
|
819
815
|
onChange={onCalendarTypeOptionChange}
|
820
816
|
value={selectedCalendarTypeOption ?? calendarTypeOptions[0]}
|
821
|
-
placeholder=
|
817
|
+
placeholder="Select calendar type"
|
818
|
+
disabled={!aggregateColumnState.calendarFunction}
|
822
819
|
darkMode={
|
823
820
|
!applicationStore.layoutService
|
824
821
|
.TEMPORARY__isLightColorThemeEnabled
|
@@ -23,7 +23,6 @@ import {
|
|
23
23
|
LongArrowAltDownIcon,
|
24
24
|
LongArrowAltUpIcon,
|
25
25
|
Dialog,
|
26
|
-
useResizeDetector,
|
27
26
|
Modal,
|
28
27
|
ModalBody,
|
29
28
|
ModalFooter,
|
@@ -154,13 +153,6 @@ const LambdaEditorInline = observer(
|
|
154
153
|
}
|
155
154
|
};
|
156
155
|
|
157
|
-
const { ref, width, height } = useResizeDetector<HTMLDivElement>();
|
158
|
-
useEffect(() => {
|
159
|
-
if (width !== undefined && height !== undefined) {
|
160
|
-
editor?.layout({ width, height });
|
161
|
-
}
|
162
|
-
}, [editor, width, height]);
|
163
|
-
|
164
156
|
useEffect(() => {
|
165
157
|
if (!editor && textInputRef.current) {
|
166
158
|
const element = textInputRef.current;
|
@@ -187,8 +179,8 @@ const LambdaEditorInline = observer(
|
|
187
179
|
language: CODE_EDITOR_LANGUAGE.PURE,
|
188
180
|
theme: applicationStore.layoutService
|
189
181
|
.TEMPORARY__isLightColorThemeEnabled
|
190
|
-
? CODE_EDITOR_THEME.
|
191
|
-
: CODE_EDITOR_THEME.
|
182
|
+
? CODE_EDITOR_THEME.BUILT_IN__VSCODE_LIGHT
|
183
|
+
: CODE_EDITOR_THEME.DEFAULT_DARK,
|
192
184
|
...lambdaEditorOptions,
|
193
185
|
});
|
194
186
|
setEditor(_editor);
|
@@ -341,7 +333,6 @@ const LambdaEditorInline = observer(
|
|
341
333
|
})}
|
342
334
|
>
|
343
335
|
<div
|
344
|
-
ref={ref}
|
345
336
|
data-testid={QUERY_BUILDER_TEST_ID.LAMBDA_EDITOR__EDITOR_INPUT}
|
346
337
|
className="lambda-editor__editor__input"
|
347
338
|
>
|
@@ -451,13 +442,6 @@ const LambdaEditorPopUp = observer(
|
|
451
442
|
transformLambdaToString(true),
|
452
443
|
);
|
453
444
|
|
454
|
-
const { ref, width, height } = useResizeDetector<HTMLDivElement>();
|
455
|
-
useEffect(() => {
|
456
|
-
if (width !== undefined && height !== undefined) {
|
457
|
-
editor?.layout({ width, height });
|
458
|
-
}
|
459
|
-
}, [editor, width, height]);
|
460
|
-
|
461
445
|
const onEnter = (): void => {
|
462
446
|
if (!editor && textInputRef.current) {
|
463
447
|
const element = textInputRef.current;
|
@@ -466,8 +450,8 @@ const LambdaEditorPopUp = observer(
|
|
466
450
|
language: CODE_EDITOR_LANGUAGE.PURE,
|
467
451
|
theme: applicationStore.layoutService
|
468
452
|
.TEMPORARY__isLightColorThemeEnabled
|
469
|
-
? CODE_EDITOR_THEME.
|
470
|
-
: CODE_EDITOR_THEME.
|
453
|
+
? CODE_EDITOR_THEME.BUILT_IN__VSCODE_LIGHT
|
454
|
+
: CODE_EDITOR_THEME.DEFAULT_DARK,
|
471
455
|
});
|
472
456
|
setEditor(_editor);
|
473
457
|
}
|
@@ -613,7 +597,6 @@ const LambdaEditorPopUp = observer(
|
|
613
597
|
<ModalBody>
|
614
598
|
<div className={clsx('lambda-editor__popup__content', className)}>
|
615
599
|
<div
|
616
|
-
ref={ref}
|
617
600
|
data-testid={QUERY_BUILDER_TEST_ID.LAMBDA_EDITOR__EDITOR_INPUT}
|
618
601
|
className="lambda-editor__editor__input"
|
619
602
|
>
|