@mongoosejs/studio 0.1.16 → 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.
Files changed (36) hide show
  1. package/backend/actions/Model/getCollectionInfo.js +49 -0
  2. package/backend/actions/Model/index.js +1 -0
  3. package/backend/actions/Model/updateDocument.js +3 -0
  4. package/backend/actions/Model/updateDocuments.js +3 -0
  5. package/frontend/public/app.js +954 -524
  6. package/frontend/public/tw.css +105 -19
  7. package/frontend/src/api.js +7 -1
  8. package/frontend/src/array-utils.js +66 -0
  9. package/frontend/src/chat/chat-message/chat-message.js +7 -0
  10. package/frontend/src/chat/chat-message-script/chat-message-script.js +21 -0
  11. package/frontend/src/chat/chat.js +22 -0
  12. package/frontend/src/clone-document/clone-document.js +14 -5
  13. package/frontend/src/create-dashboard/create-dashboard.js +8 -0
  14. package/frontend/src/create-document/create-document.js +14 -5
  15. package/frontend/src/dashboard/dashboard.js +9 -1
  16. package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +8 -0
  17. package/frontend/src/dashboards/dashboards.js +8 -0
  18. package/frontend/src/detail-array/detail-array.html +25 -3
  19. package/frontend/src/detail-array/detail-array.js +22 -6
  20. package/frontend/src/document/document.js +32 -20
  21. package/frontend/src/document-details/document-details.html +61 -12
  22. package/frontend/src/document-details/document-details.js +29 -13
  23. package/frontend/src/document-details/document-property/document-property.html +41 -3
  24. package/frontend/src/document-details/document-property/document-property.js +47 -2
  25. package/frontend/src/edit-array/edit-array.html +5 -2
  26. package/frontend/src/edit-array/edit-array.js +79 -23
  27. package/frontend/src/export-query-results/export-query-results.js +8 -1
  28. package/frontend/src/index.js +2 -1
  29. package/frontend/src/list-array/list-array.html +1 -1
  30. package/frontend/src/list-array/list-array.js +0 -2
  31. package/frontend/src/models/models.html +76 -8
  32. package/frontend/src/models/models.js +112 -1
  33. package/frontend/src/update-document/update-document.js +28 -27
  34. package/package.json +1 -1
  35. package/frontend/src/edit-array/edit-array.css +0 -3
  36. package/frontend/src/list-array/list-array.css +0 -8
@@ -631,6 +631,14 @@ video {
631
631
  bottom: 0px;
632
632
  }
633
633
 
634
+ .-left-2 {
635
+ left: -0.5rem;
636
+ }
637
+
638
+ .-left-3 {
639
+ left: -0.75rem;
640
+ }
641
+
634
642
  .left-0 {
635
643
  left: 0px;
636
644
  }
@@ -659,6 +667,10 @@ video {
659
667
  top: 0.25rem;
660
668
  }
661
669
 
670
+ .top-1\/2 {
671
+ top: 50%;
672
+ }
673
+
662
674
  .top-2 {
663
675
  top: 0.5rem;
664
676
  }
@@ -769,6 +781,10 @@ video {
769
781
  margin-bottom: 0.25rem;
770
782
  }
771
783
 
784
+ .mb-1\.5 {
785
+ margin-bottom: 0.375rem;
786
+ }
787
+
772
788
  .mb-2 {
773
789
  margin-bottom: 0.5rem;
774
790
  }
@@ -984,6 +1000,10 @@ video {
984
1000
  max-height: 50vh;
985
1001
  }
986
1002
 
1003
+ .max-h-\[6\.5em\] {
1004
+ max-height: 6.5em;
1005
+ }
1006
+
987
1007
  .min-h-0 {
988
1008
  min-height: 0px;
989
1009
  }
@@ -1072,6 +1092,10 @@ video {
1072
1092
  min-width: 140px;
1073
1093
  }
1074
1094
 
1095
+ .min-w-\[80px\] {
1096
+ min-width: 80px;
1097
+ }
1098
+
1075
1099
  .min-w-full {
1076
1100
  min-width: 100%;
1077
1101
  }
