@mongoosejs/studio 0.1.20 → 0.2.1
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/backend/actions/ChatMessage/executeScript.js +4 -1
- package/backend/actions/ChatThread/createChatMessage.js +28 -22
- package/backend/helpers/evaluateFilter.js +38 -1
- package/express.js +4 -2
- package/frontend/public/app.js +702 -428
- package/frontend/public/index.html +3 -3
- package/frontend/public/style.css +1 -1
- package/frontend/public/tw.css +81 -62
- package/frontend/src/_util/document-search-autocomplete.js +229 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +27 -20
- package/frontend/src/chat/chat.html +20 -17
- package/frontend/src/chat/chat.js +2 -0
- package/frontend/src/document/document.css +1 -8
- package/frontend/src/document/document.html +202 -164
- package/frontend/src/document/document.js +1 -0
- package/frontend/src/document-details/document-details.html +1 -11
- package/frontend/src/document-details/document-details.js +43 -1
- package/frontend/src/document-details/document-property/document-property.html +4 -4
- package/frontend/src/index.js +36 -15
- package/frontend/src/json-node/json-node.html +118 -0
- package/frontend/src/json-node/json-node.js +272 -0
- package/frontend/src/list-array/list-array.html +15 -3
- package/frontend/src/list-array/list-array.js +21 -3
- package/frontend/src/list-default/list-default.js +2 -2
- package/frontend/src/list-json/list-json.html +1 -1
- package/frontend/src/list-json/list-json.js +11 -273
- package/frontend/src/list-subdocument/list-subdocument.html +13 -4
- package/frontend/src/list-subdocument/list-subdocument.js +11 -6
- package/frontend/src/models/document-search/document-search.html +1 -1
- package/frontend/src/models/document-search/document-search.js +22 -116
- package/frontend/src/models/models.css +5 -15
- package/frontend/src/models/models.html +34 -34
- package/frontend/src/navbar/navbar.html +15 -6
- package/package.json +2 -2
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const template = require('./list-json.html');
|
|
4
4
|
|
|
5
|
-
const JsonNodeTemplate = require('./json-node.html');
|
|
6
|
-
|
|
7
5
|
module.exports = app => app.component('list-json', {
|
|
8
6
|
template: template,
|
|
9
7
|
props: {
|
|
@@ -13,13 +11,20 @@ module.exports = app => app.component('list-json', {
|
|
|
13
11
|
references: {
|
|
14
12
|
type: Object,
|
|
15
13
|
default: () => ({})
|
|
14
|
+
},
|
|
15
|
+
maxTopLevelFields: {
|
|
16
|
+
type: Number,
|
|
17
|
+
default: 15
|
|
18
|
+
},
|
|
19
|
+
expandedFields: {
|
|
20
|
+
type: Array,
|
|
21
|
+
default: () => []
|
|
16
22
|
}
|
|
17
23
|
},
|
|
18
24
|
data() {
|
|
19
25
|
return {
|
|
20
26
|
collapsedMap: {},
|
|
21
27
|
indentSize: 16,
|
|
22
|
-
maxTopLevelFields: 15,
|
|
23
28
|
topLevelExpanded: false
|
|
24
29
|
};
|
|
25
30
|
},
|
|
@@ -32,6 +37,9 @@ module.exports = app => app.component('list-json', {
|
|
|
32
37
|
},
|
|
33
38
|
created() {
|
|
34
39
|
this.resetCollapse();
|
|
40
|
+
for (const field of this.expandedFields) {
|
|
41
|
+
this.toggleCollapse(field);
|
|
42
|
+
}
|
|
35
43
|
},
|
|
36
44
|
methods: {
|
|
37
45
|
resetCollapse() {
|
|
@@ -66,275 +74,5 @@ module.exports = app => app.component('list-json', {
|
|
|
66
74
|
expandTopLevel() {
|
|
67
75
|
this.topLevelExpanded = true;
|
|
68
76
|
}
|
|
69
|
-
},
|
|
70
|
-
components: {
|
|
71
|
-
JsonNode: {
|
|
72
|
-
name: 'JsonNode',
|
|
73
|
-
template: JsonNodeTemplate,
|
|
74
|
-
props: {
|
|
75
|
-
nodeKey: {
|
|
76
|
-
type: [String, Number],
|
|
77
|
-
default: null
|
|
78
|
-
},
|
|
79
|
-
value: {
|
|
80
|
-
required: true
|
|
81
|
-
},
|
|
82
|
-
level: {
|
|
83
|
-
type: Number,
|
|
84
|
-
required: true
|
|
85
|
-
},
|
|
86
|
-
isLast: {
|
|
87
|
-
type: Boolean,
|
|
88
|
-
default: false
|
|
89
|
-
},
|
|
90
|
-
path: {
|
|
91
|
-
type: String,
|
|
92
|
-
required: true
|
|
93
|
-
},
|
|
94
|
-
toggleCollapse: {
|
|
95
|
-
type: Function,
|
|
96
|
-
required: true
|
|
97
|
-
},
|
|
98
|
-
isCollapsed: {
|
|
99
|
-
type: Function,
|
|
100
|
-
required: true
|
|
101
|
-
},
|
|
102
|
-
createChildPath: {
|
|
103
|
-
type: Function,
|
|
104
|
-
required: true
|
|
105
|
-
},
|
|
106
|
-
indentSize: {
|
|
107
|
-
type: Number,
|
|
108
|
-
required: true
|
|
109
|
-
},
|
|
110
|
-
maxTopLevelFields: {
|
|
111
|
-
type: Number,
|
|
112
|
-
default: null
|
|
113
|
-
},
|
|
114
|
-
topLevelExpanded: {
|
|
115
|
-
type: Boolean,
|
|
116
|
-
default: false
|
|
117
|
-
},
|
|
118
|
-
expandTopLevel: {
|
|
119
|
-
type: Function,
|
|
120
|
-
default: null
|
|
121
|
-
},
|
|
122
|
-
references: {
|
|
123
|
-
type: Object,
|
|
124
|
-
default: () => ({})
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
computed: {
|
|
128
|
-
hasKey() {
|
|
129
|
-
return this.nodeKey !== null && this.nodeKey !== undefined;
|
|
130
|
-
},
|
|
131
|
-
isRoot() {
|
|
132
|
-
return this.path === 'root';
|
|
133
|
-
},
|
|
134
|
-
isArray() {
|
|
135
|
-
return Array.isArray(this.value);
|
|
136
|
-
},
|
|
137
|
-
isObject() {
|
|
138
|
-
if (this.value === null || this.isArray) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
return Object.prototype.toString.call(this.value) === '[object Object]';
|
|
142
|
-
},
|
|
143
|
-
isComplex() {
|
|
144
|
-
return this.isArray || this.isObject;
|
|
145
|
-
},
|
|
146
|
-
children() {
|
|
147
|
-
if (!this.isComplex) {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
if (this.isArray) {
|
|
151
|
-
return this.value.map((childValue, index) => ({
|
|
152
|
-
displayKey: null,
|
|
153
|
-
value: childValue,
|
|
154
|
-
isLast: index === this.value.length - 1,
|
|
155
|
-
path: this.createChildPath(this.path, index, true)
|
|
156
|
-
}));
|
|
157
|
-
}
|
|
158
|
-
const keys = Object.keys(this.value);
|
|
159
|
-
const visibleKeys = this.visibleObjectKeys(keys);
|
|
160
|
-
const hasHidden = this.hasHiddenRootChildren;
|
|
161
|
-
return visibleKeys.map((key, index) => ({
|
|
162
|
-
displayKey: key,
|
|
163
|
-
value: this.value[key],
|
|
164
|
-
isLast: !hasHidden && index === visibleKeys.length - 1,
|
|
165
|
-
path: this.createChildPath(this.path, key, false)
|
|
166
|
-
}));
|
|
167
|
-
},
|
|
168
|
-
hasChildren() {
|
|
169
|
-
return this.children.length > 0;
|
|
170
|
-
},
|
|
171
|
-
totalObjectChildCount() {
|
|
172
|
-
if (!this.isObject) {
|
|
173
|
-
return 0;
|
|
174
|
-
}
|
|
175
|
-
return Object.keys(this.value).length;
|
|
176
|
-
},
|
|
177
|
-
hasHiddenRootChildren() {
|
|
178
|
-
if (!this.isRoot || !this.isObject) {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
if (this.topLevelExpanded) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
if (typeof this.maxTopLevelFields !== 'number') {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
return this.totalObjectChildCount > this.maxTopLevelFields;
|
|
188
|
-
},
|
|
189
|
-
hiddenRootChildrenCount() {
|
|
190
|
-
if (!this.hasHiddenRootChildren) {
|
|
191
|
-
return 0;
|
|
192
|
-
}
|
|
193
|
-
return this.totalObjectChildCount - this.maxTopLevelFields;
|
|
194
|
-
},
|
|
195
|
-
showToggle() {
|
|
196
|
-
return this.hasChildren && !this.isRoot;
|
|
197
|
-
},
|
|
198
|
-
openingBracket() {
|
|
199
|
-
return this.isArray ? '[' : '{';
|
|
200
|
-
},
|
|
201
|
-
closingBracket() {
|
|
202
|
-
return this.isArray ? ']' : '}';
|
|
203
|
-
},
|
|
204
|
-
isCollapsedNode() {
|
|
205
|
-
return this.isCollapsed(this.path);
|
|
206
|
-
},
|
|
207
|
-
formattedValue() {
|
|
208
|
-
if (typeof this.value === 'bigint') {
|
|
209
|
-
return `${this.value.toString()}n`;
|
|
210
|
-
}
|
|
211
|
-
const stringified = JSON.stringify(this.value);
|
|
212
|
-
if (stringified === undefined) {
|
|
213
|
-
if (typeof this.value === 'symbol') {
|
|
214
|
-
return this.value.toString();
|
|
215
|
-
}
|
|
216
|
-
return String(this.value);
|
|
217
|
-
}
|
|
218
|
-
return stringified;
|
|
219
|
-
},
|
|
220
|
-
valueClasses() {
|
|
221
|
-
const classes = ['text-slate-700'];
|
|
222
|
-
if (this.value === null) {
|
|
223
|
-
classes.push('text-gray-500', 'italic');
|
|
224
|
-
return classes;
|
|
225
|
-
}
|
|
226
|
-
const type = typeof this.value;
|
|
227
|
-
if (type === 'string') {
|
|
228
|
-
classes.push('text-emerald-600');
|
|
229
|
-
return classes;
|
|
230
|
-
}
|
|
231
|
-
if (type === 'number' || type === 'bigint') {
|
|
232
|
-
classes.push('text-amber-600');
|
|
233
|
-
return classes;
|
|
234
|
-
}
|
|
235
|
-
if (type === 'boolean') {
|
|
236
|
-
classes.push('text-violet-600');
|
|
237
|
-
return classes;
|
|
238
|
-
}
|
|
239
|
-
if (type === 'undefined') {
|
|
240
|
-
classes.push('text-gray-500');
|
|
241
|
-
return classes;
|
|
242
|
-
}
|
|
243
|
-
return classes;
|
|
244
|
-
},
|
|
245
|
-
comma() {
|
|
246
|
-
return this.isLast ? '' : ',';
|
|
247
|
-
},
|
|
248
|
-
indentStyle() {
|
|
249
|
-
return {
|
|
250
|
-
paddingLeft: `${this.level * this.indentSize}px`
|
|
251
|
-
};
|
|
252
|
-
},
|
|
253
|
-
hiddenChildrenLabel() {
|
|
254
|
-
if (!this.hasHiddenRootChildren) {
|
|
255
|
-
return '';
|
|
256
|
-
}
|
|
257
|
-
const count = this.hiddenRootChildrenCount;
|
|
258
|
-
const suffix = count === 1 ? 'field' : 'fields';
|
|
259
|
-
return `${count} more ${suffix}`;
|
|
260
|
-
},
|
|
261
|
-
hiddenChildrenTooltip() {
|
|
262
|
-
return this.hiddenChildrenLabel;
|
|
263
|
-
},
|
|
264
|
-
normalizedPath() {
|
|
265
|
-
if (typeof this.path !== 'string') {
|
|
266
|
-
return '';
|
|
267
|
-
}
|
|
268
|
-
return this.path
|
|
269
|
-
.replace(/^root\.?/, '')
|
|
270
|
-
.replace(/\[\d+\]/g, '')
|
|
271
|
-
.replace(/^\./, '');
|
|
272
|
-
},
|
|
273
|
-
referenceModel() {
|
|
274
|
-
if (!this.normalizedPath || !this.references) {
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
return this.references[this.normalizedPath] || null;
|
|
278
|
-
},
|
|
279
|
-
shouldShowReferenceLink() {
|
|
280
|
-
return this.referenceId != null;
|
|
281
|
-
},
|
|
282
|
-
referenceId() {
|
|
283
|
-
if (!this.referenceModel) {
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
if (this.value == null) {
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
289
|
-
const type = typeof this.value;
|
|
290
|
-
if (type === 'string' || type === 'number' || type === 'bigint') {
|
|
291
|
-
return String(this.value);
|
|
292
|
-
}
|
|
293
|
-
if (type === 'object') {
|
|
294
|
-
if (this.value._id != null) {
|
|
295
|
-
return String(this.value._id);
|
|
296
|
-
}
|
|
297
|
-
if (typeof this.value.toString === 'function') {
|
|
298
|
-
const stringified = this.value.toString();
|
|
299
|
-
if (typeof stringified === 'string' && stringified !== '[object Object]') {
|
|
300
|
-
return stringified;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return null;
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
methods: {
|
|
308
|
-
visibleObjectKeys(keys) {
|
|
309
|
-
if (!this.isRoot || this.topLevelExpanded) {
|
|
310
|
-
return keys;
|
|
311
|
-
}
|
|
312
|
-
if (typeof this.maxTopLevelFields !== 'number') {
|
|
313
|
-
return keys;
|
|
314
|
-
}
|
|
315
|
-
if (keys.length <= this.maxTopLevelFields) {
|
|
316
|
-
return keys;
|
|
317
|
-
}
|
|
318
|
-
return keys.slice(0, this.maxTopLevelFields);
|
|
319
|
-
},
|
|
320
|
-
handleToggle() {
|
|
321
|
-
if (!this.isRoot) {
|
|
322
|
-
this.toggleCollapse(this.path);
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
handleExpandTopLevel() {
|
|
326
|
-
if (this.isRoot && typeof this.expandTopLevel === 'function') {
|
|
327
|
-
this.expandTopLevel();
|
|
328
|
-
}
|
|
329
|
-
},
|
|
330
|
-
goToReference() {
|
|
331
|
-
const id = this.referenceId;
|
|
332
|
-
if (!this.referenceModel || id == null) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
77
|
}
|
|
340
78
|
});
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
<div class="list-subdocument tooltip">
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
2
|
+
<div>{{shortenValue}}</div>
|
|
3
|
+
<div class="tooltiptext" style="display:flex; width: 100%; justify-content: space-around; align-items: center; min-width: 180px;">
|
|
4
|
+
<div class="tooltiptextchild" @click.stop="showViewDataModal = true">View data</div>
|
|
5
|
+
<div class="tooltiptextchild" @click.stop="copyText(value)">Copy 📋</div>
|
|
6
|
+
</div>
|
|
7
|
+
<modal ref="viewDataModal" v-if="showViewDataModal" containerClass="!h-[90vh] !w-[90vw]">
|
|
8
|
+
<template #body>
|
|
9
|
+
<div @click.stop class="w-full h-full cursor-auto">
|
|
10
|
+
<div class="modal-exit" @click="showViewDataModal = false">×</div>
|
|
11
|
+
<list-json :value="value" :maxTopLevelFields="null" />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
</modal>
|
|
6
15
|
</div>
|
|
@@ -8,16 +8,24 @@ require('../appendCSS')(require('./list-subdocument.css'));
|
|
|
8
8
|
module.exports = app => app.component('list-subdocument', {
|
|
9
9
|
template: template,
|
|
10
10
|
props: ['value'],
|
|
11
|
+
data: () => ({ showViewDataModal: false }),
|
|
11
12
|
computed: {
|
|
12
13
|
shortenValue() {
|
|
13
|
-
|
|
14
|
+
if (this.value == null) {
|
|
15
|
+
return this.value;
|
|
16
|
+
}
|
|
17
|
+
const value = JSON.stringify(this.value);
|
|
18
|
+
if (value.length > 50) {
|
|
19
|
+
return `${value.slice(0, 50)}…`;
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
14
22
|
}
|
|
15
23
|
},
|
|
16
24
|
methods: {
|
|
17
25
|
copyText(value) {
|
|
18
26
|
const storage = document.createElement('textarea');
|
|
19
27
|
storage.value = JSON.stringify(value);
|
|
20
|
-
const elem = this.$
|
|
28
|
+
const elem = this.$el;
|
|
21
29
|
elem.appendChild(storage);
|
|
22
30
|
storage.select();
|
|
23
31
|
storage.setSelectionRange(0, 99999);
|
|
@@ -25,8 +33,5 @@ module.exports = app => app.component('list-subdocument', {
|
|
|
25
33
|
elem.removeChild(storage);
|
|
26
34
|
this.$toast.success('Text copied!');
|
|
27
35
|
}
|
|
28
|
-
},
|
|
29
|
-
mounted: function() {
|
|
30
|
-
Prism.highlightElement(this.$refs.SubDocCode);
|
|
31
36
|
}
|
|
32
|
-
});
|
|
37
|
+
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
ref="searchInput"
|
|
4
4
|
class="w-full font-mono rounded-md p-1 border border-gray-300 outline-gray-300 text-lg focus:ring-1 focus:ring-ultramarine-200 focus:ring-offset-0 focus:outline-none"
|
|
5
5
|
type="text"
|
|
6
|
-
placeholder="Filter"
|
|
6
|
+
placeholder="Filter (supports JS, dates, ObjectIds, and more)"
|
|
7
7
|
v-model="searchText"
|
|
8
8
|
@click="initFilter"
|
|
9
9
|
@input="updateAutocomplete"
|
|
@@ -1,34 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const template = require('./document-search.html');
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'$gt',
|
|
10
|
-
'$gte',
|
|
11
|
-
'$lt',
|
|
12
|
-
'$lte',
|
|
13
|
-
'$in',
|
|
14
|
-
'$nin',
|
|
15
|
-
'$exists',
|
|
16
|
-
'$regex',
|
|
17
|
-
'$options',
|
|
18
|
-
'$text',
|
|
19
|
-
'$search',
|
|
20
|
-
'$and',
|
|
21
|
-
'$or',
|
|
22
|
-
'$nor',
|
|
23
|
-
'$not',
|
|
24
|
-
'$elemMatch',
|
|
25
|
-
'$size',
|
|
26
|
-
'$all',
|
|
27
|
-
'$type',
|
|
28
|
-
'$expr',
|
|
29
|
-
'$jsonSchema',
|
|
30
|
-
'$mod'
|
|
31
|
-
];
|
|
4
|
+
const {
|
|
5
|
+
buildAutocompleteTrie,
|
|
6
|
+
getAutocompleteSuggestions,
|
|
7
|
+
applySuggestion
|
|
8
|
+
} = require('../../_util/document-search-autocomplete');
|
|
32
9
|
|
|
33
10
|
module.exports = app => app.component('document-search', {
|
|
34
11
|
template,
|
|
@@ -70,19 +47,7 @@ module.exports = app => app.component('document-search', {
|
|
|
70
47
|
this.$emit('search', this.searchText);
|
|
71
48
|
},
|
|
72
49
|
buildAutocompleteTrie() {
|
|
73
|
-
this.autocompleteTrie =
|
|
74
|
-
this.autocompleteTrie.bulkInsert(QUERY_SELECTORS, 5, 'operator');
|
|
75
|
-
if (Array.isArray(this.schemaPaths) && this.schemaPaths.length > 0) {
|
|
76
|
-
const paths = this.schemaPaths
|
|
77
|
-
.map(path => path?.path)
|
|
78
|
-
.filter(path => typeof path === 'string' && path.length > 0);
|
|
79
|
-
for (const path of this.schemaPaths) {
|
|
80
|
-
if (path.schema) {
|
|
81
|
-
paths.push(...Object.keys(path.schema).map(subpath => `${path.path}.${subpath}`));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
this.autocompleteTrie.bulkInsert(paths, 10, 'fieldName');
|
|
85
|
-
}
|
|
50
|
+
this.autocompleteTrie = buildAutocompleteTrie(this.schemaPaths);
|
|
86
51
|
},
|
|
87
52
|
initFilter(ev) {
|
|
88
53
|
if (!this.searchText) {
|
|
@@ -95,60 +60,18 @@ module.exports = app => app.component('document-search', {
|
|
|
95
60
|
updateAutocomplete() {
|
|
96
61
|
const input = this.$refs.searchInput;
|
|
97
62
|
const cursorPos = input ? input.selectionStart : 0;
|
|
98
|
-
const before = this.searchText.slice(0, cursorPos);
|
|
99
|
-
const match = before.match(/(?:\{|,)\s*([^:\s]*)$/);
|
|
100
|
-
if (match && match[1]) {
|
|
101
|
-
const token = match[1];
|
|
102
|
-
const leadingQuoteMatch = token.match(/^["']/);
|
|
103
|
-
const trailingQuoteMatch = token.length > 1 && /["']$/.test(token)
|
|
104
|
-
? token[token.length - 1]
|
|
105
|
-
: '';
|
|
106
|
-
const term = token
|
|
107
|
-
.replace(/^["']/, '')
|
|
108
|
-
.replace(trailingQuoteMatch ? new RegExp(`[${trailingQuoteMatch}]$`) : '', '')
|
|
109
|
-
.trim();
|
|
110
|
-
if (!term) {
|
|
111
|
-
this.autocompleteSuggestions = [];
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
63
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
typeof path === 'string' &&
|
|
126
|
-
path.startsWith(`${term}.`) &&
|
|
127
|
-
!suggestionsSet.has(path)
|
|
128
|
-
) {
|
|
129
|
-
suggestionsSet.add(path);
|
|
130
|
-
if (suggestionsSet.size >= 10) {
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
let suggestions = Array.from(suggestionsSet);
|
|
137
|
-
if (leadingQuoteMatch) {
|
|
138
|
-
const leadingQuote = leadingQuoteMatch[0];
|
|
139
|
-
suggestions = suggestions.map(suggestion => `${leadingQuote}${suggestion}`);
|
|
140
|
-
}
|
|
141
|
-
if (trailingQuoteMatch) {
|
|
142
|
-
suggestions = suggestions.map(suggestion =>
|
|
143
|
-
suggestion.endsWith(trailingQuoteMatch) ? suggestion : `${suggestion}${trailingQuoteMatch}`
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
this.autocompleteSuggestions = suggestions;
|
|
147
|
-
this.autocompleteIndex = 0;
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
64
|
+
if (this.autocompleteTrie) {
|
|
65
|
+
this.autocompleteSuggestions = getAutocompleteSuggestions(
|
|
66
|
+
this.autocompleteTrie,
|
|
67
|
+
this.searchText,
|
|
68
|
+
cursorPos,
|
|
69
|
+
this.schemaPaths
|
|
70
|
+
);
|
|
71
|
+
this.autocompleteIndex = 0;
|
|
72
|
+
} else {
|
|
73
|
+
this.autocompleteSuggestions = [];
|
|
150
74
|
}
|
|
151
|
-
this.autocompleteSuggestions = [];
|
|
152
75
|
},
|
|
153
76
|
handleKeyDown(ev) {
|
|
154
77
|
if (this.autocompleteSuggestions.length === 0) {
|
|
@@ -172,32 +95,15 @@ module.exports = app => app.component('document-search', {
|
|
|
172
95
|
}
|
|
173
96
|
const input = this.$refs.searchInput;
|
|
174
97
|
const cursorPos = input.selectionStart;
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
const colonNeeded = !/^\s*:/.test(after);
|
|
179
|
-
if (!match) {
|
|
98
|
+
|
|
99
|
+
const result = applySuggestion(this.searchText, cursorPos, suggestion);
|
|
100
|
+
if (!result) {
|
|
180
101
|
return;
|
|
181
102
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
let replacement = suggestion;
|
|
185
|
-
const leadingQuote = token.startsWith('"') || token.startsWith('\'') ? token[0] : '';
|
|
186
|
-
const trailingQuote = token.length > 1 && (token.endsWith('"') || token.endsWith('\'')) ? token[token.length - 1] : '';
|
|
187
|
-
if (leadingQuote && !replacement.startsWith(leadingQuote)) {
|
|
188
|
-
replacement = `${leadingQuote}${replacement}`;
|
|
189
|
-
}
|
|
190
|
-
if (trailingQuote && !replacement.endsWith(trailingQuote)) {
|
|
191
|
-
replacement = `${replacement}${trailingQuote}`;
|
|
192
|
-
}
|
|
193
|
-
// Only insert : if we know the user isn't entering in a nested path
|
|
194
|
-
if (colonNeeded && (!leadingQuote || trailingQuote)) {
|
|
195
|
-
replacement = `${replacement}:`;
|
|
196
|
-
}
|
|
197
|
-
this.searchText = this.searchText.slice(0, start) + replacement + after;
|
|
103
|
+
|
|
104
|
+
this.searchText = result.text;
|
|
198
105
|
this.$nextTick(() => {
|
|
199
|
-
|
|
200
|
-
input.setSelectionRange(pos, pos);
|
|
106
|
+
input.setSelectionRange(result.newCursorPos, result.newCursorPos);
|
|
201
107
|
});
|
|
202
108
|
this.autocompleteSuggestions = [];
|
|
203
109
|
},
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
.models .documents table th {
|
|
45
45
|
position: sticky;
|
|
46
46
|
top: 42px;
|
|
47
|
-
background-color: white;
|
|
48
47
|
z-index: 1;
|
|
49
48
|
}
|
|
50
49
|
|
|
@@ -60,24 +59,17 @@
|
|
|
60
59
|
.models .documents table tr {
|
|
61
60
|
color: black;
|
|
62
61
|
border-spacing: 0px 0px;
|
|
63
|
-
background-color: white;
|
|
64
|
-
cursor: pointer;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
.models .documents table
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
.models .documents table tr:hover {
|
|
72
|
-
background-color: #a7b9ff;
|
|
64
|
+
.models .documents table th {
|
|
65
|
+
border-bottom: thin solid rgba(0, 0, 0, 0.12);
|
|
66
|
+
text-align: left;
|
|
67
|
+
height: 48px;
|
|
73
68
|
}
|
|
74
69
|
|
|
75
|
-
.models .documents table
|
|
76
|
-
td {
|
|
70
|
+
.models .documents table td {
|
|
77
71
|
border-bottom: thin solid rgba(0, 0, 0, 0.12);
|
|
78
72
|
text-align: left;
|
|
79
|
-
padding: 0 16px;
|
|
80
|
-
height: 48px;
|
|
81
73
|
}
|
|
82
74
|
|
|
83
75
|
.models textarea {
|
|
@@ -91,7 +83,6 @@ td {
|
|
|
91
83
|
|
|
92
84
|
.models .documents-menu {
|
|
93
85
|
position: fixed;
|
|
94
|
-
background-color: white;
|
|
95
86
|
z-index: 1;
|
|
96
87
|
padding: 4px;
|
|
97
88
|
display: flex;
|
|
@@ -136,4 +127,3 @@ td {
|
|
|
136
127
|
justify-content: space-around;
|
|
137
128
|
align-items: center;
|
|
138
129
|
}
|
|
139
|
-
|