@mongoosejs/studio 0.4.0 → 0.4.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/README.md +9 -0
- package/backend/actions/Model/getDocuments.js +7 -4
- package/backend/actions/Model/getDocumentsStream.js +7 -4
- package/backend/helpers/isBindIPConnection.js +8 -0
- package/backend/helpers/isLocalhostConnection.js +8 -0
- package/backend/helpers/normalizeBindIPOption.js +16 -0
- package/backend/helpers/parseProjectionParam.js +180 -0
- package/express.js +16 -0
- package/frontend/public/app.js +743 -88
- package/frontend/src/detail-objectid/detail-objectid.html +1 -0
- package/frontend/src/detail-objectid/detail-objectid.js +67 -0
- package/frontend/src/document-details/document-property/document-property.html +8 -3
- package/frontend/src/document-details/document-property/document-property.js +7 -0
- package/frontend/src/document-details/objectid-view-mode-picker/objectid-view-mode-picker.html +12 -0
- package/frontend/src/document-details/objectid-view-mode-picker/objectid-view-mode-picker.js +19 -0
- package/frontend/src/models/document-search/document-search.js +6 -0
- package/frontend/src/models/models.html +6 -8
- package/frontend/src/models/models.js +257 -85
- package/frontend/src/models/projection-search/projection-search.html +27 -0
- package/frontend/src/models/projection-search/projection-search.js +226 -0
- package/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<pre class="w-full whitespace-pre-wrap break-words font-mono text-sm text-content-secondary m-0">{{displayValue}}</pre>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const template = require('./detail-objectid.html');
|
|
4
|
+
const ObjectId = require('mongoose/lib/types/objectid');
|
|
5
|
+
|
|
6
|
+
module.exports = app => app.component('detail-objectid', {
|
|
7
|
+
template,
|
|
8
|
+
props: ['value', 'viewMode'],
|
|
9
|
+
emits: ['updated'],
|
|
10
|
+
watch: {
|
|
11
|
+
displayValue: {
|
|
12
|
+
immediate: true,
|
|
13
|
+
handler(val) {
|
|
14
|
+
this.$emit('updated', val);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
computed: {
|
|
19
|
+
format() {
|
|
20
|
+
return this.viewMode || 'hex';
|
|
21
|
+
},
|
|
22
|
+
hexValue() {
|
|
23
|
+
if (this.value == null) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (typeof this.value === 'string') {
|
|
27
|
+
return this.value;
|
|
28
|
+
}
|
|
29
|
+
if (typeof this.value === 'object') {
|
|
30
|
+
if (typeof this.value.toHexString === 'function') {
|
|
31
|
+
return this.value.toHexString();
|
|
32
|
+
}
|
|
33
|
+
if (typeof this.value.$oid === 'string') {
|
|
34
|
+
return this.value.$oid;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return String(this.value);
|
|
38
|
+
},
|
|
39
|
+
objectIdDate() {
|
|
40
|
+
const hex = this.hexValue;
|
|
41
|
+
return new ObjectId(hex).getTimestamp();
|
|
42
|
+
},
|
|
43
|
+
displayValue() {
|
|
44
|
+
if (this.value == null) {
|
|
45
|
+
return String(this.value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const hex = this.hexValue;
|
|
49
|
+
if (this.format === 'object_call') {
|
|
50
|
+
return `ObjectId('${hex}')`;
|
|
51
|
+
}
|
|
52
|
+
if (this.format === 'unix_seconds') {
|
|
53
|
+
if (!this.objectIdDate) {
|
|
54
|
+
return 'Invalid ObjectId';
|
|
55
|
+
}
|
|
56
|
+
return String(Math.floor(this.objectIdDate.getTime() / 1000));
|
|
57
|
+
}
|
|
58
|
+
if (this.format === 'date') {
|
|
59
|
+
if (!this.objectIdDate) {
|
|
60
|
+
return 'Invalid ObjectId';
|
|
61
|
+
}
|
|
62
|
+
return this.objectIdDate.toISOString();
|
|
63
|
+
}
|
|
64
|
+
return hex;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
@@ -20,7 +20,7 @@
|
|
|
20
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
26
|
:class="detailViewMode === 'text' ? 'bg-blue-600 text-white shadow' : 'text-content-secondary hover:text-content'"
|
|
@@ -76,6 +76,11 @@
|
|
|
76
76
|
:path="path"
|
|
77
77
|
@update:viewMode="dateViewMode = $event"
|
|
78
78
|
></date-view-mode-picker>
|
|
79
|
+
<objectid-view-mode-picker
|
|
80
|
+
v-if="isObjectIdPath"
|
|
81
|
+
:viewMode="objectIdViewMode"
|
|
82
|
+
@update:viewMode="objectIdViewMode = $event"
|
|
83
|
+
></objectid-view-mode-picker>
|
|
79
84
|
<button
|
|
80
85
|
type="button"
|
|
81
86
|
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"
|
|
@@ -202,7 +207,7 @@
|
|
|
202
207
|
<component
|
|
203
208
|
:is="getComponentForPath(path)"
|
|
204
209
|
:value="rawValue"
|
|
205
|
-
:viewMode="isDatePath ? dateViewMode : detailViewMode"
|
|
210
|
+
:viewMode="isDatePath ? dateViewMode : (isObjectIdPath ? objectIdViewMode : detailViewMode)"
|
|
206
211
|
@updated="renderedValue = $event"></component>
|
|
207
212
|
<button
|
|
208
213
|
@click="toggleValueExpansion"
|
|
@@ -219,7 +224,7 @@
|
|
|
219
224
|
<component
|
|
220
225
|
:is="getComponentForPath(path)"
|
|
221
226
|
:value="rawValue"
|
|
222
|
-
:viewMode="isDatePath ? dateViewMode : detailViewMode"
|
|
227
|
+
:viewMode="isDatePath ? dateViewMode : (isObjectIdPath ? objectIdViewMode : detailViewMode)"
|
|
223
228
|
@updated="renderedValue = $event"></component>
|
|
224
229
|
</div>
|
|
225
230
|
</div>
|
|
@@ -18,6 +18,7 @@ module.exports = app => app.component('document-property', {
|
|
|
18
18
|
return {
|
|
19
19
|
dateType: 'picker', // picker, iso
|
|
20
20
|
dateViewMode: 'utc_iso',
|
|
21
|
+
objectIdViewMode: 'hex',
|
|
21
22
|
renderedValue: UNSET,
|
|
22
23
|
isCollapsed: false, // Start uncollapsed by default
|
|
23
24
|
isValueExpanded: false, // Track if the value is expanded
|
|
@@ -38,6 +39,9 @@ module.exports = app => app.component('document-property', {
|
|
|
38
39
|
isDatePath() {
|
|
39
40
|
return this.path?.instance === 'Date';
|
|
40
41
|
},
|
|
42
|
+
isObjectIdPath() {
|
|
43
|
+
return this.path?.instance === 'ObjectID' || this.path?.instance === 'ObjectId';
|
|
44
|
+
},
|
|
41
45
|
rawValue() {
|
|
42
46
|
return this.getValueForPath(this.path.path);
|
|
43
47
|
},
|
|
@@ -177,6 +181,9 @@ module.exports = app => app.component('document-property', {
|
|
|
177
181
|
if (schemaPath.instance === 'Date') {
|
|
178
182
|
return 'detail-date';
|
|
179
183
|
}
|
|
184
|
+
if (schemaPath.instance === 'ObjectID' || schemaPath.instance === 'ObjectId') {
|
|
185
|
+
return 'detail-objectid';
|
|
186
|
+
}
|
|
180
187
|
return 'detail-default';
|
|
181
188
|
},
|
|
182
189
|
getEditComponentForPath(path) {
|
package/frontend/src/document-details/objectid-view-mode-picker/objectid-view-mode-picker.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="flex items-center gap-2" @click.stop>
|
|
2
|
+
<select
|
|
3
|
+
:value="format"
|
|
4
|
+
@input="onFormatChange($event.target.value)"
|
|
5
|
+
class="text-xs border border-edge rounded-md bg-surface px-2 py-1"
|
|
6
|
+
>
|
|
7
|
+
<option value="hex">Hex string</option>
|
|
8
|
+
<option value="object_call">ObjectId('...')</option>
|
|
9
|
+
<option value="unix_seconds">Unix timestamp</option>
|
|
10
|
+
<option value="date">Date</option>
|
|
11
|
+
</select>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const template = require('./objectid-view-mode-picker.html');
|
|
4
|
+
|
|
5
|
+
module.exports = app => app.component('objectid-view-mode-picker', {
|
|
6
|
+
template,
|
|
7
|
+
props: ['viewMode'],
|
|
8
|
+
emits: ['update:viewMode'],
|
|
9
|
+
computed: {
|
|
10
|
+
format() {
|
|
11
|
+
return this.viewMode || 'hex';
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
methods: {
|
|
15
|
+
onFormatChange(newFormat) {
|
|
16
|
+
this.$emit('update:viewMode', newFormat);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
@@ -45,6 +45,12 @@ module.exports = app => app.component('document-search', {
|
|
|
45
45
|
this.$refs.searchInput.focus();
|
|
46
46
|
},
|
|
47
47
|
methods: {
|
|
48
|
+
focusInput() {
|
|
49
|
+
const input = this.$refs.searchInput;
|
|
50
|
+
if (input && typeof input.focus === 'function') {
|
|
51
|
+
input.focus();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
48
54
|
emitSearch() {
|
|
49
55
|
this.$emit('input', this.searchText);
|
|
50
56
|
this.$emit('search', this.searchText);
|
|
@@ -263,14 +263,12 @@
|
|
|
263
263
|
</span>
|
|
264
264
|
</div>
|
|
265
265
|
<div v-if="isProjectionMenuSelected && (outputType === 'table' || outputType === 'json')" class="flex items-center gap-2 w-full mt-2 flex-shrink-0">
|
|
266
|
-
<
|
|
267
|
-
ref="
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
@focus="initProjection($event)"
|
|
273
|
-
@keydown.enter="applyProjectionFromInput()"
|
|
266
|
+
<projection-search
|
|
267
|
+
ref="projectionSearch"
|
|
268
|
+
:value="projectionText"
|
|
269
|
+
:schema-paths="schemaPaths"
|
|
270
|
+
@projection-input="projectionText = $event"
|
|
271
|
+
@apply="applyProjectionFromInput"
|
|
274
272
|
/>
|
|
275
273
|
</div>
|
|
276
274
|
</div>
|