@@ -1080,6 +1104,10 @@ video {
1080
1104
  max-width: 64rem;
1081
1105
  }
1082
1106
 
1107
+ .max-w-\[30em\] {
1108
+ max-width: 30em;
1109
+ }
1110
+
1083
1111
  .max-w-\[calc\(100vw-3rem\)\] {
1084
1112
  max-width: calc(100vw - 3rem);
1085
1113
  }
@@ -1128,6 +1156,11 @@ video {
1128
1156
  transform-origin: top right;
1129
1157
  }
1130
1158
 
1159
+ .-translate-y-1\/2 {
1160
+ --tw-translate-y: -50%;
1161
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1162
+ }
1163
+
1131
1164
  .translate-x-0 {
1132
1165
  --tw-translate-x: 0px;
1133
1166
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -1293,6 +1326,12 @@ video {
1293
1326
  margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
1294
1327
  }
1295
1328
 
1329
+ .space-y-3 > :not([hidden]) ~ :not([hidden]) {
1330
+ --tw-space-y-reverse: 0;
1331
+ margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
1332
+ margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
1333
+ }
1334
+
1296
1335
  .space-y-4 > :not([hidden]) ~ :not([hidden]) {
1297
1336
  --tw-space-y-reverse: 0;
1298
1337
  margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
@@ -1454,6 +1493,10 @@ video {
1454
1493
  border-bottom-width: 2px;
1455
1494
  }
1456
1495
 
1496
+ .border-l-\[3px\] {
1497
+ border-left-width: 3px;
1498
+ }
1499
+
1457
1500
  .border-r {
1458
1501
  border-right-width: 1px;
1459
1502
  }
@@ -1470,11 +1513,6 @@ video {
1470
1513
  border-style: none;
1471
1514
  }
1472
1515
 
1473
- .border-amber-400 {
1474
- --tw-border-opacity: 1;
1475
- border-color: rgb(251 191 36 / var(--tw-border-opacity));
1476
- }
1477
-
1478
1516
  .border-blue-300 {
1479
1517
  --tw-border-opacity: 1;
1480
1518
  border-color: rgb(147 197 253 / var(--tw-border-opacity));
@@ -1514,11 +1552,21 @@ video {
1514
1552
  border-color: rgb(63 83 255 / var(--tw-border-opacity));
1515
1553
  }
1516
1554
 
1555
+ .border-l-blue-500 {
1556
+ --tw-border-opacity: 1;
1557
+ border-left-color: rgb(59 130 246 / var(--tw-border-opacity));
1558
+ }
1559
+
1517
1560
  .bg-amber-100 {
1518
1561
  --tw-bg-opacity: 1;
1519
1562
  background-color: rgb(254 243 199 / var(--tw-bg-opacity));
1520
1563
  }
1521
1564
 
1565
+ .bg-amber-200 {
1566
+ --tw-bg-opacity: 1;
1567
+ background-color: rgb(253 230 138 / var(--tw-bg-opacity));
1568
+ }
1569
+
1522
1570
  .bg-black {
1523
1571
  --tw-bg-opacity: 1;
1524
1572
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1644,11 +1692,6 @@ video {
1644
1692
  background-color: rgb(220 38 38 / var(--tw-bg-opacity));
1645
1693
  }
1646
1694
 
1647
- .bg-slate-50 {
1648
- --tw-bg-opacity: 1;
1649
- background-color: rgb(248 250 252 / var(--tw-bg-opacity));
1650
- }
1651
-
1652
1695
  .bg-slate-500 {
1653
1696
  --tw-bg-opacity: 1;
1654
1697
  background-color: rgb(100 116 139 / var(--tw-bg-opacity));
@@ -1776,6 +1819,11 @@ video {
1776
1819
  padding-bottom: 0.5rem;
1777
1820
  }
1778
1821
 
1822
+ .py-2\.5 {
1823
+ padding-top: 0.625rem;
1824
+ padding-bottom: 0.625rem;
1825
+ }
1826
+
1779
1827
  .py-3 {
1780
1828
  padding-top: 0.75rem;
1781
1829
  padding-bottom: 0.75rem;
@@ -1890,6 +1938,10 @@ video {
1890
1938
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1891
1939
  }
1892
1940
 
1941
+ .text-\[10px\] {
1942
+ font-size: 10px;
1943
+ }
1944
+
1893
1945
  .text-base {
1894
1946
  font-size: 1rem;
1895
1947
  line-height: 1.5rem;
@@ -2143,6 +2195,10 @@ video {
2143
2195
  opacity: 0.5;
2144
2196
  }
2145
2197
 
2198
+ .opacity-70 {
2199
+ opacity: 0.7;
2200
+ }
2201
+
2146
2202
  .opacity-75 {
2147
2203
  opacity: 0.75;
2148
2204
  }
@@ -2206,11 +2262,6 @@ video {
2206
2262
  --tw-ring-inset: inset;
2207
2263
  }
2208
2264
 
2209
- .ring-amber-200 {
2210
- --tw-ring-opacity: 1;
2211
- --tw-ring-color: rgb(253 230 138 / var(--tw-ring-opacity));
2212
- }
2213
-
2214
2265
  .ring-black {
2215
2266
  --tw-ring-opacity: 1;
2216
2267
  --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
@@ -2241,10 +2292,6 @@ video {
2241
2292
  --tw-ring-opacity: 0.05;
2242
2293
  }
2243
2294
 
2244
- .ring-offset-1 {
2245
- --tw-ring-offset-width: 1px;
2246
- }
2247
-
2248
2295
  .filter {
2249
2296
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
2250
2297
  }
@@ -2307,6 +2354,10 @@ video {
2307
2354
  color: rgb(156 163 175 / var(--tw-text-opacity));
2308
2355
  }
2309
2356
 
2357
+ .last\:mb-0:last-child {
2358
+ margin-bottom: 0px;
2359
+ }
2360
+
2310
2361
  .focus-within\:ring-2:focus-within {
2311
2362
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
2312
2363
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@@ -2322,6 +2373,16 @@ video {
2322
2373
  --tw-ring-color: rgb(0 168 165 / var(--tw-ring-opacity));
2323
2374
  }
2324
2375
 
2376
+ .hover\:-translate-y-0:hover {
2377
+ --tw-translate-y: -0px;
2378
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2379
+ }
2380
+
2381
+ .hover\:-translate-y-0\.5:hover {
2382
+ --tw-translate-y: -0.125rem;
2383
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2384
+ }
2385
+
2325
2386
  .hover\:translate-x-0:hover {
2326
2387
  --tw-translate-x: 0px;
2327
2388
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -2337,6 +2398,16 @@ video {
2337
2398
  border-color: rgb(209 213 219 / var(--tw-border-opacity));
2338
2399
  }
2339
2400
 
2401
+ .hover\:border-l-blue-600:hover {
2402
+ --tw-border-opacity: 1;
2403
+ border-left-color: rgb(37 99 235 / var(--tw-border-opacity));
2404
+ }
2405
+
2406
+ .hover\:bg-amber-200:hover {
2407
+ --tw-bg-opacity: 1;
2408
+ background-color: rgb(253 230 138 / var(--tw-bg-opacity));
2409
+ }
2410
+
2340
2411
  .hover\:bg-blue-600:hover {
2341
2412
  --tw-bg-opacity: 1;
2342
2413
  background-color: rgb(37 99 235 / var(--tw-bg-opacity));
@@ -2442,6 +2513,11 @@ video {
2442
2513
  background-color: rgb(148 163 184 / var(--tw-bg-opacity));
2443
2514
  }
2444
2515
 
2516
+ .hover\:bg-slate-50:hover {
2517
+ --tw-bg-opacity: 1;
2518
+ background-color: rgb(248 250 252 / var(--tw-bg-opacity));
2519
+ }
2520
+
2445
2521
  .hover\:bg-slate-500:hover {
2446
2522
  --tw-bg-opacity: 1;
2447
2523
  background-color: rgb(100 116 139 / var(--tw-bg-opacity));
@@ -2502,6 +2578,16 @@ video {
2502
2578
  color: rgb(6 14 172 / var(--tw-text-opacity));
2503
2579
  }
2504
2580
 
2581
+ .hover\:opacity-100:hover {
2582
+ opacity: 1;
2583
+ }
2584
+
2585
+ .hover\:shadow-lg:hover {
2586
+ --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
2587
+ --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
2588
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
2589
+ }
2590
+
2505
2591
  .focus\:z-10:focus {
2506
2592
  z-index: 10;
2507
2593
  }
@@ -21,7 +21,7 @@ client.interceptors.request.use(req => {
21
21
  client.interceptors.response.use(
22
22
  res => res,
23
23
  err => {
24
- if (typeof err.response.data === 'string') {
24
+ if (typeof err?.response?.data === 'string') {
25
25
  throw new Error(`Error in ${err.config?.method} ${err.config?.url}: ${err.response.data}`);
26
26
  }
27
27
  throw err;
@@ -132,6 +132,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
132
132
  yield { document: doc };
133
133
  }
134
134
  },
135
+ getCollectionInfo: function getCollectionInfo(params) {
136
+ return client.post('', { action: 'Model.getCollectionInfo', ...params }).then(res => res.data);
137
+ },
135
138
  getIndexes: function getIndexes(params) {
136
139
  return client.post('', { action: 'Model.getIndexes', ...params }).then(res => res.data);
137
140
  },
@@ -338,6 +341,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
338
341
  }
339
342
  }
340
343
  },
344
+ getCollectionInfo: function getCollectionInfo(params) {
345
+ return client.post('/Model/getCollectionInfo', params).then(res => res.data);
346
+ },
341
347
  getIndexes: function getIndexes(params) {
342
348
  return client.post('/Model/getIndexes', params).then(res => res.data);
343
349
  },
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ const { inspect } = require('node-inspect-extracted');
4
+
5
+ /**
6
+ * Format a value for display in array views
7
+ * @param {*} item - The item to format
8
+ * @returns {string} - Formatted string representation
9
+ */
10
+ function formatValue(item) {
11
+ if (item == null) {
12
+ return 'null';
13
+ }
14
+ if (typeof item === 'object') {
15
+ return inspect(item, { maxArrayLength: 50 });
16
+ }
17
+ return String(item);
18
+ }
19
+
20
+ /**
21
+ * Check if an item is a plain object (not array, not null)
22
+ * @param {*} item - The item to check
23
+ * @returns {boolean} - True if item is a plain object
24
+ */
25
+ function isObjectItem(item) {
26
+ return item != null && typeof item === 'object' && !Array.isArray(item) && item.constructor === Object;
27
+ }
28
+
29
+ /**
30
+ * Get the keys of an object item
31
+ * @param {*} item - The item to get keys from
32
+ * @returns {string[]} - Array of keys, or empty array if not an object
33
+ */
34
+ function getItemKeys(item) {
35
+ if (!isObjectItem(item)) {
36
+ return [];
37
+ }
38
+ return Object.keys(item);
39
+ }
40
+
41
+ /**
42
+ * Format a specific value from an object item by key
43
+ * @param {*} item - The object item
44
+ * @param {string} key - The key to get the value for
45
+ * @returns {string} - Formatted string representation of the value
46
+ */
47
+ function formatItemValue(item, key) {
48
+ const value = item[key];
49
+ if (value === null) {
50
+ return 'null';
51
+ }
52
+ if (value === undefined) {
53
+ return 'undefined';
54
+ }
55
+ if (typeof value === 'object') {
56
+ return inspect(value, { maxArrayLength: 50 });
57
+ }
58
+ return String(value);
59
+ }
60
+
61
+ module.exports = {
62
+ formatValue,
63
+ isObjectItem,
64
+ getItemKeys,
65
+ formatItemValue
66
+ };
@@ -62,6 +62,13 @@ module.exports = app => app.component('chat-message', {
62
62
  });
63
63
  message.executionResult = chatMessage.executionResult;
64
64
  console.log(message);
65
+ vanillatoasts.create({
66
+ title: 'Script executed successfully!',
67
+ type: 'success',
68
+ timeout: 3000,
69
+ icon: 'images/success.png',
70
+ positionClass: 'bottomRight'
71
+ });
65
72
  },
66
73
  async copyMessage() {
67
74
  const parts = this.contentSplitByScripts;
@@ -56,6 +56,13 @@ module.exports = app => app.component('chat-message-script', {
56
56
  this.highlightCode();
57
57
  }
58
58
  this.activeTab = 'output';
59
+ vanillatoasts.create({
60
+ title: 'Script executed successfully!',
61
+ type: 'success',
62
+ timeout: 3000,
63
+ icon: 'images/success.png',
64
+ positionClass: 'bottomRight'
65
+ });
59
66
  return chatMessage;
60
67
  },
61
68
  openDetailModal() {
@@ -157,6 +164,13 @@ module.exports = app => app.component('chat-message-script', {
157
164
  throw err;
158
165
  });
159
166
  this.createError = null;
167
+ vanillatoasts.create({
168
+ title: 'Dashboard created!',
169
+ type: 'success',
170
+ timeout: 3000,
171
+ icon: 'images/success.png',
172
+ positionClass: 'bottomRight'
173
+ });
160
174
  this.showCreateDashboardModal = false;
161
175
  this.$router.push('/dashboard/' + dashboard._id);
162
176
  },
@@ -183,6 +197,13 @@ module.exports = app => app.component('chat-message-script', {
183
197
  });
184
198
 
185
199
  this.overwriteError = null;
200
+ vanillatoasts.create({
201
+ title: 'Dashboard updated!',
202
+ type: 'success',
203
+ timeout: 3000,
204
+ icon: 'images/success.png',
205
+ positionClass: 'bottomRight'
206
+ });
186
207
  this.showOverwriteDashboardConfirmationModal = false;
187
208
  this.$router.push('/dashboard/' + doc._id);
188
209
  },
@@ -28,6 +28,13 @@ module.exports = app => app.component('chat', {
28
28
  this.chatThreads.unshift(chatThread);
29
29
  this.chatThreadId = chatThread._id;
30
30
  this.chatMessages = [];
31
+ vanillatoasts.create({
32
+ title: 'Chat thread created!',
33
+ type: 'success',
34
+ timeout: 3000,
35
+ icon: 'images/success.png',
36
+ positionClass: 'bottomRight'
37
+ });
31
38
  }
32
39
 
33
40
  this.chatMessages.push({
@@ -121,6 +128,13 @@ module.exports = app => app.component('chat', {
121
128
  },
122
129
  async createNewThread() {
123
130
  const { chatThread } = await api.ChatThread.createChatThread();
131
+ vanillatoasts.create({
132
+ title: 'Chat thread created!',
133
+ type: 'success',
134
+ timeout: 3000,
135
+ icon: 'images/success.png',
136
+ positionClass: 'bottomRight'
137
+ });
124
138
  this.$router.push('/chat/' + chatThread._id);
125
139
  },
126
140
  async toggleShareThread() {
@@ -136,6 +150,14 @@ module.exports = app => app.component('chat', {
136
150
  this.chatThreads.splice(idx, 1, chatThread);
137
151
  }
138
152
 
153
+ vanillatoasts.create({
154
+ title: 'Chat thread shared!',
155
+ type: 'success',
156
+ timeout: 3000,
157
+ icon: 'images/success.png',
158
+ positionClass: 'bottomRight'
159
+ });
160
+
139
161
  // Copy current URL to clipboard and show a toast
140
162
  const url = window.location.href;
141
163
  await navigator.clipboard.writeText(url);
@@ -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
 
@@ -29,19 +30,27 @@ module.exports = app => app.component('clone-document', {
29
30
  methods: {
30
31
  async cloneDocument() {
31
32
  const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
32
- const { doc } = await api.Model.createDocument({ model: this.currentModel, data }).catch(err => {
33
+ try {
34
+ const { doc } = await api.Model.createDocument({ model: this.currentModel, data });
35
+ this.errors.length = 0;
36
+ vanillatoasts.create({
37
+ title: 'Document cloned!',
38
+ type: 'success',
39
+ timeout: 3000,
40
+ icon: 'images/success.png',
41
+ positionClass: 'bottomRight'
42
+ });
43
+ this.$emit('close', doc);
44
+ } catch (err) {
33
45
  if (err.response?.data?.message) {
34
46
  console.log(err.response.data);
35
47
  const message = err.response.data.message.split(': ').slice(1).join(': ');
36
48
  this.errors = message.split(',').map(error => {
37
49
  return error.split(': ').slice(1).join(': ').trim();
38
50
  });
39
- throw new Error(err.response?.data?.message);
40
51
  }
41
52
  throw err;
42
- });
43
- this.errors.length = 0;
44
- this.$emit('close', doc);
53
+ }
45
54
  }
46
55
  },
47
56
  mounted: function() {
@@ -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 template = require('./create-dashboard.html');
6
7
 
@@ -28,6 +29,13 @@ module.exports = app => app.component('create-dashboard', {
28
29
  throw err;
29
30
  });
30
31
  this.errors.length = 0;
32
+ vanillatoasts.create({
33
+ title: 'Dashboard created!',
34
+ type: 'success',
35
+ timeout: 3000,
36
+ icon: 'images/success.png',
37
+ positionClass: 'bottomRight'
38
+ });
31
39
  this.$emit('close', dashboard);
32
40
  }
33
41
  },
@@ -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
 
@@ -29,19 +30,27 @@ module.exports = app => app.component('create-document', {
29
30
  methods: {
30
31
  async createDocument() {
31
32
  const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
32
- const { doc } = await api.Model.createDocument({ model: this.currentModel, data }).catch(err => {
33
+ try {
34
+ const { doc } = await api.Model.createDocument({ model: this.currentModel, data });
35
+ this.errors.length = 0;
36
+ vanillatoasts.create({
37
+ title: 'Document created!',
38
+ type: 'success',
39
+ timeout: 3000,
40
+ icon: 'images/success.png',
41
+ positionClass: 'bottomRight'
42
+ });
43
+ this.$emit('close', doc);
44
+ } catch (err) {
33
45
  if (err.response?.data?.message) {
34
46
  console.log(err.response.data);
35
47
  const message = err.response.data.message.split(': ').slice(1).join(': ');
36
48
  this.errors = message.split(',').map(error => {
37
49
  return error.split(': ').slice(1).join(': ').trim();
38
50
  });
39
- throw new Error(err.response?.data?.message);
40
51
  }
41
52
  throw err;
42
- });
43
- this.errors.length = 0;
44
- this.$emit('close', doc);
53
+ }
45
54
  }
46
55
  },
47
56
  mounted: function() {
@@ -2,6 +2,7 @@
2
2
 
3
3
  const api = require('../api');
4
4
  const template = require('./dashboard.html');
5
+ const vanillatoasts = require('vanillatoasts');
5
6
 
6
7
  module.exports = app => app.component('dashboard', {
7
8
  template: template,
@@ -109,6 +110,13 @@ module.exports = app => app.component('dashboard', {
109
110
  initialMessage,
110
111
  dashboardId: this.dashboard?._id
111
112
  });
113
+ vanillatoasts.create({
114
+ title: 'Chat thread created!',
115
+ type: 'success',
116
+ timeout: 3000,
117
+ icon: 'images/success.png',
118
+ positionClass: 'bottomRight'
119
+ });
112
120
  this.$router.push('/chat/' + chatThread._id);
113
121
  } finally {
114
122
  this.startingChat = false;
@@ -141,5 +149,5 @@ module.exports = app => app.component('dashboard', {
141
149
  },
142
150
  beforeDestroy() {
143
151
  document.removeEventListener('click', this.handleDocumentClick);
144
- },
152
+ }
145
153
  });
@@ -2,6 +2,7 @@
2
2
 
3
3
  const api = require('../../api');
4
4
  const template = require('./edit-dashboard.html');
5
+ const vanillatoasts = require('vanillatoasts');
5
6
 
6
7
  module.exports = app => app.component('edit-dashboard', {
7
8
  template: template,
@@ -31,6 +32,13 @@ module.exports = app => app.component('edit-dashboard', {
31
32
  });
32
33
  this.$emit('update', { doc });
33
34
  this.editor.setValue(doc.code);
35
+ vanillatoasts.create({
36
+ title: 'Dashboard updated!',
37
+ type: 'success',
38
+ timeout: 3000,
39
+ icon: 'images/success.png',
40
+ positionClass: 'bottomRight'
41
+ });
34
42
  this.closeEditor();
35
43
  } catch (err) {
36
44
  this.$emit('update', { error: { message: err.message } });
@@ -2,6 +2,7 @@
2
2
 
3
3
  const api = require('../api');
4
4
  const template = require('./dashboards.html');
5
+ const vanillatoasts = require('vanillatoasts');
5
6
 
6
7
 
7
8
  module.exports = app => app.component('dashboards', {
@@ -21,6 +22,13 @@ module.exports = app => app.component('dashboards', {
21
22
  const removedDashboard = this.dashboards.findIndex(x => x._id.toString() === dashboard._id.toString());
22
23
  this.dashboards.splice(removedDashboard, 1);
23
24
  this.showDeleteDashboardModal = null;
25
+ vanillatoasts.create({
26
+ title: 'Dashboard deleted!',
27
+ type: 'success',
28
+ timeout: 3000,
29
+ icon: 'images/success.png',
30
+ positionClass: 'bottomRight'
31
+ });
24
32
  },
25
33
  insertNewDashboard(dashboard) {
26
34
  this.dashboards.push(dashboard);
@@ -1,3 +1,25 @@
1
- <div class="detail-array">
2
- <pre><code ref="code" class="language-javascript" v-text="displayValue"></code></pre>
3
- </div>
1
+ <div class="w-full">
2
+ <div v-if="!arrayValue || arrayValue.length === 0" class="text-gray-400 text-xs py-2 text-center">
3
+ Empty array
4
+ </div>
5
+
6
+ <div v-else class="mt-2">
7
+ <div
8
+ v-for="(item, index) in arrayValue"
9
+ :key="index"
10
+ :title="'Index: ' + index"
11
+ class="mb-1.5 last:mb-0 py-2.5 px-3 pl-4 bg-transparent border-l-[3px] border-l-blue-500 rounded-none transition-all duration-200 cursor-pointer relative hover:bg-slate-50 hover:border-l-blue-600 hover:shadow-lg hover:-translate-y-0.5">
12
+ <div class="absolute -left-3 top-1/2 -translate-y-1/2 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-[10px] font-semibold font-mono z-10 hover:bg-blue-600">{{ index >= 1000 ? '1k+' : index }}</div>
13
+ <div v-if="arrayUtils.isObjectItem(item)" class="flex flex-col gap-1 mt-1 px-2">
14
+ <div
15
+ v-for="key in arrayUtils.getItemKeys(item)"
16
+ :key="key"
17
+ class="flex items-start gap-2 text-xs font-mono">
18
+ <span class="font-semibold text-gray-600 flex-shrink-0 min-w-[80px]">{{ key }}:</span>
19
+ <span class="text-gray-800 break-words whitespace-pre-wrap flex-1">{{ arrayUtils.formatItemValue(item, key) }}</span>
20
+ </div>
21
+ </div>
22
+ <div v-else class="text-xs py-1.5 px-2 font-mono text-gray-800 break-words whitespace-pre-wrap mt-1">{{ arrayUtils.formatValue(item) }}</div>
23
+ </div>
24
+ </div>
25
+ </div>