@xh/hoist 73.0.0-SNAPSHOT.1738098086901 → 73.0.0-SNAPSHOT.1738169109530
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/admin/jsonsearch/JsonSearchPanel.ts +121 -64
- package/admin/jsonsearch/impl/JsonSearchPanelImplModel.ts +22 -20
- package/admin/tabs/general/config/ConfigPanel.ts +30 -4
- package/admin/tabs/userData/jsonblob/JsonBlobPanel.ts +36 -37
- package/admin/tabs/userData/prefs/UserPreferencePanel.ts +28 -26
- package/build/types/admin/jsonsearch/JsonSearchPanel.d.ts +5 -5
- package/build/types/admin/jsonsearch/impl/JsonSearchPanelImplModel.d.ts +7 -6
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -9,85 +9,124 @@ import {startCase} from 'lodash';
|
|
|
9
9
|
import {toolbar, toolbarSep} from '@xh/hoist/desktop/cmp/toolbar';
|
|
10
10
|
import {errorMessage} from '@xh/hoist/cmp/error';
|
|
11
11
|
import {grid, GridConfig, gridCountLabel} from '@xh/hoist/cmp/grid';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
a,
|
|
14
|
+
box,
|
|
15
|
+
filler,
|
|
16
|
+
fragment,
|
|
17
|
+
h4,
|
|
18
|
+
hframe,
|
|
19
|
+
label,
|
|
20
|
+
li,
|
|
21
|
+
span,
|
|
22
|
+
ul,
|
|
23
|
+
vbox
|
|
24
|
+
} from '@xh/hoist/cmp/layout';
|
|
13
25
|
import {hoistCmp, HoistProps, SelectOption, useLocalModel} from '@xh/hoist/core';
|
|
14
26
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
15
27
|
import {buttonGroupInput, jsonInput, select, textInput} from '@xh/hoist/desktop/cmp/input';
|
|
16
28
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
17
29
|
import {Icon} from '@xh/hoist/icon';
|
|
18
|
-
import {popover} from '@xh/hoist/kit/blueprint';
|
|
30
|
+
import {dialog, popover} from '@xh/hoist/kit/blueprint';
|
|
19
31
|
import {clipboardButton} from '@xh/hoist/desktop/cmp/clipboard';
|
|
20
32
|
import {JsonSearchPanelImplModel} from './impl/JsonSearchPanelImplModel';
|
|
21
33
|
|
|
22
|
-
export interface
|
|
34
|
+
export interface JsonSearchButtonProps extends HoistProps {
|
|
35
|
+
/** Name of the type of Json Documents being searched. This appears in the dialog title. */
|
|
36
|
+
subjectName: string;
|
|
37
|
+
|
|
23
38
|
/** Url to endpoint for searching for matching JSON documents */
|
|
24
39
|
docSearchUrl: string;
|
|
25
40
|
|
|
26
|
-
/** Url to endpoint for listing matching JSON nodes */
|
|
27
|
-
matchingNodesUrl: string;
|
|
28
|
-
|
|
29
41
|
/**
|
|
30
42
|
* Config for GridModel used to display search results.
|
|
31
43
|
*/
|
|
32
44
|
gridModelConfig: GridConfig;
|
|
33
45
|
|
|
34
46
|
/**
|
|
35
|
-
* Names of
|
|
47
|
+
* Names of fields that can be used to group by.
|
|
36
48
|
*/
|
|
37
49
|
groupByOptions: Array<SelectOption | any>;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
export const [
|
|
52
|
+
export const [JsonSearchButton, jsonSearchButton] = hoistCmp.withFactory<JsonSearchButtonProps>({
|
|
41
53
|
displayName: 'JsonSearchPanel',
|
|
42
54
|
|
|
43
55
|
render() {
|
|
44
|
-
const impl = useLocalModel(JsonSearchPanelImplModel)
|
|
45
|
-
{error} = impl;
|
|
56
|
+
const impl = useLocalModel(JsonSearchPanelImplModel);
|
|
46
57
|
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
return fragment(
|
|
59
|
+
button({
|
|
60
|
+
icon: Icon.json(),
|
|
61
|
+
text: 'JSON Search',
|
|
62
|
+
onClick: () => impl.toggleSearchIsOpen()
|
|
63
|
+
}),
|
|
64
|
+
jsonSearchDialog({
|
|
65
|
+
omit: !impl.isOpen,
|
|
66
|
+
model: impl
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const jsonSearchDialog = hoistCmp.factory<JsonSearchPanelImplModel>({
|
|
73
|
+
displayName: 'JsonSearchPanel',
|
|
74
|
+
|
|
75
|
+
render({model}) {
|
|
76
|
+
const {error, subjectName} = model;
|
|
77
|
+
|
|
78
|
+
return dialog({
|
|
79
|
+
title: `${subjectName} Json Search`,
|
|
80
|
+
style: {
|
|
81
|
+
width: '90vw',
|
|
82
|
+
height: '90vh'
|
|
55
83
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
84
|
+
icon: Icon.json(),
|
|
85
|
+
isOpen: true,
|
|
86
|
+
className: 'xh-admin-diff-detail',
|
|
87
|
+
onClose: () => model.toggleSearchIsOpen(),
|
|
59
88
|
item: panel({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
tbar: searchTbar(),
|
|
90
|
+
item: panel({
|
|
91
|
+
mask: model.docLoadTask,
|
|
92
|
+
items: [
|
|
93
|
+
errorMessage({
|
|
94
|
+
error,
|
|
95
|
+
title: error?.name ? startCase(error.name) : undefined
|
|
96
|
+
}),
|
|
97
|
+
hframe({
|
|
98
|
+
omit: error,
|
|
99
|
+
items: [
|
|
100
|
+
panel({
|
|
101
|
+
item: grid({model: model.gridModel}),
|
|
102
|
+
modelConfig: {
|
|
103
|
+
side: 'left',
|
|
104
|
+
defaultSize: '30%',
|
|
105
|
+
collapsible: true,
|
|
106
|
+
defaultCollapsed: false,
|
|
107
|
+
resizable: true
|
|
108
|
+
}
|
|
78
109
|
}),
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
110
|
+
panel({
|
|
111
|
+
mask: model.nodeLoadTask,
|
|
112
|
+
tbar: readerTbar(),
|
|
113
|
+
bbar: nodeBbar({
|
|
114
|
+
omit: model.readerContentType !== 'matches',
|
|
115
|
+
model
|
|
116
|
+
}),
|
|
117
|
+
item: jsonInput({
|
|
118
|
+
model,
|
|
119
|
+
bind: 'readerContent',
|
|
120
|
+
flex: 1,
|
|
121
|
+
width: '100%',
|
|
122
|
+
readonly: true,
|
|
123
|
+
showCopyButton: true
|
|
124
|
+
})
|
|
86
125
|
})
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
126
|
+
]
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
})
|
|
91
130
|
})
|
|
92
131
|
});
|
|
93
132
|
}
|
|
@@ -147,14 +186,7 @@ const helpButton = hoistCmp.factory({
|
|
|
147
186
|
items: [
|
|
148
187
|
h4('Sample Queries'),
|
|
149
188
|
ul({
|
|
150
|
-
|
|
151
|
-
items: [
|
|
152
|
-
{
|
|
153
|
-
query: "$..[?(@.colId == 'trader')]",
|
|
154
|
-
explanation:
|
|
155
|
-
'Find all nodes with a property "colId" equal to "trader"'
|
|
156
|
-
}
|
|
157
|
-
].map(({query, explanation}) =>
|
|
189
|
+
items: queryExamples.map(({query, explanation}) =>
|
|
158
190
|
li({
|
|
159
191
|
key: query,
|
|
160
192
|
items: [
|
|
@@ -202,12 +234,8 @@ const readerTbar = hoistCmp.factory<JsonSearchPanelImplModel>(({model}) => {
|
|
|
202
234
|
value: 'document'
|
|
203
235
|
}),
|
|
204
236
|
button({
|
|
205
|
-
text: '
|
|
206
|
-
value: '
|
|
207
|
-
}),
|
|
208
|
-
button({
|
|
209
|
-
text: 'Matching Values',
|
|
210
|
-
value: 'values'
|
|
237
|
+
text: 'Matches',
|
|
238
|
+
value: 'matches'
|
|
211
239
|
})
|
|
212
240
|
]
|
|
213
241
|
}),
|
|
@@ -228,6 +256,7 @@ const nodeBbar = hoistCmp.factory<JsonSearchPanelImplModel>(({model}) => {
|
|
|
228
256
|
bind: 'pathFormat',
|
|
229
257
|
minimal: true,
|
|
230
258
|
outlined: true,
|
|
259
|
+
disabled: !model.selectedRecord,
|
|
231
260
|
items: [
|
|
232
261
|
button({
|
|
233
262
|
text: 'XPath',
|
|
@@ -241,3 +270,31 @@ const nodeBbar = hoistCmp.factory<JsonSearchPanelImplModel>(({model}) => {
|
|
|
241
270
|
})
|
|
242
271
|
);
|
|
243
272
|
});
|
|
273
|
+
|
|
274
|
+
const queryExamples = [
|
|
275
|
+
{
|
|
276
|
+
query: '$',
|
|
277
|
+
explanation: 'Return the root object'
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
query: '$..*',
|
|
281
|
+
explanation: 'Return all nodes, recursively'
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
query: '$..[?(@.colId && @.width && @.hidden != true)]',
|
|
285
|
+
explanation:
|
|
286
|
+
'Find all nodes with a property "colId" and a property "width" and a property "hidden" not equal to true'
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
query: '$..[?(@.colId && @.width)]',
|
|
290
|
+
explanation: 'Find all nodes with a property "colId" and a property "width"'
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
query: "$..[?(@.colId == 'trader')]",
|
|
294
|
+
explanation: 'Find all nodes with a property "colId" equal to "trader"'
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
query: '$..grid[?(@.version == 1)]',
|
|
298
|
+
explanation: 'Find all grid nodes with a property "version" equal to 1'
|
|
299
|
+
}
|
|
300
|
+
];
|
|
@@ -9,7 +9,7 @@ import {GridModel} from '@xh/hoist/cmp/grid';
|
|
|
9
9
|
import {GroupingChooserModel} from '@xh/hoist/cmp/grouping';
|
|
10
10
|
import {HoistModel, managed, TaskObserver, XH} from '@xh/hoist/core';
|
|
11
11
|
import {action, bindable, makeObservable, observable} from '@xh/hoist/mobx';
|
|
12
|
-
import {isEmpty} from 'lodash';
|
|
12
|
+
import {isEmpty, zipWith} from 'lodash';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @internal
|
|
@@ -17,36 +17,31 @@ import {isEmpty} from 'lodash';
|
|
|
17
17
|
export class JsonSearchPanelImplModel extends HoistModel {
|
|
18
18
|
override xhImpl = true;
|
|
19
19
|
|
|
20
|
+
private matchingNodesUrl = 'jsonSearch/getMatchingNodes';
|
|
21
|
+
|
|
20
22
|
@managed gridModel: GridModel;
|
|
21
23
|
@managed groupingChooserModel: GroupingChooserModel;
|
|
22
24
|
@managed docLoadTask: TaskObserver = TaskObserver.trackLast();
|
|
23
25
|
@managed nodeLoadTask: TaskObserver = TaskObserver.trackLast();
|
|
24
26
|
|
|
25
27
|
@observable groupBy: string = null;
|
|
28
|
+
@observable isOpen: boolean = false;
|
|
26
29
|
|
|
27
30
|
@bindable.ref error = null;
|
|
28
31
|
@bindable path: string = '';
|
|
29
|
-
@bindable readerContentType: 'document' | '
|
|
32
|
+
@bindable readerContentType: 'document' | 'matches' = 'matches';
|
|
30
33
|
@bindable pathFormat: 'XPath' | 'JSONPath' = 'XPath';
|
|
31
34
|
@bindable readerContent: string = '';
|
|
32
35
|
@bindable matchingNodeCount: number = 0;
|
|
33
36
|
|
|
34
|
-
get
|
|
35
|
-
return this.
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get queryBuffer(): number {
|
|
39
|
-
return this.componentProps.queryBuffer ?? 200;
|
|
37
|
+
get subjectName(): string {
|
|
38
|
+
return this.componentProps.subjectName;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
get docSearchUrl(): string {
|
|
43
42
|
return this.componentProps.docSearchUrl;
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
get matchingNodesUrl(): string {
|
|
47
|
-
return this.componentProps.matchingNodesUrl;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
45
|
get selectedRecord() {
|
|
51
46
|
return this.gridModel.selectedRecord;
|
|
52
47
|
}
|
|
@@ -59,6 +54,11 @@ export class JsonSearchPanelImplModel extends HoistModel {
|
|
|
59
54
|
return [...this.componentProps.groupByOptions, {value: null, label: 'None'}];
|
|
60
55
|
}
|
|
61
56
|
|
|
57
|
+
@action
|
|
58
|
+
toggleSearchIsOpen() {
|
|
59
|
+
this.isOpen = !this.isOpen;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
62
|
constructor() {
|
|
63
63
|
super();
|
|
64
64
|
makeObservable(this);
|
|
@@ -82,7 +82,7 @@ export class JsonSearchPanelImplModel extends HoistModel {
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
track: () => [this.selectedRecord, this.readerContentType, this.pathFormat],
|
|
85
|
-
run: () => this.
|
|
85
|
+
run: () => this.loadreaderContentAsync(),
|
|
86
86
|
debounce: 300
|
|
87
87
|
}
|
|
88
88
|
);
|
|
@@ -110,7 +110,7 @@ export class JsonSearchPanelImplModel extends HoistModel {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
private async
|
|
113
|
+
private async loadreaderContentAsync() {
|
|
114
114
|
if (!this.selectedRecord) {
|
|
115
115
|
this.matchingNodeCount = 0;
|
|
116
116
|
this.readerContent = '';
|
|
@@ -128,19 +128,21 @@ export class JsonSearchPanelImplModel extends HoistModel {
|
|
|
128
128
|
url: this.matchingNodesUrl,
|
|
129
129
|
params: {
|
|
130
130
|
path: this.path,
|
|
131
|
-
asPathList: this.readerContentType === 'paths',
|
|
132
131
|
json
|
|
133
132
|
}
|
|
134
133
|
}).linkTo(this.nodeLoadTask);
|
|
135
134
|
|
|
136
|
-
this.matchingNodeCount = nodes.length;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
this.matchingNodeCount = nodes.paths.length;
|
|
136
|
+
nodes = zipWith(nodes.paths, nodes.values, (path: string, value) => {
|
|
137
|
+
return {
|
|
138
|
+
path: this.pathFormat === 'XPath' ? this.convertToXPath(path) : path,
|
|
139
|
+
value
|
|
140
|
+
};
|
|
141
|
+
});
|
|
140
142
|
this.readerContent = JSON.stringify(nodes, null, 2);
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
private
|
|
145
|
+
private convertToXPath(JSONPath: string): string {
|
|
144
146
|
return JSONPath.replaceAll(/^\$\['?/g, '/')
|
|
145
147
|
.replaceAll(/^\$/g, '')
|
|
146
148
|
.replaceAll(/'?]\['?/g, '/')
|
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
+
import * as AdminCol from '@xh/hoist/admin/columns';
|
|
8
|
+
import * as Col from '@xh/hoist/admin/columns/Rest';
|
|
9
|
+
import {jsonSearchButton} from '@xh/hoist/admin/jsonsearch/JsonSearchPanel';
|
|
7
10
|
import {fragment} from '@xh/hoist/cmp/layout';
|
|
8
11
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
9
12
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
10
13
|
import {restGrid} from '@xh/hoist/desktop/cmp/rest';
|
|
14
|
+
import {toolbarSep} from '@xh/hoist/desktop/cmp/toolbar';
|
|
11
15
|
import {Icon} from '@xh/hoist/icon';
|
|
12
16
|
import {differ} from '../../../differ/Differ';
|
|
13
17
|
import {regroupDialog} from '../../../regroup/RegroupDialog';
|
|
@@ -20,13 +24,35 @@ export const configPanel = hoistCmp.factory({
|
|
|
20
24
|
return fragment(
|
|
21
25
|
restGrid({
|
|
22
26
|
testId: 'config',
|
|
23
|
-
extraToolbarItems: () =>
|
|
24
|
-
|
|
27
|
+
extraToolbarItems: () => [
|
|
28
|
+
button({
|
|
25
29
|
icon: Icon.diff(),
|
|
26
30
|
text: 'Compare w/ Remote',
|
|
27
31
|
onClick: () => model.openDiffer()
|
|
28
|
-
})
|
|
29
|
-
|
|
32
|
+
}),
|
|
33
|
+
toolbarSep(),
|
|
34
|
+
jsonSearchButton({
|
|
35
|
+
subjectName: 'Config',
|
|
36
|
+
docSearchUrl: 'jsonSearch/searchConfigs',
|
|
37
|
+
gridModelConfig: {
|
|
38
|
+
sortBy: ['groupName', 'name', 'owner'],
|
|
39
|
+
columns: [
|
|
40
|
+
{
|
|
41
|
+
field: {name: 'owner', type: 'string'},
|
|
42
|
+
width: 200
|
|
43
|
+
},
|
|
44
|
+
{...AdminCol.groupName},
|
|
45
|
+
{...AdminCol.name},
|
|
46
|
+
{
|
|
47
|
+
field: {name: 'json', type: 'string'},
|
|
48
|
+
hidden: true
|
|
49
|
+
},
|
|
50
|
+
{...Col.lastUpdated}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
groupByOptions: ['owner', 'groupName', 'name']
|
|
54
|
+
})
|
|
55
|
+
]
|
|
30
56
|
}),
|
|
31
57
|
differ({omit: !model.differModel}),
|
|
32
58
|
regroupDialog()
|
|
@@ -10,9 +10,10 @@ import * as AdminCol from '@xh/hoist/admin/columns';
|
|
|
10
10
|
import {hframe} from '@xh/hoist/cmp/layout';
|
|
11
11
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
12
12
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
13
|
-
import {
|
|
13
|
+
import {jsonSearchButton} from '@xh/hoist/admin/jsonsearch/JsonSearchPanel';
|
|
14
14
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
15
15
|
import {restGrid} from '@xh/hoist/desktop/cmp/rest';
|
|
16
|
+
import {toolbarSep} from '@xh/hoist/desktop/cmp/toolbar';
|
|
16
17
|
import {Icon} from '@xh/hoist/icon';
|
|
17
18
|
import {differ} from '../../../differ/Differ';
|
|
18
19
|
import {JsonBlobModel} from './JsonBlobModel';
|
|
@@ -24,46 +25,44 @@ export const jsonBlobPanel = hoistCmp.factory({
|
|
|
24
25
|
return hframe(
|
|
25
26
|
panel({
|
|
26
27
|
item: restGrid({
|
|
27
|
-
extraToolbarItems: () =>
|
|
28
|
-
|
|
28
|
+
extraToolbarItems: () => [
|
|
29
|
+
button({
|
|
29
30
|
icon: Icon.diff(),
|
|
30
31
|
text: 'Compare w/ Remote',
|
|
31
32
|
onClick: () => model.openDiffer()
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
{...Col.lastUpdated}
|
|
33
|
+
}),
|
|
34
|
+
toolbarSep(),
|
|
35
|
+
jsonSearchButton({
|
|
36
|
+
subjectName: 'JSON Blob',
|
|
37
|
+
docSearchUrl: 'jsonSearch/searchBlobs',
|
|
38
|
+
gridModelConfig: {
|
|
39
|
+
sortBy: ['type', 'name', 'owner'],
|
|
40
|
+
columns: [
|
|
41
|
+
{
|
|
42
|
+
field: {name: 'token', type: 'string'},
|
|
43
|
+
hidden: true,
|
|
44
|
+
width: 100
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
field: {name: 'type', type: 'string'},
|
|
48
|
+
width: 200
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
field: {name: 'owner', type: 'string'},
|
|
52
|
+
width: 200
|
|
53
|
+
},
|
|
54
|
+
{...AdminCol.name},
|
|
55
|
+
{
|
|
56
|
+
field: {name: 'json', type: 'string'},
|
|
57
|
+
hidden: true
|
|
58
|
+
},
|
|
59
|
+
{...Col.lastUpdated}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
groupByOptions: ['owner', 'type', 'name']
|
|
63
|
+
})
|
|
64
64
|
]
|
|
65
|
-
}
|
|
66
|
-
groupByOptions: ['owner', 'type', 'name']
|
|
65
|
+
})
|
|
67
66
|
}),
|
|
68
67
|
differ({omit: !model.differModel})
|
|
69
68
|
);
|
|
@@ -12,9 +12,10 @@ import {UserPreferenceModel} from '@xh/hoist/admin/tabs/userData/prefs/UserPrefe
|
|
|
12
12
|
import {hframe} from '@xh/hoist/cmp/layout';
|
|
13
13
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
14
14
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
15
|
-
import {
|
|
15
|
+
import {jsonSearchButton} from '@xh/hoist/admin/jsonsearch/JsonSearchPanel';
|
|
16
16
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
17
17
|
import {restGrid} from '@xh/hoist/desktop/cmp/rest';
|
|
18
|
+
import {toolbarSep} from '@xh/hoist/desktop/cmp/toolbar';
|
|
18
19
|
import {Icon} from '@xh/hoist/icon';
|
|
19
20
|
|
|
20
21
|
export const userPreferencePanel = hoistCmp.factory({
|
|
@@ -25,38 +26,39 @@ export const userPreferencePanel = hoistCmp.factory({
|
|
|
25
26
|
panel({
|
|
26
27
|
items: [
|
|
27
28
|
restGrid({
|
|
28
|
-
extraToolbarItems: () =>
|
|
29
|
-
|
|
29
|
+
extraToolbarItems: () => [
|
|
30
|
+
button({
|
|
30
31
|
icon: Icon.gear(),
|
|
31
32
|
text: 'Configure',
|
|
32
33
|
onClick: () => (model.showEditorDialog = true)
|
|
33
|
-
})
|
|
34
|
-
|
|
34
|
+
}),
|
|
35
|
+
toolbarSep(),
|
|
36
|
+
jsonSearchButton({
|
|
37
|
+
subjectName: 'User Preference',
|
|
38
|
+
docSearchUrl: 'jsonSearch/searchUserPreferences',
|
|
39
|
+
gridModelConfig: {
|
|
40
|
+
sortBy: ['groupName', 'name', 'owner'],
|
|
41
|
+
columns: [
|
|
42
|
+
{
|
|
43
|
+
field: {name: 'owner', type: 'string'},
|
|
44
|
+
width: 200
|
|
45
|
+
},
|
|
46
|
+
{...AdminCol.groupName},
|
|
47
|
+
{...AdminCol.name},
|
|
48
|
+
{
|
|
49
|
+
field: {name: 'json', type: 'string'},
|
|
50
|
+
hidden: true
|
|
51
|
+
},
|
|
52
|
+
{...Col.lastUpdated}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
groupByOptions: ['owner', 'groupName', 'name']
|
|
56
|
+
})
|
|
57
|
+
]
|
|
35
58
|
}),
|
|
36
59
|
prefEditorDialog()
|
|
37
60
|
],
|
|
38
61
|
mask: 'onLoad'
|
|
39
|
-
}),
|
|
40
|
-
jsonSearchPanel({
|
|
41
|
-
docSearchUrl: 'jsonSearch/searchUserPreferences',
|
|
42
|
-
matchingNodesUrl: 'jsonSearch/getMatchingNodes',
|
|
43
|
-
gridModelConfig: {
|
|
44
|
-
sortBy: ['name'],
|
|
45
|
-
columns: [
|
|
46
|
-
{
|
|
47
|
-
field: {name: 'owner', type: 'string'},
|
|
48
|
-
width: 200
|
|
49
|
-
},
|
|
50
|
-
{...AdminCol.groupName},
|
|
51
|
-
{...AdminCol.name},
|
|
52
|
-
{
|
|
53
|
-
field: {name: 'json', type: 'string'},
|
|
54
|
-
hidden: true
|
|
55
|
-
},
|
|
56
|
-
{...Col.lastUpdated}
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
groupByOptions: ['owner', 'groupName', 'name']
|
|
60
62
|
})
|
|
61
63
|
);
|
|
62
64
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { GridConfig } from '@xh/hoist/cmp/grid';
|
|
3
3
|
import { HoistProps, SelectOption } from '@xh/hoist/core';
|
|
4
|
-
export interface
|
|
4
|
+
export interface JsonSearchButtonProps extends HoistProps {
|
|
5
|
+
/** Name of the type of Json Documents being searched. This appears in the dialog title. */
|
|
6
|
+
subjectName: string;
|
|
5
7
|
/** Url to endpoint for searching for matching JSON documents */
|
|
6
8
|
docSearchUrl: string;
|
|
7
|
-
/** Url to endpoint for listing matching JSON nodes */
|
|
8
|
-
matchingNodesUrl: string;
|
|
9
9
|
/**
|
|
10
10
|
* Config for GridModel used to display search results.
|
|
11
11
|
*/
|
|
12
12
|
gridModelConfig: GridConfig;
|
|
13
13
|
/**
|
|
14
|
-
* Names of
|
|
14
|
+
* Names of fields that can be used to group by.
|
|
15
15
|
*/
|
|
16
16
|
groupByOptions: Array<SelectOption | any>;
|
|
17
17
|
}
|
|
18
|
-
export declare const
|
|
18
|
+
export declare const JsonSearchButton: import("react").FC<JsonSearchButtonProps>, jsonSearchButton: import("@xh/hoist/core").ElementFactory<JsonSearchButtonProps>;
|
|
@@ -6,28 +6,29 @@ import { HoistModel, TaskObserver } from '@xh/hoist/core';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare class JsonSearchPanelImplModel extends HoistModel {
|
|
8
8
|
xhImpl: boolean;
|
|
9
|
+
private matchingNodesUrl;
|
|
9
10
|
gridModel: GridModel;
|
|
10
11
|
groupingChooserModel: GroupingChooserModel;
|
|
11
12
|
docLoadTask: TaskObserver;
|
|
12
13
|
nodeLoadTask: TaskObserver;
|
|
13
14
|
groupBy: string;
|
|
15
|
+
isOpen: boolean;
|
|
14
16
|
error: any;
|
|
15
17
|
path: string;
|
|
16
|
-
readerContentType: 'document' | '
|
|
18
|
+
readerContentType: 'document' | 'matches';
|
|
17
19
|
pathFormat: 'XPath' | 'JSONPath';
|
|
18
20
|
readerContent: string;
|
|
19
21
|
matchingNodeCount: number;
|
|
20
|
-
get
|
|
21
|
-
get queryBuffer(): number;
|
|
22
|
+
get subjectName(): string;
|
|
22
23
|
get docSearchUrl(): string;
|
|
23
|
-
get matchingNodesUrl(): string;
|
|
24
24
|
get selectedRecord(): import("../../../data").StoreRecord;
|
|
25
25
|
get gridModelConfig(): any;
|
|
26
26
|
get groupByOptions(): any[];
|
|
27
|
+
toggleSearchIsOpen(): void;
|
|
27
28
|
constructor();
|
|
28
29
|
onLinked(): void;
|
|
29
30
|
loadJsonDocsAsync(): Promise<void>;
|
|
30
|
-
private
|
|
31
|
-
private
|
|
31
|
+
private loadreaderContentAsync;
|
|
32
|
+
private convertToXPath;
|
|
32
33
|
private setGroupBy;
|
|
33
34
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "73.0.0-SNAPSHOT.
|
|
3
|
+
"version": "73.0.0-SNAPSHOT.1738169109530",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|