@finos/legend-query-builder 3.2.0 → 3.2.2
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__/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/components/QueryBuilder.d.ts.map +1 -1
- package/lib/components/QueryBuilder.js +24 -34
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.d.ts +0 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.d.ts.map +1 -1
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js +3 -4
- package/lib/components/QueryBuilder_LegendApplicationPlugin.js.map +1 -1
- package/lib/components/QueryLoader.d.ts.map +1 -1
- package/lib/components/QueryLoader.js +6 -2
- package/lib/components/QueryLoader.js.map +1 -1
- 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/QueryBuilderResultModifierPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +2 -2
- package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.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/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/package.json +6 -4
- 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 +9 -0
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts.map +1 -1
- 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/package.json +14 -12
- package/src/__lib__/QueryBuilderColorTheme.ts +23 -0
- package/src/components/QueryBuilder.tsx +85 -96
- package/src/components/QueryBuilder_LegendApplicationPlugin.ts +4 -5
- package/src/components/QueryLoader.tsx +4 -1
- 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/QueryBuilderResultModifierPanel.tsx +2 -3
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +99 -102
- package/src/components/shared/LambdaEditor.tsx +4 -21
- package/src/index.ts +4 -0
- package/src/stores/QueryBuilderState.ts +65 -19
- package/src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts +10 -0
- package/src/stores/data-access/DataAccessState.ts +322 -0
- package/src/stores/entitlements/QueryBuilderCheckEntitlementsState.ts +53 -6
- package/tsconfig.json +3 -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>
|
@@ -30,6 +30,7 @@ import {
|
|
30
30
|
DropdownMenu,
|
31
31
|
MenuContent,
|
32
32
|
MenuContentItem,
|
33
|
+
ModalFooterButton,
|
33
34
|
} from '@finos/legend-art';
|
34
35
|
import {
|
35
36
|
COLUMN_SORT_TYPE,
|
@@ -262,9 +263,7 @@ export const QueryResultModifierModal = observer(
|
|
262
263
|
</div>
|
263
264
|
</ModalBody>
|
264
265
|
<ModalFooter>
|
265
|
-
<
|
266
|
-
Close
|
267
|
-
</button>
|
266
|
+
<ModalFooterButton onClick={close} text="Close" />
|
268
267
|
</ModalFooter>
|
269
268
|
</Modal>
|
270
269
|
</Dialog>
|
@@ -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
|