@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.
@@ -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
- <button
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) {
@@ -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
- <input
267
- ref="projectionInput"
268
- v-model="projectionText"
269
- type="text"
270
- placeholder="Projection: name email, or -password"
271
- class="flex-1 min-w-0 rounded border border-edge bg-surface px-2 py-1.5 text-sm font-mono placeholder:text-content-tertiary focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary"
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>