@finos/legend-query-builder 4.18.32 → 4.19.0
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__/QueryBuilderSetting.d.ts +1 -2
- package/lib/__lib__/QueryBuilderSetting.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderSetting.js +0 -4
- package/lib/__lib__/QueryBuilderSetting.js.map +1 -1
- package/lib/components/QueryBuilder.d.ts.map +1 -1
- package/lib/components/QueryBuilder.js +3 -7
- package/lib/components/QueryBuilder.js.map +1 -1
- package/lib/components/QueryBuilderUnsupportedQueryEditor.d.ts.map +1 -1
- package/lib/components/QueryBuilderUnsupportedQueryEditor.js +1 -2
- package/lib/components/QueryBuilderUnsupportedQueryEditor.js.map +1 -1
- package/lib/components/QueryLoader.d.ts.map +1 -1
- package/lib/components/QueryLoader.js +215 -92
- package/lib/components/QueryLoader.js.map +1 -1
- package/lib/components/{QueryChat.d.ts → lakehouse/IngestionDefinitionArtifactViewer.d.ts} +7 -5
- package/lib/components/lakehouse/IngestionDefinitionArtifactViewer.d.ts.map +1 -0
- package/lib/components/lakehouse/IngestionDefinitionArtifactViewer.js +122 -0
- package/lib/components/lakehouse/IngestionDefinitionArtifactViewer.js.map +1 -0
- package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts +2 -1
- package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts.map +1 -1
- package/lib/components/result/tds/QueryBuilderTDSResultShared.js +2 -2
- package/lib/components/result/tds/QueryBuilderTDSResultShared.js.map +1 -1
- package/lib/components/workflows/DataProductQueryBuilder.d.ts.map +1 -1
- package/lib/components/workflows/DataProductQueryBuilder.js +7 -4
- package/lib/components/workflows/DataProductQueryBuilder.js.map +1 -1
- package/lib/data-access-overview.css +1 -1
- package/lib/graph-manager/QueryBuilderConfig.d.ts +0 -8
- package/lib/graph-manager/QueryBuilderConfig.d.ts.map +1 -1
- package/lib/graph-manager/QueryBuilderConfig.js +0 -10
- package/lib/graph-manager/QueryBuilderConfig.js.map +1 -1
- package/lib/index.css +1 -17
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryBuilderState.d.ts +0 -5
- package/lib/stores/QueryBuilderState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderState.js +0 -19
- package/lib/stores/QueryBuilderState.js.map +1 -1
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts +0 -5
- package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts.map +1 -1
- package/lib/stores/QueryLoaderState.d.ts +39 -3
- package/lib/stores/QueryLoaderState.d.ts.map +1 -1
- package/lib/stores/QueryLoaderState.js +129 -2
- package/lib/stores/QueryLoaderState.js.map +1 -1
- package/lib/stores/workflows/dataProduct/DataProductQueryBuilderState.d.ts +6 -0
- package/lib/stores/workflows/dataProduct/DataProductQueryBuilderState.d.ts.map +1 -1
- package/lib/stores/workflows/dataProduct/DataProductQueryBuilderState.js +6 -3
- package/lib/stores/workflows/dataProduct/DataProductQueryBuilderState.js.map +1 -1
- package/package.json +7 -7
- package/src/__lib__/QueryBuilderSetting.ts +0 -4
- package/src/components/QueryBuilder.tsx +0 -31
- package/src/components/QueryBuilderUnsupportedQueryEditor.tsx +0 -7
- package/src/components/QueryLoader.tsx +708 -381
- package/src/components/lakehouse/IngestionDefinitionArtifactViewer.tsx +370 -0
- package/src/components/result/tds/QueryBuilderTDSResultShared.tsx +6 -3
- package/src/components/workflows/DataProductQueryBuilder.tsx +20 -5
- package/src/graph-manager/QueryBuilderConfig.ts +0 -11
- package/src/index.ts +1 -1
- package/src/stores/QueryBuilderState.ts +0 -26
- package/src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts +0 -9
- package/src/stores/QueryLoaderState.ts +173 -2
- package/src/stores/workflows/dataProduct/DataProductQueryBuilderState.ts +17 -8
- package/tsconfig.json +1 -2
- package/lib/components/QueryChat.d.ts.map +0 -1
- package/lib/components/QueryChat.js +0 -26
- package/lib/components/QueryChat.js.map +0 -1
- package/lib/stores/QueryChatState.d.ts +0 -19
- package/lib/stores/QueryChatState.d.ts.map +0 -1
- package/lib/stores/QueryChatState.js +0 -18
- package/lib/stores/QueryChatState.js.map +0 -1
- package/src/components/QueryChat.tsx +0 -38
- package/src/stores/QueryChatState.ts +0 -19
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
useApplicationStore,
|
|
19
|
+
ActionAlertType,
|
|
20
|
+
ActionAlertActionType,
|
|
21
|
+
} from '@finos/legend-application';
|
|
18
22
|
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
|
|
19
|
-
import { CodeEditor } from '@finos/legend-lego/code-editor';
|
|
23
|
+
import { CodeEditor, CodeDiffView } from '@finos/legend-lego/code-editor';
|
|
20
24
|
import {
|
|
21
25
|
Dialog,
|
|
22
26
|
Modal,
|
|
@@ -36,10 +40,12 @@ import {
|
|
|
36
40
|
LastModifiedIcon,
|
|
37
41
|
MoreVerticalIcon,
|
|
38
42
|
ThinChevronRightIcon,
|
|
43
|
+
ArrowLeftIcon,
|
|
39
44
|
InfoCircleIcon,
|
|
40
45
|
CustomSelectorInput,
|
|
41
46
|
CubesLoadingIndicator,
|
|
42
47
|
CubesLoadingIndicatorIcon,
|
|
48
|
+
BlankPanelContent,
|
|
43
49
|
} from '@finos/legend-art';
|
|
44
50
|
import type { LightQuery, RawLambda } from '@finos/legend-graph';
|
|
45
51
|
import {
|
|
@@ -51,25 +57,88 @@ import {
|
|
|
51
57
|
} from '@finos/legend-shared';
|
|
52
58
|
import { flowResult } from 'mobx';
|
|
53
59
|
import { observer } from 'mobx-react-lite';
|
|
54
|
-
import { useRef, useState, useMemo, useEffect } from 'react';
|
|
60
|
+
import { useRef, useState, useMemo, useEffect, type ReactNode } from 'react';
|
|
55
61
|
import {
|
|
56
62
|
QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT,
|
|
57
63
|
SORT_BY_OPTIONS,
|
|
58
64
|
type QueryLoaderState,
|
|
65
|
+
type QueryRevisionDiffInput,
|
|
59
66
|
type SortByOption,
|
|
60
67
|
} from '../stores/QueryLoaderState.js';
|
|
61
68
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const LATEST_REVISION_KEY = 'latest';
|
|
70
|
+
|
|
71
|
+
// Numeric ordering key for a revision `version`. The value is typed as a string
|
|
72
|
+
// but can arrive as a number at runtime, so coerce before parsing (e.g. 4 -> 4,
|
|
73
|
+
// "rev-2" -> 2); undefined/unparseable versions sort last.
|
|
74
|
+
const revisionSortKey = (version: string | undefined): number => {
|
|
75
|
+
const match = String(version ?? '').match(/\d+/);
|
|
76
|
+
return match ? Number(match[0]) : Number.NEGATIVE_INFINITY;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Shared "last updated · owner" line rendered under a result title, used by both
|
|
80
|
+
// the query search results and the version-history rows. The owner is shown as a
|
|
81
|
+
// highlighted "Me" tag when it belongs to the current user.
|
|
82
|
+
const QueryResultDescription = observer(
|
|
83
|
+
(props: {
|
|
84
|
+
lastUpdatedAt: number | undefined;
|
|
85
|
+
owner: string | undefined;
|
|
86
|
+
isCurrentUser: boolean;
|
|
87
|
+
}) => {
|
|
88
|
+
const { lastUpdatedAt, owner, isCurrentUser } = props;
|
|
89
|
+
return (
|
|
90
|
+
<div className="query-loader__result__description">
|
|
91
|
+
<div className="query-loader__result__description__date__icon">
|
|
92
|
+
<LastModifiedIcon />
|
|
93
|
+
</div>
|
|
94
|
+
<div className="query-loader__result__description__date">
|
|
95
|
+
{lastUpdatedAt !== undefined
|
|
96
|
+
? formatDistanceToNow(new Date(lastUpdatedAt), {
|
|
97
|
+
includeSeconds: true,
|
|
98
|
+
addSuffix: true,
|
|
99
|
+
})
|
|
100
|
+
: '(unknown)'}
|
|
101
|
+
</div>
|
|
102
|
+
<div
|
|
103
|
+
className={clsx('query-loader__result__description__author__icon', {
|
|
104
|
+
'query-loader__result__description__author__icon--owner':
|
|
105
|
+
isCurrentUser,
|
|
106
|
+
})}
|
|
107
|
+
>
|
|
108
|
+
<UserIcon />
|
|
109
|
+
</div>
|
|
110
|
+
<div className="query-loader__result__description__author__name">
|
|
111
|
+
{isCurrentUser ? (
|
|
112
|
+
<div
|
|
113
|
+
title={owner}
|
|
114
|
+
className="query-loader__result__description__owner"
|
|
115
|
+
>
|
|
116
|
+
Me
|
|
117
|
+
</div>
|
|
118
|
+
) : (
|
|
119
|
+
(owner ?? '(unknown)')
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Shared read-only code modal (Pure grammar) used by the query preview and the
|
|
128
|
+
// version-history grammar diff — same shell, only the title and body differ.
|
|
129
|
+
const QueryLoaderCodeModal = observer(
|
|
130
|
+
(props: {
|
|
131
|
+
queryLoaderState: QueryLoaderState;
|
|
132
|
+
open: boolean;
|
|
133
|
+
title: string;
|
|
134
|
+
onClose: () => void;
|
|
135
|
+
children: ReactNode;
|
|
136
|
+
}) => {
|
|
137
|
+
const { queryLoaderState, open, title, onClose, children } = props;
|
|
69
138
|
return (
|
|
70
139
|
<Dialog
|
|
71
|
-
open={
|
|
72
|
-
onClose={
|
|
140
|
+
open={open}
|
|
141
|
+
onClose={onClose}
|
|
73
142
|
classes={{
|
|
74
143
|
root: 'editor-modal__root-container',
|
|
75
144
|
container: 'editor-modal__container',
|
|
@@ -79,26 +148,18 @@ const QueryPreviewViewer = observer(
|
|
|
79
148
|
<Modal
|
|
80
149
|
className="editor-modal"
|
|
81
150
|
darkMode={
|
|
82
|
-
!applicationStore.layoutService
|
|
151
|
+
!queryLoaderState.applicationStore.layoutService
|
|
152
|
+
.TEMPORARY__isLightColorThemeEnabled
|
|
83
153
|
}
|
|
84
154
|
>
|
|
85
|
-
<ModalHeader
|
|
86
|
-
|
|
87
|
-
guaranteeNonNullable(queryLoaderState.queryPreviewContent).name
|
|
88
|
-
}
|
|
89
|
-
/>
|
|
90
|
-
<ModalBody>
|
|
91
|
-
<CodeEditor
|
|
92
|
-
inputValue={
|
|
93
|
-
guaranteeNonNullable(queryLoaderState.queryPreviewContent)
|
|
94
|
-
.content
|
|
95
|
-
}
|
|
96
|
-
isReadOnly={true}
|
|
97
|
-
language={CODE_EDITOR_LANGUAGE.PURE}
|
|
98
|
-
/>
|
|
99
|
-
</ModalBody>
|
|
155
|
+
<ModalHeader title={title} />
|
|
156
|
+
<ModalBody>{children}</ModalBody>
|
|
100
157
|
<ModalFooter>
|
|
101
|
-
<ModalFooterButton
|
|
158
|
+
<ModalFooterButton
|
|
159
|
+
onClick={onClose}
|
|
160
|
+
text="Close"
|
|
161
|
+
type="secondary"
|
|
162
|
+
/>
|
|
102
163
|
</ModalFooter>
|
|
103
164
|
</Modal>
|
|
104
165
|
</Dialog>
|
|
@@ -106,6 +167,258 @@ const QueryPreviewViewer = observer(
|
|
|
106
167
|
},
|
|
107
168
|
);
|
|
108
169
|
|
|
170
|
+
const QueryPreviewViewer = observer(
|
|
171
|
+
(props: { queryLoaderState: QueryLoaderState }) => {
|
|
172
|
+
const { queryLoaderState } = props;
|
|
173
|
+
const content = guaranteeNonNullable(queryLoaderState.queryPreviewContent);
|
|
174
|
+
return (
|
|
175
|
+
<QueryLoaderCodeModal
|
|
176
|
+
queryLoaderState={queryLoaderState}
|
|
177
|
+
open={queryLoaderState.showPreviewViewer}
|
|
178
|
+
title={content.name}
|
|
179
|
+
onClose={(): void => queryLoaderState.setShowPreviewViewer(false)}
|
|
180
|
+
>
|
|
181
|
+
<CodeEditor
|
|
182
|
+
inputValue={content.content}
|
|
183
|
+
isReadOnly={true}
|
|
184
|
+
language={CODE_EDITOR_LANGUAGE.PURE}
|
|
185
|
+
/>
|
|
186
|
+
</QueryLoaderCodeModal>
|
|
187
|
+
);
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const QueryHistoryDiffViewer = observer(
|
|
192
|
+
(props: { queryLoaderState: QueryLoaderState }) => {
|
|
193
|
+
const { queryLoaderState } = props;
|
|
194
|
+
const labels = queryLoaderState.historyDiffLabels;
|
|
195
|
+
const grammars = queryLoaderState.historyDiffGrammars;
|
|
196
|
+
return (
|
|
197
|
+
<QueryLoaderCodeModal
|
|
198
|
+
queryLoaderState={queryLoaderState}
|
|
199
|
+
open={queryLoaderState.showHistoryDiff}
|
|
200
|
+
title={labels ? `${labels.from} → ${labels.to}` : 'Grammar Diff'}
|
|
201
|
+
onClose={(): void => queryLoaderState.setShowHistoryDiff(false)}
|
|
202
|
+
>
|
|
203
|
+
<PanelLoadingIndicator
|
|
204
|
+
isLoading={queryLoaderState.queryHistoryDiffState.isInProgress}
|
|
205
|
+
/>
|
|
206
|
+
<div className="query-loader__history__diff">
|
|
207
|
+
<CodeDiffView
|
|
208
|
+
language={CODE_EDITOR_LANGUAGE.PURE}
|
|
209
|
+
from={grammars?.from ?? ''}
|
|
210
|
+
to={grammars?.to ?? ''}
|
|
211
|
+
/>
|
|
212
|
+
</div>
|
|
213
|
+
</QueryLoaderCodeModal>
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const QueryHistoryViewer = observer(
|
|
219
|
+
(props: { queryLoaderState: QueryLoaderState }) => {
|
|
220
|
+
const { queryLoaderState } = props;
|
|
221
|
+
const applicationStore = queryLoaderState.applicationStore;
|
|
222
|
+
const query = queryLoaderState.historyQuery;
|
|
223
|
+
const revisions = queryLoaderState.queryHistoryRevisions;
|
|
224
|
+
const selectedKeys = queryLoaderState.selectedRevisionKeysForDiff;
|
|
225
|
+
|
|
226
|
+
// Selectable snapshots for the grammar diff: the current (latest) version
|
|
227
|
+
// followed by each historical revision, newest first (highest `version`).
|
|
228
|
+
// The latest version's content is not part of the `/history` payload, so it
|
|
229
|
+
// is resolved lazily when comparing.
|
|
230
|
+
const orderedRevisions = [...revisions].sort(
|
|
231
|
+
(a, b) => revisionSortKey(b.version) - revisionSortKey(a.version),
|
|
232
|
+
);
|
|
233
|
+
const diffEntries = [
|
|
234
|
+
{
|
|
235
|
+
key: LATEST_REVISION_KEY,
|
|
236
|
+
label: 'Latest revision',
|
|
237
|
+
isLatest: true,
|
|
238
|
+
content: undefined as string | undefined,
|
|
239
|
+
revisionId: undefined as string | undefined,
|
|
240
|
+
lastUpdatedAt: query?.lastUpdatedAt,
|
|
241
|
+
owner: query?.owner,
|
|
242
|
+
},
|
|
243
|
+
...orderedRevisions.map((revision, idx) => ({
|
|
244
|
+
key: revision.version ?? `revision-${idx}`,
|
|
245
|
+
label: `Revision ${revision.version}`,
|
|
246
|
+
isLatest: false,
|
|
247
|
+
content: revision.content as string | undefined,
|
|
248
|
+
revisionId: revision.version,
|
|
249
|
+
lastUpdatedAt: revision.lastUpdatedAt,
|
|
250
|
+
owner: revision.owner,
|
|
251
|
+
})),
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
const back = (): void => {
|
|
255
|
+
queryLoaderState.setShowHistoryViewer(false);
|
|
256
|
+
queryLoaderState.clearHistoryDiffSelection();
|
|
257
|
+
};
|
|
258
|
+
const openRevision = (revisionId: string | undefined): void => {
|
|
259
|
+
queryLoaderState.setShowHistoryViewer(false);
|
|
260
|
+
queryLoaderState.setQueryLoaderDialogOpen(false);
|
|
261
|
+
queryLoaderState.loadQuery(guaranteeNonNullable(query), revisionId);
|
|
262
|
+
};
|
|
263
|
+
const compareSelected = (): void => {
|
|
264
|
+
// `diffEntries` runs newest → oldest, so ordering the two picks by their
|
|
265
|
+
// position here always diffs the older revision (from) into the newer one
|
|
266
|
+
// (to). This keeps the diff reading forward in time — additions show as
|
|
267
|
+
// additions — regardless of the order the checkboxes were ticked.
|
|
268
|
+
const [newer, older] = diffEntries.filter((entry) =>
|
|
269
|
+
selectedKeys.includes(entry.key),
|
|
270
|
+
);
|
|
271
|
+
if (newer && older) {
|
|
272
|
+
flowResult(
|
|
273
|
+
queryLoaderState.computeHistoryDiff(
|
|
274
|
+
older as QueryRevisionDiffInput,
|
|
275
|
+
newer as QueryRevisionDiffInput,
|
|
276
|
+
),
|
|
277
|
+
).catch(applicationStore.alertUnhandledError);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const confirmRevert = (label: string, revisionId: string): void => {
|
|
281
|
+
applicationStore.alertService.setActionAlertInfo({
|
|
282
|
+
message: `Revert this query to "${label}"? This saves the selected revision as the current version. Your version history is preserved, so you can revert back later.`,
|
|
283
|
+
type: ActionAlertType.CAUTION,
|
|
284
|
+
actions: [
|
|
285
|
+
{
|
|
286
|
+
label: 'Revert',
|
|
287
|
+
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
|
|
288
|
+
handler: applicationStore.guardUnhandledError(() =>
|
|
289
|
+
flowResult(queryLoaderState.revertToRevision(revisionId)),
|
|
290
|
+
),
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
label: 'Cancel',
|
|
294
|
+
type: ActionAlertActionType.PROCEED,
|
|
295
|
+
default: true,
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<>
|
|
303
|
+
<div className="query-loader__header query-loader__header--history">
|
|
304
|
+
{!queryLoaderState.isHistoryViewerStandalone && (
|
|
305
|
+
<button
|
|
306
|
+
className="query-loader__history__back-btn"
|
|
307
|
+
title="Back to results"
|
|
308
|
+
onClick={back}
|
|
309
|
+
>
|
|
310
|
+
<ArrowLeftIcon />
|
|
311
|
+
</button>
|
|
312
|
+
)}
|
|
313
|
+
<div className="query-loader__history__title">
|
|
314
|
+
{`Query History${query ? ` - ${query.name}` : ''}`}
|
|
315
|
+
</div>
|
|
316
|
+
<button
|
|
317
|
+
className="query-loader__history__compare-btn"
|
|
318
|
+
title={
|
|
319
|
+
selectedKeys.length === 2
|
|
320
|
+
? 'Compare the grammar of the two selected revisions'
|
|
321
|
+
: 'Select two revisions to compare their grammar'
|
|
322
|
+
}
|
|
323
|
+
disabled={selectedKeys.length !== 2}
|
|
324
|
+
onClick={compareSelected}
|
|
325
|
+
>
|
|
326
|
+
Compare
|
|
327
|
+
</button>
|
|
328
|
+
</div>
|
|
329
|
+
<div className="query-loader__content">
|
|
330
|
+
<PanelLoadingIndicator
|
|
331
|
+
isLoading={
|
|
332
|
+
queryLoaderState.queryHistoryState.isInProgress ||
|
|
333
|
+
queryLoaderState.queryHistoryDiffState.isInProgress
|
|
334
|
+
}
|
|
335
|
+
/>
|
|
336
|
+
<div className="query-loader__results">
|
|
337
|
+
{/* The `/history` endpoint only returns non-current revisions, so
|
|
338
|
+
the latest (current) version is surfaced explicitly. */}
|
|
339
|
+
{diffEntries.map((entry) => (
|
|
340
|
+
<div
|
|
341
|
+
key={entry.key}
|
|
342
|
+
className="query-loader__result query-loader__result--history"
|
|
343
|
+
>
|
|
344
|
+
<label
|
|
345
|
+
className="query-loader__result__diff-select"
|
|
346
|
+
title="Select this revision for a grammar diff"
|
|
347
|
+
>
|
|
348
|
+
<input
|
|
349
|
+
type="checkbox"
|
|
350
|
+
checked={selectedKeys.includes(entry.key)}
|
|
351
|
+
onChange={(): void =>
|
|
352
|
+
queryLoaderState.toggleRevisionForDiff(entry.key)
|
|
353
|
+
}
|
|
354
|
+
/>
|
|
355
|
+
</label>
|
|
356
|
+
<div
|
|
357
|
+
className="query-loader__result__content"
|
|
358
|
+
title={
|
|
359
|
+
entry.isLatest
|
|
360
|
+
? 'Load the latest revision'
|
|
361
|
+
: 'Load this revision'
|
|
362
|
+
}
|
|
363
|
+
onClick={(): void => openRevision(entry.revisionId)}
|
|
364
|
+
>
|
|
365
|
+
<div className="query-loader__result__title">
|
|
366
|
+
{entry.label}
|
|
367
|
+
</div>
|
|
368
|
+
<QueryResultDescription
|
|
369
|
+
lastUpdatedAt={entry.lastUpdatedAt}
|
|
370
|
+
owner={entry.owner}
|
|
371
|
+
isCurrentUser={
|
|
372
|
+
entry.owner ===
|
|
373
|
+
applicationStore.identityService.currentUser
|
|
374
|
+
}
|
|
375
|
+
/>
|
|
376
|
+
</div>
|
|
377
|
+
{!queryLoaderState.isReadOnly &&
|
|
378
|
+
!entry.isLatest &&
|
|
379
|
+
entry.revisionId !== undefined && (
|
|
380
|
+
<button
|
|
381
|
+
className="query-loader__result__revert-btn"
|
|
382
|
+
title="Revert the query to this revision (saves it as the current version)"
|
|
383
|
+
onClick={(): void =>
|
|
384
|
+
confirmRevert(
|
|
385
|
+
entry.label,
|
|
386
|
+
guaranteeNonNullable(entry.revisionId),
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
>
|
|
390
|
+
Revert
|
|
391
|
+
</button>
|
|
392
|
+
)}
|
|
393
|
+
<div
|
|
394
|
+
className="query-loader__result__arrow"
|
|
395
|
+
title={
|
|
396
|
+
entry.isLatest
|
|
397
|
+
? 'Load the latest revision'
|
|
398
|
+
: 'Load this revision'
|
|
399
|
+
}
|
|
400
|
+
onClick={(): void => openRevision(entry.revisionId)}
|
|
401
|
+
>
|
|
402
|
+
<ThinChevronRightIcon />
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
))}
|
|
406
|
+
</div>
|
|
407
|
+
{queryLoaderState.queryHistoryState.hasCompleted &&
|
|
408
|
+
revisions.length === 0 && (
|
|
409
|
+
<BlankPanelContent>
|
|
410
|
+
No earlier revisions available
|
|
411
|
+
</BlankPanelContent>
|
|
412
|
+
)}
|
|
413
|
+
</div>
|
|
414
|
+
{queryLoaderState.showHistoryDiff && (
|
|
415
|
+
<QueryHistoryDiffViewer queryLoaderState={queryLoaderState} />
|
|
416
|
+
)}
|
|
417
|
+
</>
|
|
418
|
+
);
|
|
419
|
+
},
|
|
420
|
+
);
|
|
421
|
+
|
|
109
422
|
export const QueryLoader = observer(
|
|
110
423
|
(props: { queryLoaderState: QueryLoaderState; loadActionLabel: string }) => {
|
|
111
424
|
const { queryLoaderState, loadActionLabel } = props;
|
|
@@ -268,386 +581,387 @@ export const QueryLoader = observer(
|
|
|
268
581
|
).catch(applicationStore.alertUnhandledError);
|
|
269
582
|
queryLoaderState.setShowPreviewViewer(true);
|
|
270
583
|
};
|
|
584
|
+
const showHistory = (query: LightQuery): void => {
|
|
585
|
+
flowResult(queryLoaderState.getQueryHistory(query)).catch(
|
|
586
|
+
applicationStore.alertUnhandledError,
|
|
587
|
+
);
|
|
588
|
+
};
|
|
271
589
|
|
|
272
590
|
return (
|
|
273
591
|
<div className="query-loader">
|
|
274
|
-
|
|
275
|
-
<
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
title="Clear"
|
|
298
|
-
>
|
|
299
|
-
<TimesIcon />
|
|
300
|
-
</button>
|
|
301
|
-
</>
|
|
302
|
-
)}
|
|
303
|
-
</div>
|
|
304
|
-
</div>
|
|
305
|
-
<div className="query-loader__filter">
|
|
306
|
-
<div className="query-loader__filter__toggler">
|
|
307
|
-
<button
|
|
308
|
-
className={clsx('query-loader__filter__toggler__btn', {
|
|
309
|
-
'query-loader__filter__toggler__btn--toggled': isMineOnly,
|
|
310
|
-
})}
|
|
311
|
-
onClick={toggleShowCurrentUserQueriesOnly}
|
|
312
|
-
disabled={queryLoaderState.isCuratedTemplateToggled}
|
|
313
|
-
title={
|
|
314
|
-
queryLoaderState.isCuratedTemplateToggled
|
|
315
|
-
? 'current fitler is disabled when `Curated Template Query` is on'
|
|
316
|
-
: 'click to add filter'
|
|
317
|
-
}
|
|
318
|
-
tabIndex={-1}
|
|
319
|
-
>
|
|
320
|
-
Mine Only
|
|
321
|
-
</button>
|
|
322
|
-
{queryLoaderState.extraFilterOptions.length > 0 && (
|
|
323
|
-
<div className="query-loader__filter__extra__filters">
|
|
324
|
-
{Array.from(queryLoaderState.extraFilters.entries()).map(
|
|
325
|
-
([key, value]) => (
|
|
592
|
+
{queryLoaderState.showHistoryViewer ? (
|
|
593
|
+
<QueryHistoryViewer queryLoaderState={queryLoaderState} />
|
|
594
|
+
) : (
|
|
595
|
+
<>
|
|
596
|
+
<div className="query-loader__header">
|
|
597
|
+
<div className="query-loader__search">
|
|
598
|
+
<div className="query-loader__search__input__container">
|
|
599
|
+
<input
|
|
600
|
+
ref={searchInputRef}
|
|
601
|
+
className={clsx('query-loader__search__input input--dark', {
|
|
602
|
+
'query-loader__search__input--searching':
|
|
603
|
+
queryLoaderState.searchText,
|
|
604
|
+
})}
|
|
605
|
+
onChange={onSearchTextChange}
|
|
606
|
+
value={queryLoaderState.searchText}
|
|
607
|
+
placeholder="Search for queries by name or ID"
|
|
608
|
+
/>
|
|
609
|
+
{!queryLoaderState.searchText ? (
|
|
610
|
+
<div className="query-loader__search__input__search__icon">
|
|
611
|
+
<SearchIcon />
|
|
612
|
+
</div>
|
|
613
|
+
) : (
|
|
614
|
+
<>
|
|
326
615
|
<button
|
|
327
|
-
|
|
328
|
-
className={clsx('query-loader__filter__toggler__btn', {
|
|
329
|
-
'query-loader__filter__toggler__btn--toggled': value,
|
|
330
|
-
})}
|
|
331
|
-
disabled={queryLoaderState.isCuratedTemplateToggled}
|
|
332
|
-
title={
|
|
333
|
-
queryLoaderState.isCuratedTemplateToggled
|
|
334
|
-
? 'current fitler is disabled when `Curated Template Query` is on'
|
|
335
|
-
: 'click to add filter'
|
|
336
|
-
}
|
|
337
|
-
onClick={(): void => toggleExtraFilters(key)}
|
|
616
|
+
className="query-loader__search__input__clear-btn"
|
|
338
617
|
tabIndex={-1}
|
|
618
|
+
onClick={clearSearchResults}
|
|
619
|
+
title="Clear"
|
|
339
620
|
>
|
|
340
|
-
|
|
621
|
+
<TimesIcon />
|
|
341
622
|
</button>
|
|
342
|
-
|
|
623
|
+
</>
|
|
343
624
|
)}
|
|
344
625
|
</div>
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
<div className="query-loader__filter__extra__filters">
|
|
626
|
+
</div>
|
|
627
|
+
<div className="query-loader__filter">
|
|
628
|
+
<div className="query-loader__filter__toggler">
|
|
349
629
|
<button
|
|
350
630
|
className={clsx('query-loader__filter__toggler__btn', {
|
|
351
|
-
'query-loader__filter__toggler__btn--toggled':
|
|
352
|
-
queryLoaderState.isCuratedTemplateToggled,
|
|
631
|
+
'query-loader__filter__toggler__btn--toggled': isMineOnly,
|
|
353
632
|
})}
|
|
354
|
-
onClick={
|
|
633
|
+
onClick={toggleShowCurrentUserQueriesOnly}
|
|
634
|
+
disabled={queryLoaderState.isCuratedTemplateToggled}
|
|
635
|
+
title={
|
|
636
|
+
queryLoaderState.isCuratedTemplateToggled
|
|
637
|
+
? 'current fitler is disabled when `Curated Template Query` is on'
|
|
638
|
+
: 'click to add filter'
|
|
639
|
+
}
|
|
355
640
|
tabIndex={-1}
|
|
356
641
|
>
|
|
357
|
-
|
|
642
|
+
Mine Only
|
|
358
643
|
</button>
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<InfoCircleIcon
|
|
387
|
-
title="Some queries are not listed, refine your search to get better matches"
|
|
388
|
-
className="query-loader__results__summary__info"
|
|
389
|
-
/>
|
|
390
|
-
</>
|
|
391
|
-
) : (
|
|
392
|
-
`Found ${quantifyList(searchResults, 'match', 'matches')}`
|
|
393
|
-
)
|
|
394
|
-
) : curatedTemplateQueries.length >=
|
|
395
|
-
QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT ? (
|
|
396
|
-
<>
|
|
397
|
-
{`Found ${QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT}+ matches`}{' '}
|
|
398
|
-
<InfoCircleIcon
|
|
399
|
-
title="Some queries are not listed, refine your search to get better matches"
|
|
400
|
-
className="query-loader__results__summary__info"
|
|
401
|
-
/>
|
|
402
|
-
</>
|
|
403
|
-
) : (
|
|
404
|
-
`Found ${quantifyList(
|
|
405
|
-
curatedTemplateQueries,
|
|
406
|
-
'match',
|
|
407
|
-
'matches',
|
|
408
|
-
)}`
|
|
644
|
+
{queryLoaderState.extraFilterOptions.length > 0 && (
|
|
645
|
+
<div className="query-loader__filter__extra__filters">
|
|
646
|
+
{Array.from(queryLoaderState.extraFilters.entries()).map(
|
|
647
|
+
([key, value]) => (
|
|
648
|
+
<button
|
|
649
|
+
key={key}
|
|
650
|
+
className={clsx(
|
|
651
|
+
'query-loader__filter__toggler__btn',
|
|
652
|
+
{
|
|
653
|
+
'query-loader__filter__toggler__btn--toggled':
|
|
654
|
+
value,
|
|
655
|
+
},
|
|
656
|
+
)}
|
|
657
|
+
disabled={queryLoaderState.isCuratedTemplateToggled}
|
|
658
|
+
title={
|
|
659
|
+
queryLoaderState.isCuratedTemplateToggled
|
|
660
|
+
? 'current fitler is disabled when `Curated Template Query` is on'
|
|
661
|
+
: 'click to add filter'
|
|
662
|
+
}
|
|
663
|
+
onClick={(): void => toggleExtraFilters(key)}
|
|
664
|
+
tabIndex={-1}
|
|
665
|
+
>
|
|
666
|
+
{key}
|
|
667
|
+
</button>
|
|
668
|
+
),
|
|
669
|
+
)}
|
|
670
|
+
</div>
|
|
409
671
|
)}
|
|
410
|
-
{queryLoaderState
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
<
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
onChange={(option: SortByOption) => {
|
|
422
|
-
applySort(option);
|
|
423
|
-
}}
|
|
424
|
-
value={{
|
|
425
|
-
label: queryLoaderState.sortBy,
|
|
426
|
-
value: queryLoaderState.sortBy,
|
|
427
|
-
}}
|
|
428
|
-
darkMode={
|
|
429
|
-
!applicationStore.layoutService
|
|
430
|
-
.TEMPORARY__isLightColorThemeEnabled
|
|
431
|
-
}
|
|
432
|
-
/>
|
|
433
|
-
</div>
|
|
434
|
-
)}
|
|
435
|
-
</div>
|
|
436
|
-
{!queryLoaderState.isCuratedTemplateToggled &&
|
|
437
|
-
searchResults
|
|
438
|
-
.slice(0, QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT)
|
|
439
|
-
.map((query, idx) => (
|
|
440
|
-
<div
|
|
441
|
-
className="query-loader__result"
|
|
442
|
-
title={`Click to ${loadActionLabel}...`}
|
|
443
|
-
key={query.id}
|
|
444
|
-
onClick={() => queryLoaderState.loadQuery(query)}
|
|
672
|
+
{queryLoaderState
|
|
673
|
+
.extraQueryFilterOptionsRelatedToTemplateQuery.length >
|
|
674
|
+
0 && (
|
|
675
|
+
<div className="query-loader__filter__extra__filters">
|
|
676
|
+
<button
|
|
677
|
+
className={clsx('query-loader__filter__toggler__btn', {
|
|
678
|
+
'query-loader__filter__toggler__btn--toggled':
|
|
679
|
+
queryLoaderState.isCuratedTemplateToggled,
|
|
680
|
+
})}
|
|
681
|
+
onClick={toggleCuratedTemplate}
|
|
682
|
+
tabIndex={-1}
|
|
445
683
|
>
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
684
|
+
Curated Template Query
|
|
685
|
+
</button>
|
|
686
|
+
</div>
|
|
687
|
+
)}
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
</div>
|
|
691
|
+
<div className="query-loader__content">
|
|
692
|
+
<PanelLoadingIndicator
|
|
693
|
+
isLoading={
|
|
694
|
+
queryLoaderState.searchQueriesState.isInProgress ||
|
|
695
|
+
queryLoaderState.renameQueryState.isInProgress ||
|
|
696
|
+
queryLoaderState.deleteQueryState.isInProgress ||
|
|
697
|
+
queryLoaderState.previewQueryState.isInProgress
|
|
698
|
+
}
|
|
699
|
+
/>
|
|
700
|
+
<div className="query-loader__results">
|
|
701
|
+
{queryLoaderState.searchQueriesState.hasCompleted && (
|
|
702
|
+
<>
|
|
703
|
+
<div className="query-loader__results__summary">
|
|
704
|
+
{queryLoaderState.showingDefaultQueries ? (
|
|
705
|
+
(queryLoaderState.generateDefaultQueriesSummaryText?.(
|
|
706
|
+
searchResults,
|
|
707
|
+
) ?? 'Refine your search to get better matches')
|
|
708
|
+
) : !queryLoaderState.isCuratedTemplateToggled ? (
|
|
709
|
+
searchResults.length >=
|
|
710
|
+
QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT ? (
|
|
711
|
+
<>
|
|
712
|
+
{`Found ${QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT}+ matches`}{' '}
|
|
713
|
+
<InfoCircleIcon
|
|
714
|
+
title="Some queries are not listed, refine your search to get better matches"
|
|
715
|
+
className="query-loader__results__summary__info"
|
|
716
|
+
/>
|
|
717
|
+
</>
|
|
718
|
+
) : (
|
|
719
|
+
`Found ${quantifyList(searchResults, 'match', 'matches')}`
|
|
720
|
+
)
|
|
721
|
+
) : curatedTemplateQueries.length >=
|
|
722
|
+
QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT ? (
|
|
723
|
+
<>
|
|
724
|
+
{`Found ${QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT}+ matches`}{' '}
|
|
725
|
+
<InfoCircleIcon
|
|
726
|
+
title="Some queries are not listed, refine your search to get better matches"
|
|
727
|
+
className="query-loader__results__summary__info"
|
|
728
|
+
/>
|
|
729
|
+
</>
|
|
730
|
+
) : (
|
|
731
|
+
`Found ${quantifyList(
|
|
732
|
+
curatedTemplateQueries,
|
|
733
|
+
'match',
|
|
734
|
+
'matches',
|
|
735
|
+
)}`
|
|
736
|
+
)}
|
|
737
|
+
{queryLoaderState.canPerformAdvancedSearch(
|
|
738
|
+
queryLoaderState.searchText,
|
|
739
|
+
) &&
|
|
740
|
+
!queryLoaderState.isCuratedTemplateToggled && (
|
|
741
|
+
<div className="query-loader__results__sort-by">
|
|
742
|
+
<div className="query-loader__results__sort-by__name">
|
|
743
|
+
Sort By
|
|
491
744
|
</div>
|
|
745
|
+
<CustomSelectorInput
|
|
746
|
+
className="query-loader__results__sort-by__selector"
|
|
747
|
+
options={sortOptions}
|
|
748
|
+
onChange={(option: SortByOption) => {
|
|
749
|
+
applySort(option);
|
|
750
|
+
}}
|
|
751
|
+
value={{
|
|
752
|
+
label: queryLoaderState.sortBy,
|
|
753
|
+
value: queryLoaderState.sortBy,
|
|
754
|
+
}}
|
|
755
|
+
darkMode={
|
|
756
|
+
!applicationStore.layoutService
|
|
757
|
+
.TEMPORARY__isLightColorThemeEnabled
|
|
758
|
+
}
|
|
759
|
+
/>
|
|
760
|
+
</div>
|
|
761
|
+
)}
|
|
762
|
+
</div>
|
|
763
|
+
{!queryLoaderState.isCuratedTemplateToggled &&
|
|
764
|
+
searchResults
|
|
765
|
+
.slice(0, QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT)
|
|
766
|
+
.map((query, idx) => (
|
|
767
|
+
<div className="query-loader__result" key={query.id}>
|
|
492
768
|
<div
|
|
493
|
-
className=
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
'query-loader__result__description__author__icon--owner':
|
|
497
|
-
query.isCurrentUserQuery,
|
|
498
|
-
},
|
|
499
|
-
)}
|
|
769
|
+
className="query-loader__result__content"
|
|
770
|
+
title={`Click to ${loadActionLabel}...`}
|
|
771
|
+
onClick={() => queryLoaderState.loadQuery(query)}
|
|
500
772
|
>
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
773
|
+
{showQueryNameEditInput === idx ? (
|
|
774
|
+
<div className="query-loader__result__title__editor">
|
|
775
|
+
<input
|
|
776
|
+
className="query-loader__result__title__editor__input input--dark"
|
|
777
|
+
spellCheck={false}
|
|
778
|
+
ref={queryRenameInputRef}
|
|
779
|
+
value={queryNameInputValue}
|
|
780
|
+
onChange={changeQueryNameInputValue}
|
|
781
|
+
onKeyDown={(event) => {
|
|
782
|
+
if (event.code === 'Enter') {
|
|
783
|
+
event.stopPropagation();
|
|
784
|
+
renameQuery(query)();
|
|
785
|
+
} else if (event.code === 'Escape') {
|
|
786
|
+
event.stopPropagation();
|
|
787
|
+
hideEditQueryNameInput();
|
|
788
|
+
}
|
|
789
|
+
}}
|
|
790
|
+
onBlur={() => hideEditQueryNameInput()}
|
|
791
|
+
// avoid clicking on the input causing the call to load query
|
|
792
|
+
onClick={(event) => event.stopPropagation()}
|
|
793
|
+
/>
|
|
794
|
+
</div>
|
|
795
|
+
) : (
|
|
505
796
|
<div
|
|
506
|
-
|
|
507
|
-
|
|
797
|
+
className="query-loader__result__title"
|
|
798
|
+
title={query.name}
|
|
508
799
|
>
|
|
509
|
-
|
|
800
|
+
{query.name}
|
|
510
801
|
</div>
|
|
511
|
-
) : (
|
|
512
|
-
query.owner
|
|
513
802
|
)}
|
|
803
|
+
<QueryResultDescription
|
|
804
|
+
lastUpdatedAt={query.lastUpdatedAt}
|
|
805
|
+
owner={query.owner}
|
|
806
|
+
isCurrentUser={query.isCurrentUserQuery}
|
|
807
|
+
/>
|
|
808
|
+
</div>
|
|
809
|
+
<ControlledDropdownMenu
|
|
810
|
+
className="query-loader__result__actions-menu"
|
|
811
|
+
title="More Actions..."
|
|
812
|
+
content={
|
|
813
|
+
<MenuContent>
|
|
814
|
+
<MenuContentItem
|
|
815
|
+
onClick={(): void => showPreview(query.id)}
|
|
816
|
+
>
|
|
817
|
+
Show Query Preview
|
|
818
|
+
</MenuContentItem>
|
|
819
|
+
<MenuContentItem
|
|
820
|
+
onClick={(): void => showHistory(query)}
|
|
821
|
+
>
|
|
822
|
+
Show Query History
|
|
823
|
+
</MenuContentItem>
|
|
824
|
+
{!queryLoaderState.isReadOnly && (
|
|
825
|
+
<MenuContentItem
|
|
826
|
+
disabled={!query.isCurrentUserQuery}
|
|
827
|
+
onClick={deleteQuery(query)}
|
|
828
|
+
>
|
|
829
|
+
Delete
|
|
830
|
+
</MenuContentItem>
|
|
831
|
+
)}
|
|
832
|
+
{!queryLoaderState.isReadOnly && (
|
|
833
|
+
<MenuContentItem
|
|
834
|
+
disabled={!query.isCurrentUserQuery}
|
|
835
|
+
onClick={showEditQueryNameInput(
|
|
836
|
+
query.name,
|
|
837
|
+
idx,
|
|
838
|
+
)}
|
|
839
|
+
>
|
|
840
|
+
Rename
|
|
841
|
+
</MenuContentItem>
|
|
842
|
+
)}
|
|
843
|
+
</MenuContent>
|
|
844
|
+
}
|
|
845
|
+
menuProps={{
|
|
846
|
+
anchorOrigin: {
|
|
847
|
+
vertical: 'bottom',
|
|
848
|
+
horizontal: 'left',
|
|
849
|
+
},
|
|
850
|
+
transformOrigin: {
|
|
851
|
+
vertical: 'top',
|
|
852
|
+
horizontal: 'left',
|
|
853
|
+
},
|
|
854
|
+
elevation: 7,
|
|
855
|
+
}}
|
|
856
|
+
>
|
|
857
|
+
<MoreVerticalIcon />
|
|
858
|
+
</ControlledDropdownMenu>
|
|
859
|
+
<div
|
|
860
|
+
className="query-loader__result__arrow"
|
|
861
|
+
title={`Click to ${loadActionLabel}...`}
|
|
862
|
+
onClick={() => queryLoaderState.loadQuery(query)}
|
|
863
|
+
>
|
|
864
|
+
<ThinChevronRightIcon />
|
|
514
865
|
</div>
|
|
515
866
|
</div>
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
867
|
+
))}
|
|
868
|
+
{queryLoaderState.queryBuilderState &&
|
|
869
|
+
queryLoaderState.isCuratedTemplateToggled &&
|
|
870
|
+
loadCuratedTemplateQuery &&
|
|
871
|
+
curatedTemplateQueries
|
|
872
|
+
.slice(0, QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT)
|
|
873
|
+
.map((templateQuery) => {
|
|
874
|
+
const loadTemplateQuery = (): void => {
|
|
875
|
+
flowResult(
|
|
876
|
+
loadCuratedTemplateQuery()(
|
|
877
|
+
templateQuery,
|
|
878
|
+
guaranteeNonNullable(
|
|
879
|
+
queryLoaderState.queryBuilderState,
|
|
880
|
+
),
|
|
881
|
+
),
|
|
882
|
+
);
|
|
883
|
+
queryLoaderState.setQueryLoaderDialogOpen(false);
|
|
884
|
+
};
|
|
885
|
+
return (
|
|
886
|
+
<div
|
|
887
|
+
className="query-loader__result"
|
|
888
|
+
key={templateQuery.title}
|
|
889
|
+
>
|
|
890
|
+
<div
|
|
891
|
+
className="query-loader__result__content"
|
|
892
|
+
title={`Click to ${loadActionLabel}...`}
|
|
893
|
+
onClick={loadTemplateQuery}
|
|
524
894
|
>
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
<MenuContentItem
|
|
529
|
-
disabled={!query.isCurrentUserQuery}
|
|
530
|
-
onClick={deleteQuery(query)}
|
|
531
|
-
>
|
|
532
|
-
Delete
|
|
533
|
-
</MenuContentItem>
|
|
534
|
-
)}
|
|
535
|
-
{!queryLoaderState.isReadOnly && (
|
|
536
|
-
<MenuContentItem
|
|
537
|
-
disabled={!query.isCurrentUserQuery}
|
|
538
|
-
onClick={showEditQueryNameInput(
|
|
539
|
-
query.name,
|
|
540
|
-
idx,
|
|
541
|
-
)}
|
|
895
|
+
<div
|
|
896
|
+
className="query-loader__result__title"
|
|
897
|
+
title={templateQuery.title}
|
|
542
898
|
>
|
|
543
|
-
|
|
544
|
-
</
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
</div>
|
|
566
|
-
))}
|
|
567
|
-
{queryLoaderState.queryBuilderState &&
|
|
568
|
-
queryLoaderState.isCuratedTemplateToggled &&
|
|
569
|
-
loadCuratedTemplateQuery &&
|
|
570
|
-
curatedTemplateQueries
|
|
571
|
-
.slice(0, QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT)
|
|
572
|
-
.map((templateQuery, idx) => (
|
|
573
|
-
<div
|
|
574
|
-
className="query-loader__result"
|
|
575
|
-
title={`Click to ${loadActionLabel}...`}
|
|
576
|
-
key={templateQuery.title}
|
|
577
|
-
onClick={() => {
|
|
578
|
-
flowResult(
|
|
579
|
-
loadCuratedTemplateQuery()(
|
|
580
|
-
templateQuery,
|
|
581
|
-
guaranteeNonNullable(
|
|
582
|
-
queryLoaderState.queryBuilderState,
|
|
583
|
-
),
|
|
584
|
-
),
|
|
585
|
-
);
|
|
586
|
-
queryLoaderState.setQueryLoaderDialogOpen(false);
|
|
587
|
-
}}
|
|
588
|
-
>
|
|
589
|
-
<div className="query-loader__result__content">
|
|
590
|
-
<div
|
|
591
|
-
className="query-loader__result__title"
|
|
592
|
-
title={templateQuery.title}
|
|
593
|
-
>
|
|
594
|
-
{templateQuery.title}
|
|
595
|
-
</div>
|
|
596
|
-
<div className="query-loader__result__description">
|
|
597
|
-
{templateQuery.description}
|
|
598
|
-
</div>
|
|
599
|
-
</div>
|
|
600
|
-
<ControlledDropdownMenu
|
|
601
|
-
className="query-loader__result__actions-menu"
|
|
602
|
-
title="More Actions..."
|
|
603
|
-
content={
|
|
604
|
-
<MenuContent>
|
|
605
|
-
<MenuContentItem
|
|
606
|
-
onClick={(): void =>
|
|
607
|
-
showPreview(undefined, {
|
|
608
|
-
queryContent: templateQuery.query,
|
|
609
|
-
queryName: templateQuery.title,
|
|
610
|
-
})
|
|
899
|
+
{templateQuery.title}
|
|
900
|
+
</div>
|
|
901
|
+
<div className="query-loader__result__description">
|
|
902
|
+
{templateQuery.description}
|
|
903
|
+
</div>
|
|
904
|
+
</div>
|
|
905
|
+
<ControlledDropdownMenu
|
|
906
|
+
className="query-loader__result__actions-menu"
|
|
907
|
+
title="More Actions..."
|
|
908
|
+
content={
|
|
909
|
+
<MenuContent>
|
|
910
|
+
<MenuContentItem
|
|
911
|
+
onClick={(): void =>
|
|
912
|
+
showPreview(undefined, {
|
|
913
|
+
queryContent: templateQuery.query,
|
|
914
|
+
queryName: templateQuery.title,
|
|
915
|
+
})
|
|
916
|
+
}
|
|
917
|
+
>
|
|
918
|
+
Show Query Preview
|
|
919
|
+
</MenuContentItem>
|
|
920
|
+
</MenuContent>
|
|
611
921
|
}
|
|
922
|
+
menuProps={{
|
|
923
|
+
anchorOrigin: {
|
|
924
|
+
vertical: 'bottom',
|
|
925
|
+
horizontal: 'left',
|
|
926
|
+
},
|
|
927
|
+
transformOrigin: {
|
|
928
|
+
vertical: 'top',
|
|
929
|
+
horizontal: 'left',
|
|
930
|
+
},
|
|
931
|
+
elevation: 7,
|
|
932
|
+
}}
|
|
612
933
|
>
|
|
613
|
-
|
|
614
|
-
</
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
)}
|
|
645
|
-
</div>
|
|
646
|
-
{queryLoaderState.showPreviewViewer &&
|
|
647
|
-
queryLoaderState.queryPreviewContent && (
|
|
648
|
-
<QueryPreviewViewer queryLoaderState={queryLoaderState} />
|
|
649
|
-
)}
|
|
650
|
-
</div>
|
|
934
|
+
<MoreVerticalIcon />
|
|
935
|
+
</ControlledDropdownMenu>
|
|
936
|
+
<div
|
|
937
|
+
className="query-loader__result__arrow"
|
|
938
|
+
title={`Click to ${loadActionLabel}...`}
|
|
939
|
+
onClick={loadTemplateQuery}
|
|
940
|
+
>
|
|
941
|
+
<ThinChevronRightIcon />
|
|
942
|
+
</div>
|
|
943
|
+
</div>
|
|
944
|
+
);
|
|
945
|
+
})}
|
|
946
|
+
</>
|
|
947
|
+
)}
|
|
948
|
+
{!queryLoaderState.searchQueriesState.hasCompleted && (
|
|
949
|
+
<CubesLoadingIndicator
|
|
950
|
+
isLoading={
|
|
951
|
+
!queryLoaderState.searchQueriesState.hasCompleted
|
|
952
|
+
}
|
|
953
|
+
>
|
|
954
|
+
<CubesLoadingIndicatorIcon />
|
|
955
|
+
</CubesLoadingIndicator>
|
|
956
|
+
)}
|
|
957
|
+
</div>
|
|
958
|
+
</div>
|
|
959
|
+
</>
|
|
960
|
+
)}
|
|
961
|
+
{queryLoaderState.showPreviewViewer &&
|
|
962
|
+
queryLoaderState.queryPreviewContent && (
|
|
963
|
+
<QueryPreviewViewer queryLoaderState={queryLoaderState} />
|
|
964
|
+
)}
|
|
651
965
|
</div>
|
|
652
966
|
);
|
|
653
967
|
},
|
|
@@ -663,6 +977,13 @@ export const QueryLoaderDialog = observer(
|
|
|
663
977
|
const applicationStore = queryLoaderState.applicationStore;
|
|
664
978
|
|
|
665
979
|
const close = (): void => {
|
|
980
|
+
// while the grammar-diff dialog is open, a dismiss (Close/Escape/backdrop)
|
|
981
|
+
// that reaches this parent should only close the diff and return to the
|
|
982
|
+
// history list — not tear down the whole loader
|
|
983
|
+
if (queryLoaderState.showHistoryDiff) {
|
|
984
|
+
queryLoaderState.setShowHistoryDiff(false);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
666
987
|
queryLoaderState.setQueryLoaderDialogOpen(false);
|
|
667
988
|
queryLoaderState.reset();
|
|
668
989
|
};
|
|
@@ -677,7 +998,9 @@ export const QueryLoaderDialog = observer(
|
|
|
677
998
|
}}
|
|
678
999
|
slotProps={{
|
|
679
1000
|
paper: {
|
|
680
|
-
classes: {
|
|
1001
|
+
classes: {
|
|
1002
|
+
root: 'query-loader__dialog__body',
|
|
1003
|
+
},
|
|
681
1004
|
},
|
|
682
1005
|
}}
|
|
683
1006
|
>
|
|
@@ -690,7 +1013,11 @@ export const QueryLoaderDialog = observer(
|
|
|
690
1013
|
<div className="modal query-loader__dialog__header">
|
|
691
1014
|
<ModalTitle
|
|
692
1015
|
className="query-loader__dialog__header__title"
|
|
693
|
-
title={
|
|
1016
|
+
title={
|
|
1017
|
+
queryLoaderState.isHistoryViewerStandalone
|
|
1018
|
+
? 'Query History'
|
|
1019
|
+
: title
|
|
1020
|
+
}
|
|
694
1021
|
/>
|
|
695
1022
|
<button
|
|
696
1023
|
className="query-loader__dialog__header__close-btn"
|