@mongoosejs/studio 0.2.13 → 0.3.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/backend/actions/ChatMessage/executeScript.js +5 -1
- package/backend/actions/ChatThread/createChatMessage.js +2 -1
- package/backend/actions/ChatThread/streamChatMessage.js +2 -2
- package/eslint.config.js +4 -1
- package/frontend/public/app.js +24642 -543
- package/frontend/public/dark-theme.css +365 -0
- package/frontend/public/images/mongoose-studio.svg +4 -0
- package/frontend/public/index.html +21 -1
- package/frontend/public/style.css +5 -7
- package/frontend/public/theme-variables.css +294 -0
- package/frontend/public/tw.css +305 -252
- package/frontend/src/ace-editor/ace-editor.html +4 -0
- package/frontend/src/ace-editor/ace-editor.js +89 -0
- package/frontend/src/aceEditor.js +69 -0
- package/frontend/src/chat/chat-message/chat-message.html +1 -1
- package/frontend/src/chat/chat-message/chat-message.js +1 -1
- package/frontend/src/chat/chat-message-script/chat-message-script.html +51 -34
- package/frontend/src/chat/chat-message-script/chat-message-script.js +12 -55
- package/frontend/src/chat/chat.html +68 -39
- package/frontend/src/chat/chat.js +26 -2
- package/frontend/src/clone-document/clone-document.html +7 -2
- package/frontend/src/clone-document/clone-document.js +1 -8
- package/frontend/src/create-dashboard/create-dashboard.html +11 -6
- package/frontend/src/create-dashboard/create-dashboard.js +0 -7
- package/frontend/src/create-document/create-document.html +15 -9
- package/frontend/src/create-document/create-document.js +5 -12
- package/frontend/src/dashboard/dashboard.html +14 -12
- package/frontend/src/dashboard/dashboard.js +12 -4
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +13 -7
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +13 -21
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +19 -17
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +97 -2
- package/frontend/src/dashboard-result/dashboard-map/dashboard-map.js +27 -3
- package/frontend/src/dashboard-result/dashboard-result.html +3 -3
- package/frontend/src/dashboards/dashboards.html +101 -109
- package/frontend/src/dashboards/dashboards.js +25 -1
- package/frontend/src/detail-default/detail-default.html +2 -2
- package/frontend/src/detail-default/detail-default.js +24 -3
- package/frontend/src/document/confirm-changes/confirm-changes.html +1 -1
- package/frontend/src/document/confirm-delete/confirm-delete.html +1 -1
- package/frontend/src/document/document.css +1 -1
- package/frontend/src/document/document.html +28 -28
- package/frontend/src/document/execute-script/execute-script.html +20 -21
- package/frontend/src/document/execute-script/execute-script.js +1 -43
- package/frontend/src/document-details/document-details.css +4 -9
- package/frontend/src/document-details/document-details.html +34 -33
- package/frontend/src/document-details/document-details.js +2 -53
- package/frontend/src/document-details/document-property/document-property.html +12 -12
- package/frontend/src/edit-array/edit-array.html +7 -6
- package/frontend/src/edit-array/edit-array.js +10 -50
- package/frontend/src/edit-boolean/edit-boolean.html +12 -12
- package/frontend/src/edit-date/edit-date.html +2 -2
- package/frontend/src/edit-default/edit-default.html +1 -1
- package/frontend/src/edit-string/edit-string.html +3 -3
- package/frontend/src/edit-subdocument/edit-subdocument.html +5 -3
- package/frontend/src/edit-subdocument/edit-subdocument.js +1 -15
- package/frontend/src/export-query-results/export-query-results.html +3 -3
- package/frontend/src/json-node/json-node.html +3 -3
- package/frontend/src/list-json/json-node.html +1 -1
- package/frontend/src/models/document-search/document-search.html +3 -3
- package/frontend/src/models/model-switcher/model-switcher.html +53 -0
- package/frontend/src/models/model-switcher/model-switcher.js +123 -0
- package/frontend/src/models/models.css +3 -10
- package/frontend/src/models/models.html +146 -80
- package/frontend/src/models/models.js +108 -4
- package/frontend/src/navbar/navbar.html +157 -97
- package/frontend/src/navbar/navbar.js +31 -12
- package/frontend/src/routes.js +1 -1
- package/frontend/src/splash/splash.html +5 -5
- package/frontend/src/task-single/task-single.html +29 -29
- package/frontend/src/task-single/task-single.js +10 -10
- package/frontend/src/tasks/task-details/task-details.html +38 -38
- package/frontend/src/tasks/task-details/task-details.js +7 -2
- package/frontend/src/tasks/tasks.html +36 -35
- package/frontend/src/tasks/tasks.js +2 -25
- package/frontend/src/team/new-invitation/new-invitation.html +8 -8
- package/frontend/src/team/team.html +27 -27
- package/frontend/src/update-document/update-document.html +7 -2
- package/frontend/src/update-document/update-document.js +2 -11
- package/package.json +2 -1
- package/tailwind.config.js +75 -11
|
@@ -22,8 +22,7 @@ module.exports = app => app.component('document-details', {
|
|
|
22
22
|
value: ''
|
|
23
23
|
},
|
|
24
24
|
fieldErrors: {},
|
|
25
|
-
isSubmittingField: false
|
|
26
|
-
fieldValueEditor: null
|
|
25
|
+
isSubmittingField: false
|
|
27
26
|
};
|
|
28
27
|
},
|
|
29
28
|
mounted() {
|
|
@@ -32,32 +31,11 @@ module.exports = app => app.component('document-details', {
|
|
|
32
31
|
if (this.$refs.searchInput) {
|
|
33
32
|
this.$refs.searchInput.focus();
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
if (this.showAddFieldModal) {
|
|
37
|
-
this.initializeFieldValueEditor();
|
|
38
|
-
}
|
|
39
34
|
});
|
|
40
35
|
|
|
41
36
|
this.searchQuery = this.getSearchQueryFromRoute();
|
|
42
37
|
},
|
|
43
|
-
beforeDestroy() {
|
|
44
|
-
this.destroyFieldValueEditor();
|
|
45
|
-
},
|
|
46
38
|
watch: {
|
|
47
|
-
'fieldData.type'(newType, oldType) {
|
|
48
|
-
// When field type changes, we need to handle the transition
|
|
49
|
-
if (newType !== oldType) {
|
|
50
|
-
// Destroy existing CodeMirror if it exists
|
|
51
|
-
this.destroyFieldValueEditor();
|
|
52
|
-
|
|
53
|
-
// If switching to a type that needs CodeMirror, initialize it
|
|
54
|
-
if (this.shouldUseCodeMirror) {
|
|
55
|
-
this.$nextTick(() => {
|
|
56
|
-
this.initializeFieldValueEditor();
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
39
|
searchQuery(newValue) {
|
|
62
40
|
this.syncSearchQueryToUrl(newValue);
|
|
63
41
|
},
|
|
@@ -122,7 +100,7 @@ module.exports = app => app.component('document-details', {
|
|
|
122
100
|
const allTypes = new Set([...schemaTypes, ...commonTypes]);
|
|
123
101
|
return Array.from(allTypes).sort();
|
|
124
102
|
},
|
|
125
|
-
|
|
103
|
+
shouldUseAce() {
|
|
126
104
|
return ['Array', 'Object', 'Embedded'].includes(this.fieldData.type);
|
|
127
105
|
},
|
|
128
106
|
shouldUseDatePicker() {
|
|
@@ -313,15 +291,9 @@ module.exports = app => app.component('document-details', {
|
|
|
313
291
|
},
|
|
314
292
|
openAddFieldModal() {
|
|
315
293
|
this.showAddFieldModal = true;
|
|
316
|
-
this.$nextTick(() => {
|
|
317
|
-
if (this.shouldUseCodeMirror) {
|
|
318
|
-
this.initializeFieldValueEditor();
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
294
|
},
|
|
322
295
|
closeAddFieldModal() {
|
|
323
296
|
this.showAddFieldModal = false;
|
|
324
|
-
this.destroyFieldValueEditor();
|
|
325
297
|
this.resetFieldForm();
|
|
326
298
|
},
|
|
327
299
|
async addNewField(fieldData) {
|
|
@@ -430,29 +402,6 @@ module.exports = app => app.component('document-details', {
|
|
|
430
402
|
};
|
|
431
403
|
this.fieldErrors = {};
|
|
432
404
|
this.isSubmittingField = false;
|
|
433
|
-
// Reset CodeMirror editor if it exists
|
|
434
|
-
if (this.fieldValueEditor) {
|
|
435
|
-
this.fieldValueEditor.setValue('');
|
|
436
|
-
}
|
|
437
|
-
},
|
|
438
|
-
initializeFieldValueEditor() {
|
|
439
|
-
if (this.$refs.fieldValueEditor && !this.fieldValueEditor && this.shouldUseCodeMirror) {
|
|
440
|
-
this.$refs.fieldValueEditor.value = this.fieldData.value || '';
|
|
441
|
-
this.fieldValueEditor = CodeMirror.fromTextArea(this.$refs.fieldValueEditor, {
|
|
442
|
-
mode: 'javascript',
|
|
443
|
-
lineNumbers: true,
|
|
444
|
-
height: 'auto'
|
|
445
|
-
});
|
|
446
|
-
this.fieldValueEditor.on('change', () => {
|
|
447
|
-
this.fieldData.value = this.fieldValueEditor.getValue();
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
},
|
|
451
|
-
destroyFieldValueEditor() {
|
|
452
|
-
if (this.fieldValueEditor) {
|
|
453
|
-
this.fieldValueEditor.toTextArea();
|
|
454
|
-
this.fieldValueEditor = null;
|
|
455
|
-
}
|
|
456
405
|
},
|
|
457
406
|
getVirtualFieldType(virtual) {
|
|
458
407
|
const value = virtual.value;
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
<div class="border border-
|
|
1
|
+
<div class="border border-edge bg-surface rounded-lg mb-2" style="overflow: visible;">
|
|
2
2
|
<!-- Collapsible Header -->
|
|
3
3
|
<div
|
|
4
4
|
@click="toggleCollapse"
|
|
5
|
-
class="p-1 cursor-pointer flex items-center justify-between border-b border-
|
|
6
|
-
:class="{ 'bg-amber-100 hover:bg-amber-200': highlight, 'bg-slate-100 hover:bg-
|
|
5
|
+
class="p-1 cursor-pointer flex items-center justify-between border-b border-edge transition-colors duration-200 ease-in-out"
|
|
6
|
+
:class="{ 'bg-amber-100 hover:bg-amber-200': highlight, 'bg-slate-100 hover:bg-muted': !highlight }"
|
|
7
7
|
style="overflow: visible; position: relative;"
|
|
8
8
|
>
|
|
9
9
|
<div class="flex items-center" >
|
|
10
10
|
<svg
|
|
11
11
|
:class="isCollapsed ? 'rotate-0' : 'rotate-90'"
|
|
12
|
-
class="w-4 h-4 text-
|
|
12
|
+
class="w-4 h-4 text-content-tertiary mr-2 transition-transform duration-200"
|
|
13
13
|
fill="none"
|
|
14
14
|
stroke="currentColor"
|
|
15
15
|
viewBox="0 0 24 24"
|
|
16
16
|
>
|
|
17
17
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
|
18
18
|
</svg>
|
|
19
|
-
<span class="font-medium text-
|
|
20
|
-
<span class="ml-2 text-sm text-
|
|
19
|
+
<span class="font-medium text-content">{{path.path}}</span>
|
|
20
|
+
<span class="ml-2 text-sm text-content-tertiary">({{(path.instance || 'unknown').toLowerCase()}})</span>
|
|
21
21
|
<div v-if="isGeoJsonGeometry" class="ml-3 inline-flex items-center gap-2">
|
|
22
22
|
<div class="inline-flex items-center rounded-full bg-gray-200 p-0.5 text-xs font-semibold">
|
|
23
23
|
<button
|
|
24
24
|
type="button"
|
|
25
25
|
class="rounded-full px-2.5 py-0.5 transition"
|
|
26
|
-
:class="detailViewMode === 'text' ? 'bg-blue-600 text-white shadow' : 'text-
|
|
26
|
+
:class="detailViewMode === 'text' ? 'bg-blue-600 text-white shadow' : 'text-content-secondary hover:text-content'"
|
|
27
27
|
:style="detailViewMode === 'text' ? 'color: white !important; background-color: #2563eb !important;' : ''"
|
|
28
28
|
@click.stop="setDetailViewMode('text')">
|
|
29
29
|
Text
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<button
|
|
32
32
|
type="button"
|
|
33
33
|
class="rounded-full px-2.5 py-0.5 transition"
|
|
34
|
-
:class="detailViewMode === 'map' ? 'bg-blue-600 text-white shadow' : 'text-
|
|
34
|
+
:class="detailViewMode === 'map' ? 'bg-blue-600 text-white shadow' : 'text-content-secondary hover:text-content'"
|
|
35
35
|
:style="detailViewMode === 'map' ? 'color: white !important; background-color: #2563eb !important;' : ''"
|
|
36
36
|
@click.stop="setDetailViewMode('map')">
|
|
37
37
|
Map
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
<div class="flex items-center gap-2">
|
|
73
73
|
<button
|
|
74
74
|
type="button"
|
|
75
|
-
class="flex items-center gap-1 text-sm text-gray-600 hover:text-gray-800 px-2 py-1 rounded-md border border-transparent hover:border-
|
|
75
|
+
class="flex items-center gap-1 text-sm text-gray-600 hover:text-gray-800 px-2 py-1 rounded-md border border-transparent hover:border-edge-strong bg-surface"
|
|
76
76
|
@click.stop.prevent="copyPropertyValue"
|
|
77
77
|
title="Copy value"
|
|
78
78
|
aria-label="Copy property value"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<router-link
|
|
86
86
|
v-if="path.ref && getValueForPath(path.path)"
|
|
87
87
|
:to="`/model/${path.ref}/document/${getValueForPath(path.path)}`"
|
|
88
|
-
class="bg-
|
|
88
|
+
class="bg-primary hover:bg-primary-hover text-primary-text px-2 py-1 text-sm rounded-md"
|
|
89
89
|
@click.stop
|
|
90
90
|
>View Document
|
|
91
91
|
</router-link>
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
<div v-else class="text-xs py-1.5 px-2 font-mono text-gray-800 break-words whitespace-pre-wrap mt-1">{{ arrayUtils.formatValue(item) }}</div>
|
|
164
164
|
</div>
|
|
165
165
|
<div class="mb-1.5 py-2.5 px-3 pl-4 bg-transparent border-none border-l-[3px] border-l-blue-500 rounded-none transition-all duration-200 cursor-pointer relative opacity-70 hover:opacity-100">
|
|
166
|
-
<div class="text-xs py-1.5 px-2 font-mono text-
|
|
166
|
+
<div class="text-xs py-1.5 px-2 font-mono text-content-tertiary italic break-words whitespace-pre-wrap mt-1">
|
|
167
167
|
... and {{ remainingArrayCount }} more item{{ remainingArrayCount !== 1 ? 's' : '' }}
|
|
168
168
|
</div>
|
|
169
169
|
</div>
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
</div>
|
|
181
181
|
<!-- Non-array truncated view -->
|
|
182
182
|
<div v-else-if="shouldShowTruncated && !isArray" class="relative">
|
|
183
|
-
<div class="text-
|
|
183
|
+
<div class="text-content-secondary whitespace-pre-wrap break-words font-mono text-sm">{{truncatedString}}</div>
|
|
184
184
|
<button
|
|
185
185
|
@click="toggleValueExpansion"
|
|
186
186
|
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1 transform transition-all duration-200 ease-in-out hover:translate-x-0.5"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<div class="w-full">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
:
|
|
7
|
-
|
|
2
|
+
<ace-editor
|
|
3
|
+
:value="arrayStr"
|
|
4
|
+
@input="onEditorInput"
|
|
5
|
+
mode="json"
|
|
6
|
+
:line-numbers="true"
|
|
7
|
+
class="min-h-[300px]"
|
|
8
|
+
/>
|
|
8
9
|
</div>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const template = require('./edit-array.html');
|
|
4
|
-
|
|
5
4
|
const { BSON } = require('mongodb/lib/bson');
|
|
6
5
|
|
|
7
6
|
const ObjectId = new Proxy(BSON.ObjectId, {
|
|
@@ -16,10 +15,14 @@ module.exports = app => app.component('edit-array', {
|
|
|
16
15
|
props: ['value'],
|
|
17
16
|
data() {
|
|
18
17
|
return {
|
|
19
|
-
arrayValue: []
|
|
20
|
-
arrayEditor: null
|
|
18
|
+
arrayValue: []
|
|
21
19
|
};
|
|
22
20
|
},
|
|
21
|
+
computed: {
|
|
22
|
+
arrayStr() {
|
|
23
|
+
return JSON.stringify(this.arrayValue, null, 2);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
23
26
|
methods: {
|
|
24
27
|
initializeArray() {
|
|
25
28
|
if (this.value == null) {
|
|
@@ -29,42 +32,13 @@ module.exports = app => app.component('edit-array', {
|
|
|
29
32
|
} else {
|
|
30
33
|
this.arrayValue = [];
|
|
31
34
|
}
|
|
32
|
-
|
|
33
|
-
// Update CodeMirror editor if it exists
|
|
34
|
-
this.$nextTick(() => {
|
|
35
|
-
if (this.arrayEditor) {
|
|
36
|
-
const arrayStr = JSON.stringify(this.arrayValue, null, 2);
|
|
37
|
-
this.arrayEditor.setValue(arrayStr);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
},
|
|
41
|
-
initializeArrayEditor() {
|
|
42
|
-
this.$nextTick(() => {
|
|
43
|
-
const textareaRef = this.$refs.arrayEditor;
|
|
44
|
-
const textarea = Array.isArray(textareaRef) ? textareaRef[0] : textareaRef;
|
|
45
|
-
if (textarea && !this.arrayEditor) {
|
|
46
|
-
const arrayStr = JSON.stringify(this.arrayValue, null, 2);
|
|
47
|
-
textarea.value = arrayStr;
|
|
48
|
-
this.arrayEditor = CodeMirror.fromTextArea(textarea, {
|
|
49
|
-
mode: 'javascript',
|
|
50
|
-
lineNumbers: true
|
|
51
|
-
});
|
|
52
|
-
this.arrayEditor.on('change', () => {
|
|
53
|
-
this.updateArrayFromEditor();
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
35
|
},
|
|
58
|
-
|
|
59
|
-
if (!this.arrayEditor) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
36
|
+
onEditorInput(str) {
|
|
62
37
|
try {
|
|
63
|
-
|
|
64
|
-
if (value.trim() === '') {
|
|
38
|
+
if (str.trim() === '') {
|
|
65
39
|
this.arrayValue = [];
|
|
66
40
|
} else {
|
|
67
|
-
this.arrayValue = JSON.parse(
|
|
41
|
+
this.arrayValue = JSON.parse(str);
|
|
68
42
|
}
|
|
69
43
|
this.emitUpdate();
|
|
70
44
|
} catch (err) {
|
|
@@ -81,25 +55,11 @@ module.exports = app => app.component('edit-array', {
|
|
|
81
55
|
},
|
|
82
56
|
mounted() {
|
|
83
57
|
this.initializeArray();
|
|
84
|
-
this.initializeArrayEditor();
|
|
85
|
-
},
|
|
86
|
-
beforeDestroy() {
|
|
87
|
-
if (this.arrayEditor) {
|
|
88
|
-
this.arrayEditor.toTextArea();
|
|
89
|
-
}
|
|
90
58
|
},
|
|
91
59
|
watch: {
|
|
92
60
|
value: {
|
|
93
|
-
handler(
|
|
94
|
-
// Initialize array when value prop changes
|
|
61
|
+
handler() {
|
|
95
62
|
this.initializeArray();
|
|
96
|
-
// Update array editor if it exists
|
|
97
|
-
if (this.arrayEditor) {
|
|
98
|
-
this.$nextTick(() => {
|
|
99
|
-
const arrayStr = JSON.stringify(this.arrayValue, null, 2);
|
|
100
|
-
this.arrayEditor.setValue(arrayStr);
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
63
|
},
|
|
104
64
|
deep: true,
|
|
105
65
|
immediate: true
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
<div class="edit-boolean">
|
|
2
2
|
<div class="flex flex-wrap gap-2">
|
|
3
|
-
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-
|
|
4
|
-
:class="selectedValue === true ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-
|
|
3
|
+
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-page"
|
|
4
|
+
:class="selectedValue === true ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-edge-strong text-content-secondary'">
|
|
5
5
|
<input
|
|
6
6
|
type="radio"
|
|
7
7
|
:checked="selectedValue === true"
|
|
8
8
|
@change="selectValue(true)"
|
|
9
|
-
class="w-4 h-4 text-blue-600 border-
|
|
9
|
+
class="w-4 h-4 text-blue-600 border-edge-strong focus:ring-blue-500"
|
|
10
10
|
/>
|
|
11
11
|
<span class="text-sm font-medium">true</span>
|
|
12
12
|
</label>
|
|
13
13
|
|
|
14
|
-
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-
|
|
15
|
-
:class="selectedValue === false ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-
|
|
14
|
+
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-page"
|
|
15
|
+
:class="selectedValue === false ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-edge-strong text-content-secondary'">
|
|
16
16
|
<input
|
|
17
17
|
type="radio"
|
|
18
18
|
:checked="selectedValue === false"
|
|
19
19
|
@change="selectValue(false)"
|
|
20
|
-
class="w-4 h-4 text-blue-600 border-
|
|
20
|
+
class="w-4 h-4 text-blue-600 border-edge-strong focus:ring-blue-500"
|
|
21
21
|
/>
|
|
22
22
|
<span class="text-sm font-medium">false</span>
|
|
23
23
|
</label>
|
|
24
24
|
|
|
25
|
-
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-
|
|
26
|
-
:class="selectedValue === null ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-
|
|
25
|
+
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-page"
|
|
26
|
+
:class="selectedValue === null ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-edge-strong text-content-secondary'">
|
|
27
27
|
<input
|
|
28
28
|
type="radio"
|
|
29
29
|
:checked="selectedValue === null"
|
|
30
30
|
@change="selectValue(null)"
|
|
31
|
-
class="w-4 h-4 text-blue-600 border-
|
|
31
|
+
class="w-4 h-4 text-blue-600 border-edge-strong focus:ring-blue-500"
|
|
32
32
|
/>
|
|
33
33
|
<span class="text-sm font-medium">null</span>
|
|
34
34
|
</label>
|
|
35
35
|
|
|
36
|
-
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-
|
|
37
|
-
:class="selectedValue === undefined ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-
|
|
36
|
+
<label class="flex items-center gap-2 px-3 py-2 border rounded cursor-pointer hover:bg-page"
|
|
37
|
+
:class="selectedValue === undefined ? 'bg-blue-100 border-blue-300 text-blue-800' : 'border-edge-strong text-content-secondary'">
|
|
38
38
|
<input
|
|
39
39
|
type="radio"
|
|
40
40
|
:checked="selectedValue === undefined"
|
|
41
41
|
@change="selectValue(undefined)"
|
|
42
|
-
class="w-4 h-4 text-blue-600 border-
|
|
42
|
+
class="w-4 h-4 text-blue-600 border-edge-strong focus:ring-blue-500"
|
|
43
43
|
/>
|
|
44
44
|
<span class="text-sm font-medium">undefined</span>
|
|
45
45
|
</label>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<div>
|
|
2
2
|
<input
|
|
3
3
|
v-if="dateSelection == 'picker'"
|
|
4
|
-
class="w-64 h-8 border border-
|
|
4
|
+
class="w-64 h-8 border border-edge-strong outline-0"
|
|
5
5
|
type="datetime-local"
|
|
6
6
|
:value="valueAsLocalString"
|
|
7
7
|
@input="$emit('input', $event.target.value)">
|
|
8
8
|
<input
|
|
9
9
|
v-if="dateSelection == 'iso'"
|
|
10
10
|
type="text"
|
|
11
|
-
class="w-64 h-8 border border-
|
|
11
|
+
class="w-64 h-8 border border-edge-strong outline-0"
|
|
12
12
|
:value="valueAsISOString"
|
|
13
13
|
@input="updateFromISO">
|
|
14
14
|
</div>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<div>
|
|
2
|
-
<input type="text" :value="value" @input="$emit('input', $event.target.value)" class="w-full p-1 border border-
|
|
2
|
+
<input type="text" :value="value" @input="$emit('input', $event.target.value)" class="w-full p-1 border border-edge-strong outline-0">
|
|
3
3
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<div>
|
|
2
2
|
<div v-if="hasEnumValues" class="space-y-2">
|
|
3
3
|
<select
|
|
4
|
-
class="w-full px-3 py-2 border border-
|
|
4
|
+
class="w-full px-3 py-2 border border-edge-strong bg-surface rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
5
5
|
:value="selectedOption"
|
|
6
6
|
@change="onSelectChange"
|
|
7
7
|
>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<input
|
|
15
15
|
v-if="selectedOption === '__other'"
|
|
16
16
|
type="text"
|
|
17
|
-
class="w-full px-3 py-2 border border-
|
|
17
|
+
class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
18
18
|
:value="otherValue"
|
|
19
19
|
@input="onOtherInput"
|
|
20
20
|
placeholder="Enter a value"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<div v-else>
|
|
24
24
|
<input
|
|
25
25
|
type="text"
|
|
26
|
-
class="w-full px-3 py-2 border border-
|
|
26
|
+
class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
27
27
|
:value="value != null ? value : ''"
|
|
28
28
|
@input="onTextInput"
|
|
29
29
|
placeholder="Enter a value"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<div class="edit-subdocument">
|
|
2
|
-
<
|
|
3
|
-
ref="editor"
|
|
2
|
+
<ace-editor
|
|
4
3
|
v-model="currentValue"
|
|
5
|
-
|
|
4
|
+
mode="javascript"
|
|
5
|
+
:line-numbers="true"
|
|
6
|
+
class="w-full h-[300px] min-h-[200px]"
|
|
7
|
+
/>
|
|
6
8
|
</div>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const template = require('./edit-subdocument.html');
|
|
4
|
-
|
|
5
4
|
const { BSON, EJSON } = require('mongodb/lib/bson');
|
|
6
5
|
|
|
7
6
|
const ObjectId = new Proxy(BSON.ObjectId, {
|
|
@@ -13,19 +12,11 @@ const ObjectId = new Proxy(BSON.ObjectId, {
|
|
|
13
12
|
module.exports = app => app.component('edit-subdocument', {
|
|
14
13
|
template: template,
|
|
15
14
|
props: ['value'],
|
|
16
|
-
data: () => ({ currentValue:
|
|
15
|
+
data: () => ({ currentValue: '', status: 'init' }),
|
|
17
16
|
mounted() {
|
|
18
17
|
this.currentValue = this.value == null
|
|
19
18
|
? '' + this.value
|
|
20
19
|
: JSON.stringify(this.value, null, ' ').trim();
|
|
21
|
-
this.$refs.editor.value = this.currentValue;
|
|
22
|
-
this.editor = CodeMirror.fromTextArea(this.$refs.editor, {
|
|
23
|
-
mode: 'javascript',
|
|
24
|
-
lineNumbers: true
|
|
25
|
-
});
|
|
26
|
-
this.editor.on('change', ev => {
|
|
27
|
-
this.currentValue = this.editor.getValue();
|
|
28
|
-
});
|
|
29
20
|
this.status = 'loaded';
|
|
30
21
|
},
|
|
31
22
|
watch: {
|
|
@@ -41,10 +32,5 @@ module.exports = app => app.component('edit-subdocument', {
|
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
34
|
},
|
|
44
|
-
beforeDestroy() {
|
|
45
|
-
if (this.editor) {
|
|
46
|
-
this.editor.toTextArea();
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
35
|
emits: ['input', 'error']
|
|
50
36
|
});
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
Choose fields to export
|
|
5
5
|
</div>
|
|
6
6
|
<div v-for="(schemaPath,index) in schemaPaths" class="w-5 flex items-center">
|
|
7
|
-
<input type="checkbox" class="mt-0 h-4 w-4 rounded border-
|
|
8
|
-
<div class="ml-2 text-
|
|
7
|
+
<input type="checkbox" class="mt-0 h-4 w-4 rounded border-edge-strong text-sky-600 focus:ring-sky-600 accent-sky-600" v-model="shouldExport[schemaPath.path]" :id="'schemaPath.path'+index">
|
|
8
|
+
<div class="ml-2 text-content-secondary grow shrink text-left">
|
|
9
9
|
<label :for="'schemaPath.path'+index">{{schemaPath.path}}</label>
|
|
10
10
|
</div>
|
|
11
11
|
</div>
|
|
12
|
-
<async-button class="rounded-md bg-
|
|
12
|
+
<async-button class="rounded-md bg-primary px-2.5 py-1.5 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600" @click="exportQueryResults">Export</async-button>
|
|
13
13
|
</div>
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
<button
|
|
4
4
|
v-if="showToggle"
|
|
5
5
|
type="button"
|
|
6
|
-
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-
|
|
6
|
+
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-content-tertiary hover:text-content-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer"
|
|
7
7
|
@click.stop="handleToggle"
|
|
8
8
|
>
|
|
9
9
|
{{ isCollapsedNode ? '+' : '-' }}
|
|
10
10
|
</button>
|
|
11
11
|
<span v-else class="w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0"></span>
|
|
12
12
|
<template v-if="hasKey">
|
|
13
|
-
<span class="text-
|
|
13
|
+
<span class="text-primary">"{{ nodeKey }}"</span><span>: </span>
|
|
14
14
|
</template>
|
|
15
15
|
<template v-if="isComplex">
|
|
16
16
|
<template v-if="hasChildren">
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
</span>
|
|
53
53
|
<a
|
|
54
54
|
href="#"
|
|
55
|
-
class="ml-1 text-sm text-
|
|
55
|
+
class="ml-1 text-sm text-primary opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
|
|
56
56
|
@click.stop.prevent="goToReference()"
|
|
57
57
|
>
|
|
58
58
|
View Document
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<button
|
|
4
4
|
v-if="showToggle"
|
|
5
5
|
type="button"
|
|
6
|
-
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-
|
|
6
|
+
class="w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-content-tertiary hover:text-content-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer"
|
|
7
7
|
@click.stop="handleToggle"
|
|
8
8
|
>
|
|
9
9
|
{{ isCollapsedNode ? '+' : '-' }}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<form @submit.prevent="emitSearch" class="relative flex-grow m-0">
|
|
2
2
|
<input
|
|
3
3
|
ref="searchInput"
|
|
4
|
-
class="w-full font-mono rounded-md p-1 border border-
|
|
4
|
+
class="w-full font-mono rounded-md p-1 border border-edge-strong outline-edge-strong text-lg focus:ring-1 focus:ring-primary-subtle focus:ring-offset-0 focus:outline-none"
|
|
5
5
|
type="text"
|
|
6
6
|
placeholder="Filter (supports JS, dates, ObjectIds, and more)"
|
|
7
7
|
v-model="searchText"
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
@input="updateAutocomplete"
|
|
10
10
|
@keydown="handleKeyDown"
|
|
11
11
|
/>
|
|
12
|
-
<ul v-if="autocompleteSuggestions.length" class="absolute z-[9999] bg-
|
|
12
|
+
<ul v-if="autocompleteSuggestions.length" class="absolute z-[9999] bg-surface border border-edge-strong rounded mt-1 w-full max-h-40 overflow-y-auto shadow">
|
|
13
13
|
<li
|
|
14
14
|
v-for="(suggestion, index) in autocompleteSuggestions"
|
|
15
15
|
:key="suggestion"
|
|
16
16
|
class="px-2 py-1 cursor-pointer"
|
|
17
|
-
:class="{ 'bg-
|
|
17
|
+
:class="{ 'bg-primary-subtle': index === autocompleteIndex }"
|
|
18
18
|
@mousedown.prevent="applySuggestion(index)"
|
|
19
19
|
>
|
|
20
20
|
{{ suggestion }}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div v-if="show" class="fixed inset-0 z-[9999]">
|
|
2
|
+
<div class="fixed inset-0 bg-black/40" @click="$emit('close')"></div>
|
|
3
|
+
<div
|
|
4
|
+
class="fixed top-[15%] left-1/2 -translate-x-1/2 w-full max-w-lg bg-surface rounded-lg shadow-2xl border border-edge overflow-hidden"
|
|
5
|
+
role="dialog"
|
|
6
|
+
aria-modal="true"
|
|
7
|
+
aria-label="Model switcher"
|
|
8
|
+
>
|
|
9
|
+
<div class="p-3 border-b border-gray-100">
|
|
10
|
+
<input
|
|
11
|
+
ref="searchInput"
|
|
12
|
+
v-model="search"
|
|
13
|
+
type="text"
|
|
14
|
+
placeholder="Type a model name..."
|
|
15
|
+
@keydown="handleKeydown"
|
|
16
|
+
class="w-full rounded-md border border-edge bg-page py-2 px-3 text-sm text-content placeholder:text-gray-400 focus:border-edge-strong focus:outline-none focus:ring-1 focus:ring-gray-300"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
<div ref="list" class="max-h-80 overflow-y-auto">
|
|
20
|
+
<template v-for="(item, index) in items" :key="item.section + '-' + item.model">
|
|
21
|
+
<div
|
|
22
|
+
v-if="index === 0 || items[index - 1].section !== item.section"
|
|
23
|
+
class="px-3 pt-2 pb-1 text-xs font-semibold text-gray-400 uppercase tracking-wider"
|
|
24
|
+
>
|
|
25
|
+
{{ item.section }}
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
:data-selected="index === selectedIndex"
|
|
29
|
+
@click="selectModel(item.model)"
|
|
30
|
+
@mouseenter="onMouseEnter(index)"
|
|
31
|
+
class="flex items-center px-3 py-1.5 mx-2 rounded-md cursor-pointer text-sm"
|
|
32
|
+
:class="index === selectedIndex ? 'bg-muted text-content' : 'text-content-secondary hover:bg-page'"
|
|
33
|
+
>
|
|
34
|
+
<span class="truncate" v-html="highlightMatch(item.model)"></span>
|
|
35
|
+
<span
|
|
36
|
+
v-if="modelDocumentCounts && modelDocumentCounts[item.model] !== undefined"
|
|
37
|
+
class="ml-auto text-xs text-gray-400 bg-muted rounded px-1.5 py-[1px]"
|
|
38
|
+
>
|
|
39
|
+
{{ formatCompactCount(modelDocumentCounts[item.model]) }}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
<div v-if="items.length === 0" class="px-3 py-4 text-sm text-content-tertiary text-center">
|
|
44
|
+
No models match "{{ search }}"
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="border-t border-gray-100 px-3 py-2 text-xs text-gray-400 flex gap-3">
|
|
48
|
+
<span>↑↓ navigate</span>
|
|
49
|
+
<span>↵ select</span>
|
|
50
|
+
<span>esc close</span>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|