@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.
- package/backend/actions/Model/getCollectionInfo.js +49 -0
- package/backend/actions/Model/index.js +1 -0
- package/frontend/public/app.js +15088 -480
- package/frontend/public/tw.css +6 -0
- package/frontend/src/api.js +7 -1
- package/frontend/src/chat/chat-message/chat-message.js +2 -8
- package/frontend/src/chat/chat-message-script/chat-message-script.js +4 -8
- package/frontend/src/chat/chat.js +5 -8
- package/frontend/src/clone-document/clone-document.js +7 -5
- package/frontend/src/create-dashboard/create-dashboard.js +1 -0
- package/frontend/src/create-document/create-document.js +7 -5
- package/frontend/src/dashboard/dashboard.js +1 -0
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +1 -0
- package/frontend/src/dashboards/dashboards.js +1 -0
- package/frontend/src/document/document.js +21 -29
- package/frontend/src/document-details/document-details.js +1 -13
- package/frontend/src/export-query-results/export-query-results.js +1 -1
- package/frontend/src/index.js +13 -7
- package/frontend/src/list-default/list-default.js +1 -8
- package/frontend/src/list-mixed/list-mixed.js +1 -8
- package/frontend/src/list-string/list-string.js +1 -8
- package/frontend/src/list-subdocument/list-subdocument.js +1 -8
- package/frontend/src/models/models.html +77 -7
- package/frontend/src/models/models.js +75 -2
- package/frontend/src/update-document/update-document.js +21 -27
- package/package.json +3 -3
package/frontend/public/tw.css
CHANGED
|
@@ -1326,6 +1326,12 @@ video {
|
|
|
1326
1326
|
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
|
|
1327
1327
|
}
|
|
1328
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
|
+
|
|
1329
1335
|
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
|
1330
1336
|
--tw-space-y-reverse: 0;
|
|
1331
1337
|
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
|
package/frontend/src/api.js
CHANGED
|
@@ -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
|
|
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
|
},
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const api = require('../../api');
|
|
4
4
|
const marked = require('marked').marked;
|
|
5
|
-
const vanillatoasts = require('vanillatoasts');
|
|
6
5
|
const template = require('./chat-message.html');
|
|
7
6
|
|
|
8
7
|
module.exports = app => app.component('chat-message', {
|
|
@@ -62,6 +61,7 @@ module.exports = app => app.component('chat-message', {
|
|
|
62
61
|
});
|
|
63
62
|
message.executionResult = chatMessage.executionResult;
|
|
64
63
|
console.log(message);
|
|
64
|
+
this.$toast.success('Script executed successfully!');
|
|
65
65
|
},
|
|
66
66
|
async copyMessage() {
|
|
67
67
|
const parts = this.contentSplitByScripts;
|
|
@@ -86,13 +86,7 @@ module.exports = app => app.component('chat-message', {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
await navigator.clipboard.writeText(output.trim());
|
|
89
|
-
|
|
90
|
-
title: 'Message output copied!',
|
|
91
|
-
type: 'success',
|
|
92
|
-
timeout: 3000,
|
|
93
|
-
icon: 'images/success.png',
|
|
94
|
-
positionClass: 'bottomRight'
|
|
95
|
-
});
|
|
89
|
+
this.$toast.success('Message output copied!');
|
|
96
90
|
}
|
|
97
91
|
}
|
|
98
92
|
});
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
const api = require('../../api');
|
|
5
5
|
const template = require('./chat-message-script.html');
|
|
6
|
-
const vanillatoasts = require('vanillatoasts');
|
|
7
6
|
|
|
8
7
|
module.exports = app => app.component('chat-message-script', {
|
|
9
8
|
template,
|
|
@@ -56,6 +55,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
56
55
|
this.highlightCode();
|
|
57
56
|
}
|
|
58
57
|
this.activeTab = 'output';
|
|
58
|
+
this.$toast.success('Script executed successfully!');
|
|
59
59
|
return chatMessage;
|
|
60
60
|
},
|
|
61
61
|
openDetailModal() {
|
|
@@ -157,6 +157,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
157
157
|
throw err;
|
|
158
158
|
});
|
|
159
159
|
this.createError = null;
|
|
160
|
+
this.$toast.success('Dashboard created!');
|
|
160
161
|
this.showCreateDashboardModal = false;
|
|
161
162
|
this.$router.push('/dashboard/' + dashboard._id);
|
|
162
163
|
},
|
|
@@ -183,6 +184,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
183
184
|
});
|
|
184
185
|
|
|
185
186
|
this.overwriteError = null;
|
|
187
|
+
this.$toast.success('Dashboard updated!');
|
|
186
188
|
this.showOverwriteDashboardConfirmationModal = false;
|
|
187
189
|
this.$router.push('/dashboard/' + doc._id);
|
|
188
190
|
},
|
|
@@ -203,13 +205,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
await navigator.clipboard.writeText(parts.join('\n\n'));
|
|
206
|
-
|
|
207
|
-
title: 'Code output copied!',
|
|
208
|
-
type: 'success',
|
|
209
|
-
timeout: 3000,
|
|
210
|
-
icon: 'images/success.png',
|
|
211
|
-
positionClass: 'bottomRight'
|
|
212
|
-
});
|
|
208
|
+
this.$toast.success('Code output copied!');
|
|
213
209
|
}
|
|
214
210
|
},
|
|
215
211
|
watch: {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const api = require('../api');
|
|
4
4
|
const template = require('./chat.html');
|
|
5
|
-
const vanillatoasts = require('vanillatoasts');
|
|
6
5
|
|
|
7
6
|
module.exports = app => app.component('chat', {
|
|
8
7
|
template: template,
|
|
@@ -28,6 +27,7 @@ module.exports = app => app.component('chat', {
|
|
|
28
27
|
this.chatThreads.unshift(chatThread);
|
|
29
28
|
this.chatThreadId = chatThread._id;
|
|
30
29
|
this.chatMessages = [];
|
|
30
|
+
this.$toast.success('Chat thread created!');
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
this.chatMessages.push({
|
|
@@ -121,6 +121,7 @@ module.exports = app => app.component('chat', {
|
|
|
121
121
|
},
|
|
122
122
|
async createNewThread() {
|
|
123
123
|
const { chatThread } = await api.ChatThread.createChatThread();
|
|
124
|
+
this.$toast.success('Chat thread created!');
|
|
124
125
|
this.$router.push('/chat/' + chatThread._id);
|
|
125
126
|
},
|
|
126
127
|
async toggleShareThread() {
|
|
@@ -136,16 +137,12 @@ module.exports = app => app.component('chat', {
|
|
|
136
137
|
this.chatThreads.splice(idx, 1, chatThread);
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
this.$toast.success('Chat thread shared!');
|
|
141
|
+
|
|
139
142
|
// Copy current URL to clipboard and show a toast
|
|
140
143
|
const url = window.location.href;
|
|
141
144
|
await navigator.clipboard.writeText(url);
|
|
142
|
-
|
|
143
|
-
title: 'Share link copied!',
|
|
144
|
-
type: 'success',
|
|
145
|
-
timeout: 3000,
|
|
146
|
-
icon: 'images/success.png',
|
|
147
|
-
positionClass: 'bottomRight'
|
|
148
|
-
});
|
|
145
|
+
this.$toast.success('Share link copied!');
|
|
149
146
|
} finally {
|
|
150
147
|
this.sharingThread = false;
|
|
151
148
|
}
|
|
@@ -29,19 +29,21 @@ module.exports = app => app.component('clone-document', {
|
|
|
29
29
|
methods: {
|
|
30
30
|
async cloneDocument() {
|
|
31
31
|
const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
|
|
32
|
-
|
|
32
|
+
try {
|
|
33
|
+
const { doc } = await api.Model.createDocument({ model: this.currentModel, data });
|
|
34
|
+
this.errors.length = 0;
|
|
35
|
+
this.$toast.success('Document cloned!');
|
|
36
|
+
this.$emit('close', doc);
|
|
37
|
+
} catch (err) {
|
|
33
38
|
if (err.response?.data?.message) {
|
|
34
39
|
console.log(err.response.data);
|
|
35
40
|
const message = err.response.data.message.split(': ').slice(1).join(': ');
|
|
36
41
|
this.errors = message.split(',').map(error => {
|
|
37
42
|
return error.split(': ').slice(1).join(': ').trim();
|
|
38
43
|
});
|
|
39
|
-
throw new Error(err.response?.data?.message);
|
|
40
44
|
}
|
|
41
45
|
throw err;
|
|
42
|
-
}
|
|
43
|
-
this.errors.length = 0;
|
|
44
|
-
this.$emit('close', doc);
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
48
|
},
|
|
47
49
|
mounted: function() {
|
|
@@ -29,19 +29,21 @@ module.exports = app => app.component('create-document', {
|
|
|
29
29
|
methods: {
|
|
30
30
|
async createDocument() {
|
|
31
31
|
const data = EJSON.serialize(eval(`(${this.editor.getValue()})`));
|
|
32
|
-
|
|
32
|
+
try {
|
|
33
|
+
const { doc } = await api.Model.createDocument({ model: this.currentModel, data });
|
|
34
|
+
this.errors.length = 0;
|
|
35
|
+
this.$toast.success('Document created!');
|
|
36
|
+
this.$emit('close', doc);
|
|
37
|
+
} catch (err) {
|
|
33
38
|
if (err.response?.data?.message) {
|
|
34
39
|
console.log(err.response.data);
|
|
35
40
|
const message = err.response.data.message.split(': ').slice(1).join(': ');
|
|
36
41
|
this.errors = message.split(',').map(error => {
|
|
37
42
|
return error.split(': ').slice(1).join(': ').trim();
|
|
38
43
|
});
|
|
39
|
-
throw new Error(err.response?.data?.message);
|
|
40
44
|
}
|
|
41
45
|
throw err;
|
|
42
|
-
}
|
|
43
|
-
this.errors.length = 0;
|
|
44
|
-
this.$emit('close', doc);
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
48
|
},
|
|
47
49
|
mounted: function() {
|
|
@@ -109,6 +109,7 @@ module.exports = app => app.component('dashboard', {
|
|
|
109
109
|
initialMessage,
|
|
110
110
|
dashboardId: this.dashboard?._id
|
|
111
111
|
});
|
|
112
|
+
this.$toast.success('Chat thread created!');
|
|
112
113
|
this.$router.push('/chat/' + chatThread._id);
|
|
113
114
|
} finally {
|
|
114
115
|
this.startingChat = false;
|
|
@@ -31,6 +31,7 @@ module.exports = app => app.component('edit-dashboard', {
|
|
|
31
31
|
});
|
|
32
32
|
this.$emit('update', { doc });
|
|
33
33
|
this.editor.setValue(doc.code);
|
|
34
|
+
this.$toast.success('Dashboard updated!');
|
|
34
35
|
this.closeEditor();
|
|
35
36
|
} catch (err) {
|
|
36
37
|
this.$emit('update', { error: { message: err.message } });
|
|
@@ -21,6 +21,7 @@ module.exports = app => app.component('dashboards', {
|
|
|
21
21
|
const removedDashboard = this.dashboards.findIndex(x => x._id.toString() === dashboard._id.toString());
|
|
22
22
|
this.dashboards.splice(removedDashboard, 1);
|
|
23
23
|
this.showDeleteDashboardModal = null;
|
|
24
|
+
this.$toast.success('Dashboard deleted!');
|
|
24
25
|
},
|
|
25
26
|
insertNewDashboard(dashboard) {
|
|
26
27
|
this.dashboards.push(dashboard);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const api = require('../api');
|
|
4
4
|
const mpath = require('mpath');
|
|
5
5
|
const template = require('./document.html');
|
|
6
|
-
const vanillatoast = require('vanillatoasts');
|
|
7
6
|
|
|
8
7
|
const appendCSS = require('../appendCSS');
|
|
9
8
|
|
|
@@ -32,20 +31,24 @@ module.exports = app => app.component('document', {
|
|
|
32
31
|
window.pageState = this;
|
|
33
32
|
// Store query parameters from the route (preserved from models page)
|
|
34
33
|
this.previousQuery = Object.assign({}, this.$route.query);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
try {
|
|
35
|
+
const { doc, schemaPaths, virtualPaths } = await api.Model.getDocument({ model: this.model, documentId: this.documentId });
|
|
36
|
+
window.doc = doc;
|
|
37
|
+
this.document = doc;
|
|
38
|
+
this.schemaPaths = Object.keys(schemaPaths).sort((k1, k2) => {
|
|
39
|
+
if (k1 === '_id' && k2 !== '_id') {
|
|
40
|
+
return -1;
|
|
41
|
+
}
|
|
42
|
+
if (k1 !== '_id' && k2 === '_id') {
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
return 0;
|
|
46
|
+
}).map(key => schemaPaths[key]);
|
|
47
|
+
this.virtualPaths = virtualPaths || [];
|
|
48
|
+
this.status = 'loaded';
|
|
49
|
+
} finally {
|
|
50
|
+
this.status = 'loaded';
|
|
51
|
+
}
|
|
49
52
|
},
|
|
50
53
|
computed: {
|
|
51
54
|
canManipulate() {
|
|
@@ -79,6 +82,7 @@ module.exports = app => app.component('document', {
|
|
|
79
82
|
this.changes = {};
|
|
80
83
|
this.editting = false;
|
|
81
84
|
this.shouldShowConfirmModal = false;
|
|
85
|
+
this.$toast.success('Document saved!');
|
|
82
86
|
},
|
|
83
87
|
async remove() {
|
|
84
88
|
const { doc } = await api.Model.deleteDocument({
|
|
@@ -88,12 +92,7 @@ module.exports = app => app.component('document', {
|
|
|
88
92
|
if (doc.acknowledged) {
|
|
89
93
|
this.editting = false;
|
|
90
94
|
this.document = {};
|
|
91
|
-
|
|
92
|
-
title: 'Document Deleted!',
|
|
93
|
-
type: 'success',
|
|
94
|
-
timeout: 3000,
|
|
95
|
-
positionClass: 'bottomRight'
|
|
96
|
-
});
|
|
95
|
+
this.$toast.success('Document deleted!');
|
|
97
96
|
this.$router.push({
|
|
98
97
|
path: `/model/${this.model}`,
|
|
99
98
|
query: this.previousQuery || {}
|
|
@@ -112,14 +111,7 @@ module.exports = app => app.component('document', {
|
|
|
112
111
|
});
|
|
113
112
|
this.document = doc;
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
vanillatoast.create({
|
|
117
|
-
title: 'Field Added!',
|
|
118
|
-
text: `Field "${fieldData.name}" has been added to the document`,
|
|
119
|
-
type: 'success',
|
|
120
|
-
timeout: 3000,
|
|
121
|
-
positionClass: 'bottomRight'
|
|
122
|
-
});
|
|
114
|
+
this.$toast.success(`Field added! Field "${fieldData.name}" has been added to the document`);
|
|
123
115
|
},
|
|
124
116
|
updateViewMode(mode) {
|
|
125
117
|
this.viewMode = mode;
|
|
@@ -366,7 +366,7 @@ module.exports = app => app.component('document-details', {
|
|
|
366
366
|
|
|
367
367
|
try {
|
|
368
368
|
const fieldData = {
|
|
369
|
-
name: this.
|
|
369
|
+
name: this.fieldData.name,
|
|
370
370
|
type: this.fieldData.type,
|
|
371
371
|
value: this.parseFieldValue(this.fieldData.value, this.fieldData.type)
|
|
372
372
|
};
|
|
@@ -412,18 +412,6 @@ module.exports = app => app.component('document-details', {
|
|
|
412
412
|
this.fieldValueEditor = null;
|
|
413
413
|
}
|
|
414
414
|
},
|
|
415
|
-
toSnakeCase(str) {
|
|
416
|
-
return str
|
|
417
|
-
.trim()
|
|
418
|
-
.replace(/\s+/g, '_') // Replace spaces with underscores
|
|
419
|
-
.replace(/[^a-zA-Z0-9_$]/g, '') // Remove invalid characters
|
|
420
|
-
.replace(/^[0-9]/, '_$&') // Prefix numbers with underscore
|
|
421
|
-
.toLowerCase();
|
|
422
|
-
},
|
|
423
|
-
getTransformedFieldName() {
|
|
424
|
-
if (!this.fieldData.name) return '';
|
|
425
|
-
return this.toSnakeCase(this.fieldData.name.trim());
|
|
426
|
-
},
|
|
427
415
|
getVirtualFieldType(virtual) {
|
|
428
416
|
const value = virtual.value;
|
|
429
417
|
if (value === null || value === undefined) {
|
package/frontend/src/index.js
CHANGED
|
@@ -12,12 +12,21 @@ const format = require('./format');
|
|
|
12
12
|
const arrayUtils = require('./array-utils');
|
|
13
13
|
const mothership = require('./mothership');
|
|
14
14
|
const { routes } = require('./routes');
|
|
15
|
-
const
|
|
15
|
+
const Toast = require('vue-toastification').default;
|
|
16
|
+
const { useToast } = require('vue-toastification');
|
|
17
|
+
const appendCSS = require('./appendCSS');
|
|
18
|
+
appendCSS(require('vue-toastification/dist/index.css'));
|
|
16
19
|
|
|
17
20
|
const app = Vue.createApp({
|
|
18
21
|
template: '<app-component />'
|
|
19
22
|
});
|
|
20
23
|
|
|
24
|
+
// https://github.com/Maronato/vue-toastification/tree/main?tab=readme-ov-file#toast-types
|
|
25
|
+
app.use(Toast, { position: 'bottom-right', timeout: 3000 });
|
|
26
|
+
|
|
27
|
+
// Create a global toast instance for convenience (must be after app.use)
|
|
28
|
+
const toast = useToast();
|
|
29
|
+
|
|
21
30
|
// Import all components
|
|
22
31
|
const requireComponents = require.context(
|
|
23
32
|
'.', // Relative path (current directory)
|
|
@@ -56,11 +65,8 @@ app.component('app-component', {
|
|
|
56
65
|
</div>
|
|
57
66
|
`,
|
|
58
67
|
errorCaptured(err) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
icon: 'images/failure.jpg',
|
|
62
|
-
timeout: 10000,
|
|
63
|
-
positionClass: 'bottomRight'
|
|
68
|
+
this.$toast.error(`Error: ${err?.response?.data?.message || err.message}`, {
|
|
69
|
+
timeout: 10000
|
|
64
70
|
});
|
|
65
71
|
},
|
|
66
72
|
computed: {
|
|
@@ -150,7 +156,7 @@ router.beforeEach((to, from, next) => {
|
|
|
150
156
|
}
|
|
151
157
|
});
|
|
152
158
|
|
|
153
|
-
app.config.globalProperties = { format, arrayUtils };
|
|
159
|
+
app.config.globalProperties = { format, arrayUtils, $toast: toast };
|
|
154
160
|
app.use(router);
|
|
155
161
|
|
|
156
162
|
app.mount('#content');
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const template = require('./list-default.html');
|
|
4
4
|
const appendCSS = require('../appendCSS');
|
|
5
|
-
const vanillatoast = require('vanillatoasts');
|
|
6
5
|
|
|
7
6
|
appendCSS(require('./list-default.css'));
|
|
8
7
|
|
|
@@ -19,13 +18,7 @@ module.exports = app => app.component('list-default', {
|
|
|
19
18
|
storage.setSelectionRange(0, 99999);
|
|
20
19
|
document.execCommand('copy');
|
|
21
20
|
elem.removeChild(storage);
|
|
22
|
-
|
|
23
|
-
title: 'Text copied!',
|
|
24
|
-
type: 'success',
|
|
25
|
-
timeout: 3000,
|
|
26
|
-
icon: 'images/success.png',
|
|
27
|
-
positionClass: 'bottomRight'
|
|
28
|
-
});
|
|
21
|
+
this.$toast.success('Text copied!');
|
|
29
22
|
},
|
|
30
23
|
goToDoc(id) {
|
|
31
24
|
this.$router.push({ path: `/model/${this.allude}/document/${id}` });
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const api = require('../api');
|
|
4
4
|
const template = require('./list-mixed.html');
|
|
5
5
|
|
|
6
|
-
const vanillatoast = require('vanillatoasts');
|
|
7
6
|
|
|
8
7
|
require('../appendCSS')(require('./list-mixed.css'));
|
|
9
8
|
|
|
@@ -25,13 +24,7 @@ module.exports = app => app.component('list-mixed', {
|
|
|
25
24
|
storage.setSelectionRange(0, 99999);
|
|
26
25
|
document.execCommand('copy');
|
|
27
26
|
elem.removeChild(storage);
|
|
28
|
-
|
|
29
|
-
title: 'Text copied!',
|
|
30
|
-
type: 'success',
|
|
31
|
-
timeout: 3000,
|
|
32
|
-
icon: 'images/success.png',
|
|
33
|
-
positionClass: 'bottomRight'
|
|
34
|
-
});
|
|
27
|
+
this.$toast.success('Text copied!');
|
|
35
28
|
}
|
|
36
29
|
},
|
|
37
30
|
mounted: function() {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const template = require('./list-string.html');
|
|
4
4
|
const appendCSS = require('../appendCSS');
|
|
5
|
-
const vanillatoast = require('vanillatoasts');
|
|
6
5
|
appendCSS(require('./list-string.css'));
|
|
7
6
|
|
|
8
7
|
module.exports = app => app.component('list-string', {
|
|
@@ -18,13 +17,7 @@ module.exports = app => app.component('list-string', {
|
|
|
18
17
|
storage.setSelectionRange(0, 99999);
|
|
19
18
|
document.execCommand('copy');
|
|
20
19
|
elem.removeChild(storage);
|
|
21
|
-
|
|
22
|
-
title: 'Text copied!',
|
|
23
|
-
type: 'success',
|
|
24
|
-
timeout: 3000,
|
|
25
|
-
icon: 'images/success.png',
|
|
26
|
-
positionClass: 'bottomRight'
|
|
27
|
-
});
|
|
20
|
+
this.$toast.success('Text copied!');
|
|
28
21
|
}
|
|
29
22
|
},
|
|
30
23
|
computed: {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const api = require('../api');
|
|
4
4
|
const template = require('./list-subdocument.html');
|
|
5
|
-
const vanillatoast = require('vanillatoasts');
|
|
6
5
|
|
|
7
6
|
require('../appendCSS')(require('./list-subdocument.css'));
|
|
8
7
|
|
|
@@ -24,13 +23,7 @@ module.exports = app => app.component('list-subdocument', {
|
|
|
24
23
|
storage.setSelectionRange(0, 99999);
|
|
25
24
|
document.execCommand('copy');
|
|
26
25
|
elem.removeChild(storage);
|
|
27
|
-
|
|
28
|
-
title: 'Text copied!',
|
|
29
|
-
type: 'success',
|
|
30
|
-
timeout: 3000,
|
|
31
|
-
icon: 'images/success.png',
|
|
32
|
-
positionClass: 'bottomRight'
|
|
33
|
-
});
|
|
26
|
+
this.$toast.success('Text copied!');
|
|
34
27
|
}
|
|
35
28
|
},
|
|
36
29
|
mounted: function() {
|
|
@@ -79,13 +79,6 @@
|
|
|
79
79
|
>
|
|
80
80
|
Delete
|
|
81
81
|
</button>
|
|
82
|
-
<button
|
|
83
|
-
@click="openIndexModal"
|
|
84
|
-
type="button"
|
|
85
|
-
v-show="!selectMultiple"
|
|
86
|
-
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
87
|
-
Indexes
|
|
88
|
-
</button>
|
|
89
82
|
<button
|
|
90
83
|
@click="shouldShowCreateModal = true;"
|
|
91
84
|
type="button"
|
|
@@ -100,6 +93,45 @@
|
|
|
100
93
|
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
101
94
|
Fields
|
|
102
95
|
</button>
|
|
96
|
+
<div class="relative" v-show="!selectMultiple" ref="actionsMenuContainer" @keyup.esc.prevent="closeActionsMenu">
|
|
97
|
+
<button
|
|
98
|
+
@click="toggleActionsMenu"
|
|
99
|
+
type="button"
|
|
100
|
+
aria-label="More actions"
|
|
101
|
+
class="rounded bg-white px-2 py-2 text-sm font-semibold text-gray-700 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
102
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
|
103
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z" />
|
|
104
|
+
</svg>
|
|
105
|
+
</button>
|
|
106
|
+
<div
|
|
107
|
+
v-if="showActionsMenu"
|
|
108
|
+
class="absolute right-0 mt-2 w-48 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-20"
|
|
109
|
+
>
|
|
110
|
+
<div class="py-1">
|
|
111
|
+
<button
|
|
112
|
+
@click="openIndexModal"
|
|
113
|
+
type="button"
|
|
114
|
+
class="block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100"
|
|
115
|
+
>
|
|
116
|
+
Indexes
|
|
117
|
+
</button>
|
|
118
|
+
<button
|
|
119
|
+
@click="openCollectionInfo"
|
|
120
|
+
type="button"
|
|
121
|
+
class="block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100"
|
|
122
|
+
>
|
|
123
|
+
Collection Info
|
|
124
|
+
</button>
|
|
125
|
+
<button
|
|
126
|
+
@click="findOldestDocument"
|
|
127
|
+
type="button"
|
|
128
|
+
class="block w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100"
|
|
129
|
+
>
|
|
130
|
+
Find oldest document
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
103
135
|
<span class="isolate inline-flex rounded-md shadow-sm">
|
|
104
136
|
<button
|
|
105
137
|
@click="setOutputType('table')"
|
|
@@ -213,6 +245,44 @@
|
|
|
213
245
|
</div>
|
|
214
246
|
</template>
|
|
215
247
|
</modal>
|
|
248
|
+
<modal v-if="shouldShowCollectionInfoModal">
|
|
249
|
+
<template v-slot:body>
|
|
250
|
+
<div class="modal-exit" @click="shouldShowCollectionInfoModal = false">×</div>
|
|
251
|
+
<div class="text-xl font-bold mb-2">Collection Info</div>
|
|
252
|
+
<div v-if="!collectionInfo" class="text-gray-600">Loading collection details...</div>
|
|
253
|
+
<div v-else class="space-y-3">
|
|
254
|
+
<div class="flex justify-between gap-4">
|
|
255
|
+
<div class="font-semibold text-gray-700">Documents</div>
|
|
256
|
+
<div class="text-gray-900">{{ formatNumber(collectionInfo.documentCount) }}</div>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="flex justify-between gap-4">
|
|
259
|
+
<div class="font-semibold text-gray-700">Indexes</div>
|
|
260
|
+
<div class="text-gray-900">{{ formatNumber(collectionInfo.indexCount) }}</div>
|
|
261
|
+
</div>
|
|
262
|
+
<div class="flex justify-between gap-4">
|
|
263
|
+
<div class="font-semibold text-gray-700">Total Index Size</div>
|
|
264
|
+
<div class="text-gray-900">{{ formatCollectionSize(collectionInfo.totalIndexSize) }}</div>
|
|
265
|
+
</div>
|
|
266
|
+
<div class="flex justify-between gap-4">
|
|
267
|
+
<div class="font-semibold text-gray-700">Total Storage Size</div>
|
|
268
|
+
<div class="text-gray-900">{{ formatCollectionSize(collectionInfo.size) }}</div>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="flex flex-col gap-1">
|
|
271
|
+
<div class="flex justify-between gap-4">
|
|
272
|
+
<div class="font-semibold text-gray-700">Collation</div>
|
|
273
|
+
<div class="text-gray-900">{{ collectionInfo.hasCollation ? 'Yes' : 'No' }}</div>
|
|
274
|
+
</div>
|
|
275
|
+
<div v-if="collectionInfo.hasCollation" class="rounded bg-gray-100 p-3 text-sm text-gray-800 overflow-x-auto">
|
|
276
|
+
<pre class="whitespace-pre-wrap">{{ JSON.stringify(collectionInfo.collation, null, 2) }}</pre>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
<div class="flex justify-between gap-4">
|
|
280
|
+
<div class="font-semibold text-gray-700">Capped</div>
|
|
281
|
+
<div class="text-gray-900">{{ collectionInfo.capped ? 'Yes' : 'No' }}</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</template>
|
|
285
|
+
</modal>
|
|
216
286
|
<modal v-if="shouldShowFieldModal">
|
|
217
287
|
<template v-slot:body>
|
|
218
288
|
<div class="modal-exit" @click="shouldShowFieldModal = false; selectedPaths = [...filteredPaths];">×</div>
|