@mongoosejs/studio 0.1.17 → 0.1.18

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.
@@ -3,6 +3,7 @@
3
3
  const api = require('../api');
4
4
  const template = require('./models.html');
5
5
  const mpath = require('mpath');
6
+ const vanillatoasts = require('vanillatoasts');
6
7
 
7
8
  const appendCSS = require('../appendCSS');
8
9
  appendCSS(require('./models.css'));
@@ -34,6 +35,7 @@ module.exports = app => app.component('models', {
34
35
  shouldShowCreateModal: false,
35
36
  shouldShowFieldModal: false,
36
37
  shouldShowIndexModal: false,
38
+ shouldShowCollectionInfoModal: false,
37
39
  shouldShowUpdateMultipleModal: false,
38
40
  shouldShowDeleteMultipleModal: false,
39
41
  shouldExport: {},
@@ -44,7 +46,9 @@ module.exports = app => app.component('models', {
44
46
  outputType: 'table', // json, table
45
47
  hideSidebar: null,
46
48
  lastSelectedIndex: null,
47
- error: null
49
+ error: null,
50
+ showActionsMenu: false,
51
+ collectionInfo: null
48
52
  }),
49
53
  created() {
50
54
  this.currentModel = this.model;
@@ -53,12 +57,23 @@ module.exports = app => app.component('models', {
53
57
  beforeDestroy() {
54
58
  document.removeEventListener('scroll', this.onScroll, true);
55
59
  window.removeEventListener('popstate', this.onPopState, true);
60
+ document.removeEventListener('click', this.onOutsideActionsMenuClick, true);
56
61
  },
57
62
  async mounted() {
58
63
  this.onScroll = () => this.checkIfScrolledToBottom();
59
64
  document.addEventListener('scroll', this.onScroll, true);
60
65
  this.onPopState = () => this.initSearchFromUrl();
61
66
  window.addEventListener('popstate', this.onPopState, true);
67
+ this.onOutsideActionsMenuClick = event => {
68
+ if (!this.showActionsMenu) {
69
+ return;
70
+ }
71
+ const actionsMenu = this.$refs.actionsMenuContainer;
72
+ if (actionsMenu && !actionsMenu.contains(event.target)) {
73
+ this.closeActionsMenu();
74
+ }
75
+ };
76
+ document.addEventListener('click', this.onOutsideActionsMenuClick, true);
62
77
  const { models, readyState } = await api.Model.listModels();
63
78
  this.models = models;
64
79
  if (this.currentModel == null && this.models.length > 0) {
@@ -160,6 +175,13 @@ module.exports = app => app.component('models', {
160
175
  async dropIndex(name) {
161
176
  const { mongoDBIndexes } = await api.Model.dropIndex({ model: this.currentModel, name });
162
177
  this.mongoDBIndexes = mongoDBIndexes;
178
+ vanillatoasts.create({
179
+ title: 'Index dropped!',
180
+ type: 'success',
181
+ timeout: 3000,
182
+ icon: 'images/success.png',
183
+ positionClass: 'bottomRight'
184
+ });
163
185
  },
164
186
  async closeCreationModal() {
165
187
  this.shouldShowCreateModal = false;
@@ -232,11 +254,25 @@ module.exports = app => app.component('models', {
232
254
  }
233
255
  },
234
256
  async openIndexModal() {
257
+ this.closeActionsMenu();
235
258
  this.shouldShowIndexModal = true;
236
259
  const { mongoDBIndexes, schemaIndexes } = await api.Model.getIndexes({ model: this.currentModel });
237
260
  this.mongoDBIndexes = mongoDBIndexes;
238
261
  this.schemaIndexes = schemaIndexes;
239
262
  },
263
+ toggleActionsMenu() {
264
+ this.showActionsMenu = !this.showActionsMenu;
265
+ },
266
+ closeActionsMenu() {
267
+ this.showActionsMenu = false;
268
+ },
269
+ async openCollectionInfo() {
270
+ this.closeActionsMenu();
271
+ this.shouldShowCollectionInfoModal = true;
272
+ this.collectionInfo = null;
273
+ const { info } = await api.Model.getCollectionInfo({ model: this.currentModel });
274
+ this.collectionInfo = info;
275
+ },
240
276
  isTTLIndex(index) {
241
277
  return index != null && index.expireAfterSeconds != null;
242
278
  },
@@ -269,6 +305,35 @@ module.exports = app => app.component('models', {
269
305
 
270
306
  return parts.join(', ');
271
307
  },
308
+ formatCollectionSize(size) {
309
+ if (typeof size !== 'number') {
310
+ return 'Unknown';
311
+ }
312
+
313
+ const KB = 1024;
314
+ const MB = KB * 1024;
315
+ const GB = MB * 1024;
316
+ const TB = GB * 1024;
317
+
318
+ if (size >= TB) {
319
+ return `${(size / TB).toFixed(3)} TB`;
320
+ } else if (size >= GB) {
321
+ return `${(size / GB).toFixed(3)} GB`;
322
+ } else if (size >= MB) {
323
+ return `${(size / MB).toFixed(3)} MB`;
324
+ } else if (size >= KB) {
325
+ return `${(size / KB).toFixed(3)} KB`;
326
+ } else {
327
+ return `${size.toLocaleString()} bytes`;
328
+ }
329
+ },
330
+ formatNumber(value) {
331
+ if (typeof value !== 'number') {
332
+ return 'Unknown';
333
+ }
334
+
335
+ return value.toLocaleString();
336
+ },
272
337
  checkIndexLocation(indexName) {
273
338
  if (this.schemaIndexes.find(x => x.name == indexName) && this.mongoDBIndexes.find(x => x.name == indexName)) {
274
339
  return 'text-gray-500';
@@ -442,6 +507,13 @@ module.exports = app => app.component('models', {
442
507
  this.documents[index] = res.doc;
443
508
  }
444
509
  this.edittingDoc = null;
510
+ vanillatoasts.create({
511
+ title: 'Document updated!',
512
+ type: 'success',
513
+ timeout: 3000,
514
+ icon: 'images/success.png',
515
+ positionClass: 'bottomRight'
516
+ });
445
517
  },
446
518
  handleDocumentClick(document, event) {
447
519
  if (this.selectMultiple) {
@@ -505,6 +577,13 @@ module.exports = app => app.component('models', {
505
577
  this.lastSelectedIndex = null;
506
578
  this.shouldShowDeleteMultipleModal = false;
507
579
  this.selectMultiple = false;
580
+ vanillatoasts.create({
581
+ title: 'Documents deleted!',
582
+ type: 'success',
583
+ timeout: 3000,
584
+ icon: 'images/success.png',
585
+ positionClass: 'bottomRight'
586
+ });
508
587
  },
509
588
  async updateDocuments() {
510
589
  await this.getDocuments();
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const api = require('../api');
4
+ const vanillatoasts = require('vanillatoasts');
4
5
 
5
6
  const { BSON, EJSON } = require('mongodb/lib/bson');
6
7
 
@@ -28,35 +29,35 @@ module.exports = app => app.component('update-document', {
28
29
  methods: {
29
30
  async updateDocument() {
30
31
  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;
32
+ try {
33
+ if (this.multiple) {
34
+ const ids = this.document.map(x => x._id);
35
+ await api.Model.updateDocuments({ model: this.currentModel, _id: ids, update: data });
36
+ } else {
37
+ await api.Model.updateDocument({ model: this.currentModel, _id: this.document._id, update: data });
38
+ }
39
+ this.errors.length = 0;
40
+ this.$emit('update');
41
+ this.$emit('close');
42
+ this.$nextTick(() => {
43
+ vanillatoasts.create({
44
+ title: this.multiple ? 'Documents updated!' : 'Document updated!',
45
+ type: 'success',
46
+ timeout: 3000,
47
+ icon: 'images/success.png',
48
+ positionClass: 'bottomRight'
49
+ });
55
50
  });
51
+ } catch (err) {
52
+ if (err.response?.data?.message) {
53
+ console.log(err.response.data);
54
+ const message = err.response.data.message.split(': ').slice(1).join(': ');
55
+ this.errors = message.split(',').map(error => {
56
+ return error.split(': ').slice(1).join(': ').trim();
57
+ });
58
+ }
59
+ throw err;
56
60
  }
57
- this.errors.length = 0;
58
- this.$emit('update');
59
- this.$emit('close');
60
61
  }
61
62
  },
62
63
  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.18",
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": {