@mongoosejs/studio 0.1.19 → 0.1.20

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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const Archetype = require('archetype');
4
+ const getRefFromSchemaType = require('../../helpers/getRefFromSchemaType');
4
5
  const removeSpecifiedPaths = require('../../helpers/removeSpecifiedPaths');
5
6
  const authorize = require('../../authorize');
6
7
 
@@ -37,7 +38,7 @@ module.exports = ({ db }) => async function getDocument(params) {
37
38
  schemaPaths[path] = {
38
39
  instance: Model.schema.paths[path].instance,
39
40
  path,
40
- ref: Model.schema.paths[path].options?.ref,
41
+ ref: getRefFromSchemaType(Model.schema.paths[path]),
41
42
  required: Model.schema.paths[path].options?.required,
42
43
  enum: Model.schema.paths[path].options?.enum
43
44
  };
@@ -3,6 +3,7 @@
3
3
  const Archetype = require('archetype');
4
4
  const removeSpecifiedPaths = require('../../helpers/removeSpecifiedPaths');
5
5
  const evaluateFilter = require('../../helpers/evaluateFilter');
6
+ const getRefFromSchemaType = require('../../helpers/getRefFromSchemaType');
6
7
  const authorize = require('../../authorize');
7
8
 
8
9
  const GetDocumentsParams = new Archetype({
@@ -77,7 +78,7 @@ module.exports = ({ db }) => async function getDocuments(params) {
77
78
  schemaPaths[path] = {
78
79
  instance: schemaType.instance,
79
80
  path,
80
- ref: schemaType.options?.ref,
81
+ ref: getRefFromSchemaType(schemaType),
81
82
  required: schemaType.options?.required,
82
83
  enum: schemaType.options?.enum
83
84
  };
@@ -87,7 +88,7 @@ module.exports = ({ db }) => async function getDocuments(params) {
87
88
  schemaPaths[path].schema[subpath] = {
88
89
  instance: schemaType.schema.paths[subpath].instance,
89
90
  path: subpath,
90
- ref: schemaType.schema.paths[subpath].options?.ref,
91
+ ref: getRefFromSchemaType(schemaType.schema.paths[subpath]),
91
92
  required: schemaType.schema.paths[subpath].options?.required,
92
93
  enum: schemaType.schema.paths[subpath].options?.enum
93
94
  };
@@ -3,6 +3,7 @@
3
3
  const Archetype = require('archetype');
4
4
  const removeSpecifiedPaths = require('../../helpers/removeSpecifiedPaths');
5
5
  const evaluateFilter = require('../../helpers/evaluateFilter');
6
+ const getRefFromSchemaType = require('../../helpers/getRefFromSchemaType');
6
7
  const authorize = require('../../authorize');
7
8
 
8
9
  const GetDocumentsParams = new Archetype({
@@ -67,7 +68,7 @@ module.exports = ({ db }) => async function* getDocumentsStream(params) {
67
68
  schemaPaths[path] = {
68
69
  instance: schemaType.instance,
69
70
  path,
70
- ref: schemaType.options?.ref,
71
+ ref: getRefFromSchemaType(schemaType),
71
72
  required: schemaType.options?.required,
72
73
  enum: schemaType.options?.enum
73
74
  };
@@ -77,7 +78,7 @@ module.exports = ({ db }) => async function* getDocumentsStream(params) {
77
78
  schemaPaths[path].schema[subpath] = {
78
79
  instance: schemaType.schema.paths[subpath].instance,
79
80
  path: subpath,
80
- ref: schemaType.schema.paths[subpath].options?.ref,
81
+ ref: getRefFromSchemaType(schemaType.schema.paths[subpath]),
81
82
  required: schemaType.schema.paths[subpath].options?.required,
82
83
  enum: schemaType.schema.paths[subpath].options?.enum
83
84
  };
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ module.exports = function getRefFromSchemaType(schemaType) {
4
+ return schemaType?.options?.ref ?? schemaType?.embeddedSchemaType?.options?.ref ?? schemaType?.caster?.options?.ref;
5
+ };
@@ -4349,7 +4349,7 @@ module.exports = app => app.component('list-default', {
4349
4349
  (module) {
4350
4350
 
4351
4351
  "use strict";
4352
- module.exports = "<div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <button\n v-if=\"showToggle\"\n type=\"button\"\n class=\"w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-gray-500 hover:text-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer\"\n @click.stop=\"handleToggle\"\n >\n {{ isCollapsedNode ? '+' : '-' }}\n </button>\n <span v-else class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0\"></span>\n <template v-if=\"hasKey\">\n <span class=\"text-blue-600\">\"{{ nodeKey }}\"</span><span>: </span>\n </template>\n <template v-if=\"isComplex\">\n <template v-if=\"hasChildren\">\n <span>{{ openingBracket }}</span>\n <span v-if=\"isCollapsedNode\" class=\"mx-1\">…</span>\n <span v-if=\"isCollapsedNode\">{{ closingBracket }}{{ comma }}</span>\n </template>\n <template v-else>\n <span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>\n </template>\n </template>\n <template v-else>\n <!--\n If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.\n This is done via CSS ellipsis strategy.\n -->\n <span\n v-if=\"shouldShowReferenceLink\"\n class=\"inline-flex items-baseline group\"\n >\n <span\n :class=\"[...valueClasses, 'underline', 'decoration-dotted', 'underline-offset-2']\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}\n </span>\n <span>\n {{ comma }}\n </span>\n <a\n href=\"#\"\n class=\"ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity\"\n @click.stop.prevent=\"goToReference(value)\"\n >\n View Document\n </a>\n </span>\n <span\n v-else\n :class=\"valueClasses\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}{{ comma }}\n </span>\n </template>\n </div>\n <template v-if=\"isComplex && hasChildren && !isCollapsedNode\">\n <json-node\n v-for=\"child in children\"\n :key=\"child.path\"\n :node-key=\"child.displayKey\"\n :value=\"child.value\"\n :level=\"level + 1\"\n :is-last=\"child.isLast\"\n :path=\"child.path\"\n :toggle-collapse=\"toggleCollapse\"\n :is-collapsed=\"isCollapsed\"\n :create-child-path=\"createChildPath\"\n :indent-size=\"indentSize\"\n :max-top-level-fields=\"maxTopLevelFields\"\n :top-level-expanded=\"topLevelExpanded\"\n :expand-top-level=\"expandTopLevel\"\n :references=\"references\"\n ></json-node>\n <div\n v-if=\"hasHiddenRootChildren\"\n class=\"flex items-baseline whitespace-pre\"\n :style=\"indentStyle\"\n >\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <button\n type=\"button\"\n class=\"text-xs inline-flex items-center gap-1 ml-4 text-slate-500 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400\"\n :title=\"hiddenChildrenTooltip\"\n @click.stop=\"handleExpandTopLevel\"\n >\n <span aria-hidden=\"true\">{{hiddenChildrenLabel}}…</span>\n </button>\n </div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <span>{{ closingBracket }}{{ comma }}</span>\n </div>\n </template>\n</div>\n";
4352
+ module.exports = "<div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <button\n v-if=\"showToggle\"\n type=\"button\"\n class=\"w-4 h-4 mr-1 inline-flex items-center justify-center leading-none text-gray-500 hover:text-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400 cursor-pointer\"\n @click.stop=\"handleToggle\"\n >\n {{ isCollapsedNode ? '+' : '-' }}\n </button>\n <span v-else class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible flex-shrink-0\"></span>\n <template v-if=\"hasKey\">\n <span class=\"text-blue-600\">\"{{ nodeKey }}\"</span><span>: </span>\n </template>\n <template v-if=\"isComplex\">\n <template v-if=\"hasChildren\">\n <span>{{ openingBracket }}</span>\n <span v-if=\"isCollapsedNode\" class=\"mx-1\">…</span>\n <span v-if=\"isCollapsedNode\">{{ closingBracket }}{{ comma }}</span>\n </template>\n <template v-else>\n <span>{{ openingBracket }}{{ closingBracket }}{{ comma }}</span>\n </template>\n </template>\n <template v-else>\n <!--\n If value is a string and overflows its container (i.e. goes over one line), show an ellipsis.\n This is done via CSS ellipsis strategy.\n -->\n <span\n v-if=\"shouldShowReferenceLink\"\n class=\"inline-flex items-baseline group\"\n >\n <span\n :class=\"[...valueClasses, 'underline', 'decoration-dotted', 'underline-offset-2']\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}\n </span>\n <span>\n {{ comma }}\n </span>\n <a\n href=\"#\"\n class=\"ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity\"\n @click.stop.prevent=\"goToReference()\"\n >\n View Document\n </a>\n </span>\n <span\n v-else\n :class=\"valueClasses\"\n :style=\"typeof value === 'string'\n ? {\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom'\n }\n : {}\"\n :title=\"typeof value === 'string' && $el && $el.scrollWidth > $el.clientWidth ? value : undefined\"\n >\n {{ formattedValue }}{{ comma }}\n </span>\n </template>\n </div>\n <template v-if=\"isComplex && hasChildren && !isCollapsedNode\">\n <json-node\n v-for=\"child in children\"\n :key=\"child.path\"\n :node-key=\"child.displayKey\"\n :value=\"child.value\"\n :level=\"level + 1\"\n :is-last=\"child.isLast\"\n :path=\"child.path\"\n :toggle-collapse=\"toggleCollapse\"\n :is-collapsed=\"isCollapsed\"\n :create-child-path=\"createChildPath\"\n :indent-size=\"indentSize\"\n :max-top-level-fields=\"maxTopLevelFields\"\n :top-level-expanded=\"topLevelExpanded\"\n :expand-top-level=\"expandTopLevel\"\n :references=\"references\"\n ></json-node>\n <div\n v-if=\"hasHiddenRootChildren\"\n class=\"flex items-baseline whitespace-pre\"\n :style=\"indentStyle\"\n >\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <button\n type=\"button\"\n class=\"text-xs inline-flex items-center gap-1 ml-4 text-slate-500 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-slate-400\"\n :title=\"hiddenChildrenTooltip\"\n @click.stop=\"handleExpandTopLevel\"\n >\n <span aria-hidden=\"true\">{{hiddenChildrenLabel}}…</span>\n </button>\n </div>\n <div class=\"flex items-baseline whitespace-pre\" :style=\"indentStyle\">\n <span class=\"w-4 h-4 mr-1 inline-flex items-center justify-center invisible\"></span>\n <span>{{ closingBracket }}{{ comma }}</span>\n </div>\n </template>\n</div>\n";
4353
4353
 
4354
4354
  /***/ },
4355
4355
 
@@ -4650,7 +4650,31 @@ module.exports = app => app.component('list-json', {
4650
4650
  return this.references[this.normalizedPath] || null;
4651
4651
  },
4652
4652
  shouldShowReferenceLink() {
4653
- return Boolean(this.referenceModel) && typeof this.value === 'string';
4653
+ return this.referenceId != null;
4654
+ },
4655
+ referenceId() {
4656
+ if (!this.referenceModel) {
4657
+ return null;
4658
+ }
4659
+ if (this.value == null) {
4660
+ return null;
4661
+ }
4662
+ const type = typeof this.value;
4663
+ if (type === 'string' || type === 'number' || type === 'bigint') {
4664
+ return String(this.value);
4665
+ }
4666
+ if (type === 'object') {
4667
+ if (this.value._id != null) {
4668
+ return String(this.value._id);
4669
+ }
4670
+ if (typeof this.value.toString === 'function') {
4671
+ const stringified = this.value.toString();
4672
+ if (typeof stringified === 'string' && stringified !== '[object Object]') {
4673
+ return stringified;
4674
+ }
4675
+ }
4676
+ }
4677
+ return null;
4654
4678
  }
4655
4679
  },
4656
4680
  methods: {
@@ -4676,8 +4700,9 @@ module.exports = app => app.component('list-json', {
4676
4700
  this.expandTopLevel();
4677
4701
  }
4678
4702
  },
4679
- goToReference(id) {
4680
- if (!this.referenceModel) {
4703
+ goToReference() {
4704
+ const id = this.referenceId;
4705
+ if (!this.referenceModel || id == null) {
4681
4706
  return;
4682
4707
  }
4683
4708
  this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
@@ -5298,7 +5323,7 @@ module.exports = app => app.component('models', {
5298
5323
  this.error = 'No models found and Mongoose is not connected. Check our documentation for more information.';
5299
5324
  }
5300
5325
  }
5301
-
5326
+
5302
5327
  await this.initSearchFromUrl();
5303
5328
  },
5304
5329
  computed: {
@@ -31935,7 +31960,7 @@ const compile = () => {
31935
31960
  (module) {
31936
31961
 
31937
31962
  "use strict";
31938
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.19","description":"A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.","homepage":"https://studio.mongoosejs.io/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x"},"peerDependencies":{"mongoose":"7.x || 8.x || ^9.0.0"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongoose":"9.x"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js"}}');
31963
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.20","description":"A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.","homepage":"https://mongoosestudio.app/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x"},"peerDependencies":{"mongoose":"7.x || 8.x || ^9.0.0"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongoose":"9.x"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js"}}');
31939
31964
 
31940
31965
  /***/ }
31941
31966
 
@@ -53,7 +53,7 @@
53
53
  <a
54
54
  href="#"
55
55
  class="ml-1 text-sm text-sky-700 opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
56
- @click.stop.prevent="goToReference(value)"
56
+ @click.stop.prevent="goToReference()"
57
57
  >
58
58
  View Document
59
59
  </a>
@@ -277,7 +277,31 @@ module.exports = app => app.component('list-json', {
277
277
  return this.references[this.normalizedPath] || null;
278
278
  },
279
279
  shouldShowReferenceLink() {
280
- return Boolean(this.referenceModel) && typeof this.value === 'string';
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;
281
305
  }
282
306
  },
283
307
  methods: {
@@ -303,8 +327,9 @@ module.exports = app => app.component('list-json', {
303
327
  this.expandTopLevel();
304
328
  }
305
329
  },
306
- goToReference(id) {
307
- if (!this.referenceModel) {
330
+ goToReference() {
331
+ const id = this.referenceId;
332
+ if (!this.referenceModel || id == null) {
308
333
  return;
309
334
  }
310
335
  this.$router.push({ path: `/model/${this.referenceModel}/document/${id}` });
@@ -85,7 +85,7 @@ module.exports = app => app.component('models', {
85
85
  this.error = 'No models found and Mongoose is not connected. Check our documentation for more information.';
86
86
  }
87
87
  }
88
-
88
+
89
89
  await this.initSearchFromUrl();
90
90
  },
91
91
  computed: {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@mongoosejs/studio",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
5
- "homepage": "https://studio.mongoosejs.io/",
5
+ "homepage": "https://mongoosestudio.app/",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/mongoosejs/studio"