@mongoosejs/studio 0.1.17 → 0.1.19

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.
@@ -34,6 +34,7 @@ module.exports = app => app.component('models', {
34
34
  shouldShowCreateModal: false,
35
35
  shouldShowFieldModal: false,
36
36
  shouldShowIndexModal: false,
37
+ shouldShowCollectionInfoModal: false,
37
38
  shouldShowUpdateMultipleModal: false,
38
39
  shouldShowDeleteMultipleModal: false,
39
40
  shouldExport: {},
@@ -44,7 +45,9 @@ module.exports = app => app.component('models', {
44
45
  outputType: 'table', // json, table
45
46
  hideSidebar: null,
46
47
  lastSelectedIndex: null,
47
- error: null
48
+ error: null,
49
+ showActionsMenu: false,
50
+ collectionInfo: null
48
51
  }),
49
52
  created() {
50
53
  this.currentModel = this.model;
@@ -53,12 +56,23 @@ module.exports = app => app.component('models', {
53
56
  beforeDestroy() {
54
57
  document.removeEventListener('scroll', this.onScroll, true);
55
58
  window.removeEventListener('popstate', this.onPopState, true);
59
+ document.removeEventListener('click', this.onOutsideActionsMenuClick, true);
56
60
  },
57
61
  async mounted() {
58
62
  this.onScroll = () => this.checkIfScrolledToBottom();
59
63
  document.addEventListener('scroll', this.onScroll, true);
60
64
  this.onPopState = () => this.initSearchFromUrl();
61
65
  window.addEventListener('popstate', this.onPopState, true);
66
+ this.onOutsideActionsMenuClick = event => {
67
+ if (!this.showActionsMenu) {
68
+ return;
69
+ }
70
+ const actionsMenu = this.$refs.actionsMenuContainer;
71
+ if (actionsMenu && !actionsMenu.contains(event.target)) {
72
+ this.closeActionsMenu();
73
+ }
74
+ };
75
+ document.addEventListener('click', this.onOutsideActionsMenuClick, true);
62
76
  const { models, readyState } = await api.Model.listModels();
63
77
  this.models = models;
64
78
  if (this.currentModel == null && this.models.length > 0) {
@@ -71,7 +85,7 @@ module.exports = app => app.component('models', {
71
85
  this.error = 'No models found and Mongoose is not connected. Check our documentation for more information.';
72
86
  }
73
87
  }
74
-
88
+
75
89
  await this.initSearchFromUrl();
76
90
  },
77
91
  computed: {
@@ -160,6 +174,7 @@ module.exports = app => app.component('models', {
160
174
  async dropIndex(name) {
161
175
  const { mongoDBIndexes } = await api.Model.dropIndex({ model: this.currentModel, name });
162
176
  this.mongoDBIndexes = mongoDBIndexes;
177
+ this.$toast.success('Index dropped!');
163
178
  },
164
179
  async closeCreationModal() {
165
180
  this.shouldShowCreateModal = false;
@@ -232,11 +247,38 @@ module.exports = app => app.component('models', {
232
247
  }
233
248
  },
234
249
  async openIndexModal() {
250
+ this.closeActionsMenu();
235
251
  this.shouldShowIndexModal = true;
236
252
  const { mongoDBIndexes, schemaIndexes } = await api.Model.getIndexes({ model: this.currentModel });
237
253
  this.mongoDBIndexes = mongoDBIndexes;
238
254
  this.schemaIndexes = schemaIndexes;
239
255
  },
256
+ toggleActionsMenu() {
257
+ this.showActionsMenu = !this.showActionsMenu;
258
+ },
259
+ closeActionsMenu() {
260
+ this.showActionsMenu = false;
261
+ },
262
+ async openCollectionInfo() {
263
+ this.closeActionsMenu();
264
+ this.shouldShowCollectionInfoModal = true;
265
+ this.collectionInfo = null;
266
+ const { info } = await api.Model.getCollectionInfo({ model: this.currentModel });
267
+ this.collectionInfo = info;
268
+ },
269
+ async findOldestDocument() {
270
+ this.closeActionsMenu();
271
+ const { docs } = await api.Model.getDocuments({
272
+ model: this.currentModel,
273
+ limit: 1,
274
+ sortKey: '_id',
275
+ sortDirection: 1
276
+ });
277
+ if (!Array.isArray(docs) || docs.length === 0) {
278
+ throw new Error('No documents found');
279
+ }
280
+ this.openDocument(docs[0]);
281
+ },
240
282
  isTTLIndex(index) {
241
283
  return index != null && index.expireAfterSeconds != null;
242
284
  },
@@ -269,6 +311,35 @@ module.exports = app => app.component('models', {
269
311
 
270
312
  return parts.join(', ');
271
313
  },
314
+ formatCollectionSize(size) {
315
+ if (typeof size !== 'number') {
316
+ return 'Unknown';
317
+ }
318
+
319
+ const KB = 1024;
320
+ const MB = KB * 1024;
321
+ const GB = MB * 1024;
322
+ const TB = GB * 1024;
323
+
324
+ if (size >= TB) {
325
+ return `${(size / TB).toFixed(3)} TB`;
326
+ } else if (size >= GB) {
327
+ return `${(size / GB).toFixed(3)} GB`;
328
+ } else if (size >= MB) {
329
+ return `${(size / MB).toFixed(3)} MB`;
330
+ } else if (size >= KB) {
331
+ return `${(size / KB).toFixed(3)} KB`;
332
+ } else {
333
+ return `${size.toLocaleString()} bytes`;
334
+ }
335
+ },
336
+ formatNumber(value) {
337
+ if (typeof value !== 'number') {
338
+ return 'Unknown';
339
+ }
340
+
341
+ return value.toLocaleString();
342
+ },
272
343
  checkIndexLocation(indexName) {
273
344
  if (this.schemaIndexes.find(x => x.name == indexName) && this.mongoDBIndexes.find(x => x.name == indexName)) {
274
345
  return 'text-gray-500';
@@ -442,6 +513,7 @@ module.exports = app => app.component('models', {
442
513
  this.documents[index] = res.doc;
443
514
  }
444
515
  this.edittingDoc = null;
516
+ this.$toast.success('Document updated!');
445
517
  },
446
518
  handleDocumentClick(document, event) {
447
519
  if (this.selectMultiple) {
@@ -505,6 +577,7 @@ module.exports = app => app.component('models', {
505
577
  this.lastSelectedIndex = null;
506
578
  this.shouldShowDeleteMultipleModal = false;
507
579
  this.selectMultiple = false;
580
+ this.$toast.success('Documents deleted!');
508
581
  },
509
582
  async updateDocuments() {
510
583
  await this.getDocuments();
@@ -28,35 +28,29 @@ module.exports = app => app.component('update-document', {
28
28
  methods: {
29
29
  async updateDocument() {
30
30
  const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
31
- if (this.multiple) {
32
- const ids = this.document.map(x => x._id);
33
- await api.Model.updateDocuments({ model: this.currentModel, _id: ids, update: data }).catch(err => {
34
- if (err.response?.data?.message) {
35
- console.log(err.response.data);
36
- const message = err.response.data.message.split(': ').slice(1).join(': ');
37
- this.errors = message.split(',').map(error => {
38
- return error.split(': ').slice(1).join(': ').trim();
39
- });
40
- throw new Error(err.response?.data?.message);
41
- }
42
- throw err;
43
- });
44
- } else {
45
- await api.Model.updateDocument({ model: this.currentModel, _id: this.document._id, update: data }).catch(err => {
46
- if (err.response?.data?.message) {
47
- console.log(err.response.data);
48
- const message = err.response.data.message.split(': ').slice(1).join(': ');
49
- this.errors = message.split(',').map(error => {
50
- return error.split(': ').slice(1).join(': ').trim();
51
- });
52
- throw new Error(err.response?.data?.message);
53
- }
54
- throw err;
31
+ try {
32
+ if (this.multiple) {
33
+ const ids = this.document.map(x => x._id);
34
+ await api.Model.updateDocuments({ model: this.currentModel, _id: ids, update: data });
35
+ } else {
36
+ await api.Model.updateDocument({ model: this.currentModel, _id: this.document._id, update: data });
37
+ }
38
+ this.errors.length = 0;
39
+ this.$emit('update');
40
+ this.$emit('close');
41
+ this.$nextTick(() => {
42
+ this.$toast.success(this.multiple ? 'Documents updated!' : 'Document updated!');
55
43
  });
44
+ } catch (err) {
45
+ if (err.response?.data?.message) {
46
+ console.log(err.response.data);
47
+ const message = err.response.data.message.split(': ').slice(1).join(': ');
48
+ this.errors = message.split(',').map(error => {
49
+ return error.split(': ').slice(1).join(': ').trim();
50
+ });
51
+ }
52
+ throw err;
56
53
  }
57
- this.errors.length = 0;
58
- this.$emit('update');
59
- this.$emit('close');
60
54
  }
61
55
  },
62
56
  mounted: function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mongoosejs/studio",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
5
5
  "homepage": "https://studio.mongoosejs.io/",
6
6
  "repository": {
@@ -9,9 +9,9 @@
9
9
  },
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
+ "@ai-sdk/anthropic": "2.x",
12
13
  "@ai-sdk/google": "2.x",
13
14
  "@ai-sdk/openai": "2.x",
14
- "@ai-sdk/anthropic": "2.x",
15
15
  "ai": "5.x",
16
16
  "archetype": "0.13.1",
17
17
  "csv-stringify": "6.3.0",
@@ -20,8 +20,8 @@
20
20
  "marked": "15.0.12",
21
21
  "node-inspect-extracted": "3.x",
22
22
  "tailwindcss": "3.4.0",
23
- "vanillatoasts": "^1.6.0",
24
23
  "vue": "3.x",
24
+ "vue-toastification": "^2.0.0-rc.5",
25
25
  "webpack": "5.x"
26
26
  },
27
27
  "peerDependencies": {