@mongoosejs/studio 0.0.82 → 0.0.84
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/astra.js +159 -0
- package/backend/actions/ChatMessage/executeScript.js +2 -2
- package/backend/actions/ChatThread/createChatMessage.js +3 -3
- package/backend/actions/ChatThread/createChatThread.js +2 -2
- package/backend/actions/ChatThread/getChatThread.js +4 -4
- package/backend/actions/ChatThread/listChatThreads.js +2 -2
- package/backend/actions/Model/deleteDocuments.js +38 -0
- package/backend/actions/Model/getDocuments.js +2 -2
- package/backend/actions/Model/index.js +2 -0
- package/backend/actions/Model/updateDocuments.js +46 -0
- package/backend/index.js +6 -7
- package/express.js +1 -1
- package/frontend/public/app.js +6592 -6344
- package/frontend/public/tw.css +62 -0
- package/frontend/src/api.js +12 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +12 -6
- package/frontend/src/chat/chat-message-script/chat-message-script.js +11 -0
- package/frontend/src/models/models.html +55 -4
- package/frontend/src/models/models.js +52 -0
- package/frontend/src/update-document/update-document.css +0 -0
- package/frontend/src/update-document/update-document.html +25 -0
- package/frontend/src/update-document/update-document.js +70 -0
- package/package.json +1 -1
package/frontend/public/tw.css
CHANGED
|
@@ -914,6 +914,10 @@ video {
|
|
|
914
914
|
max-width: 64rem;
|
|
915
915
|
}
|
|
916
916
|
|
|
917
|
+
.max-w-\[70vw\] {
|
|
918
|
+
max-width: 70vw;
|
|
919
|
+
}
|
|
920
|
+
|
|
917
921
|
.max-w-\[calc\(100\%-6\.5rem\)\] {
|
|
918
922
|
max-width: calc(100% - 6.5rem);
|
|
919
923
|
}
|
|
@@ -1231,6 +1235,16 @@ video {
|
|
|
1231
1235
|
border-color: rgb(63 83 255 / var(--tw-border-opacity));
|
|
1232
1236
|
}
|
|
1233
1237
|
|
|
1238
|
+
.border-red-500 {
|
|
1239
|
+
--tw-border-opacity: 1;
|
|
1240
|
+
border-color: rgb(239 68 68 / var(--tw-border-opacity));
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.bg-blue-200 {
|
|
1244
|
+
--tw-bg-opacity: 1;
|
|
1245
|
+
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1234
1248
|
.bg-blue-500 {
|
|
1235
1249
|
--tw-bg-opacity: 1;
|
|
1236
1250
|
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
|
|
@@ -1326,6 +1340,11 @@ video {
|
|
|
1326
1340
|
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
|
1327
1341
|
}
|
|
1328
1342
|
|
|
1343
|
+
.bg-red-600 {
|
|
1344
|
+
--tw-bg-opacity: 1;
|
|
1345
|
+
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1329
1348
|
.bg-slate-100 {
|
|
1330
1349
|
--tw-bg-opacity: 1;
|
|
1331
1350
|
background-color: rgb(241 245 249 / var(--tw-bg-opacity));
|
|
@@ -1380,6 +1399,11 @@ video {
|
|
|
1380
1399
|
background-color: rgb(253 224 71 / var(--tw-bg-opacity));
|
|
1381
1400
|
}
|
|
1382
1401
|
|
|
1402
|
+
.bg-ultramarine-500 {
|
|
1403
|
+
--tw-bg-opacity: 1;
|
|
1404
|
+
background-color: rgb(63 83 255 / var(--tw-bg-opacity));
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1383
1407
|
.p-1 {
|
|
1384
1408
|
padding: 0.25rem;
|
|
1385
1409
|
}
|
|
@@ -1722,6 +1746,12 @@ video {
|
|
|
1722
1746
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
1723
1747
|
}
|
|
1724
1748
|
|
|
1749
|
+
.ring-2 {
|
|
1750
|
+
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
1751
|
+
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
1752
|
+
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1725
1755
|
.ring-inset {
|
|
1726
1756
|
--tw-ring-inset: inset;
|
|
1727
1757
|
}
|
|
@@ -1747,6 +1777,16 @@ video {
|
|
|
1747
1777
|
--tw-ring-color: rgb(22 163 74 / 0.2);
|
|
1748
1778
|
}
|
|
1749
1779
|
|
|
1780
|
+
.ring-yellow-800 {
|
|
1781
|
+
--tw-ring-opacity: 1;
|
|
1782
|
+
--tw-ring-color: rgb(133 77 14 / var(--tw-ring-opacity));
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
.ring-yellow-300 {
|
|
1786
|
+
--tw-ring-opacity: 1;
|
|
1787
|
+
--tw-ring-color: rgb(253 224 71 / var(--tw-ring-opacity));
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1750
1790
|
.filter {
|
|
1751
1791
|
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);
|
|
1752
1792
|
}
|
|
@@ -1850,6 +1890,11 @@ video {
|
|
|
1850
1890
|
background-color: rgb(22 163 74 / var(--tw-bg-opacity));
|
|
1851
1891
|
}
|
|
1852
1892
|
|
|
1893
|
+
.hover\:bg-red-500:hover {
|
|
1894
|
+
--tw-bg-opacity: 1;
|
|
1895
|
+
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1853
1898
|
.hover\:bg-red-600:hover {
|
|
1854
1899
|
--tw-bg-opacity: 1;
|
|
1855
1900
|
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
|
|
@@ -1895,6 +1940,11 @@ video {
|
|
|
1895
1940
|
background-color: rgb(220 73 73 / var(--tw-bg-opacity));
|
|
1896
1941
|
}
|
|
1897
1942
|
|
|
1943
|
+
.hover\:bg-ultramarine-600:hover {
|
|
1944
|
+
--tw-bg-opacity: 1;
|
|
1945
|
+
background-color: rgb(24 35 255 / var(--tw-bg-opacity));
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1898
1948
|
.hover\:text-gray-700:hover {
|
|
1899
1949
|
--tw-text-opacity: 1;
|
|
1900
1950
|
color: rgb(55 65 81 / var(--tw-text-opacity));
|
|
@@ -2033,6 +2083,10 @@ video {
|
|
|
2033
2083
|
outline-color: #fb923c;
|
|
2034
2084
|
}
|
|
2035
2085
|
|
|
2086
|
+
.focus-visible\:outline-red-500:focus-visible {
|
|
2087
|
+
outline-color: #ef4444;
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2036
2090
|
.focus-visible\:outline-red-600:focus-visible {
|
|
2037
2091
|
outline-color: #dc2626;
|
|
2038
2092
|
}
|
|
@@ -2053,6 +2107,14 @@ video {
|
|
|
2053
2107
|
outline-color: #1823ff;
|
|
2054
2108
|
}
|
|
2055
2109
|
|
|
2110
|
+
.focus-visible\:outline-gray-600:focus-visible {
|
|
2111
|
+
outline-color: #4b5563;
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
.focus-visible\:outline-gray-500:focus-visible {
|
|
2115
|
+
outline-color: #6b7280;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2056
2118
|
.disabled\:cursor-not-allowed:disabled {
|
|
2057
2119
|
cursor: not-allowed;
|
|
2058
2120
|
}
|
package/frontend/src/api.js
CHANGED
|
@@ -75,6 +75,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
75
75
|
deleteDocument(params) {
|
|
76
76
|
return client.post('', { action: 'Model.deleteDocument', ...params}).then(res => res.data);
|
|
77
77
|
},
|
|
78
|
+
deleteDocuments(params) {
|
|
79
|
+
return client.post('', { action: 'Model.deleteDocuments', ...params}).then(res => res.data);
|
|
80
|
+
},
|
|
78
81
|
exportQueryResults(params) {
|
|
79
82
|
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
80
83
|
|
|
@@ -113,6 +116,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
113
116
|
},
|
|
114
117
|
updateDocument: function updateDocument(params) {
|
|
115
118
|
return client.post('', { action: 'Model.updateDocument', ...params }).then(res => res.data);
|
|
119
|
+
},
|
|
120
|
+
updateDocuments: function updateDocuments(params) {
|
|
121
|
+
return client.post('', { action: 'Model.updateDocuments', ...params }).then(res => res.data);
|
|
116
122
|
}
|
|
117
123
|
};
|
|
118
124
|
} else {
|
|
@@ -165,6 +171,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
165
171
|
deleteDocument: function (params) {
|
|
166
172
|
return client.post('/Model/deleteDocument', params).then(res => res.data);
|
|
167
173
|
},
|
|
174
|
+
deleteDocuments: function(params) {
|
|
175
|
+
return client.post('/Model/deleteDocuments', params).then(res => res.data);
|
|
176
|
+
},
|
|
168
177
|
exportQueryResults(params) {
|
|
169
178
|
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
170
179
|
|
|
@@ -206,6 +215,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
206
215
|
},
|
|
207
216
|
updateDocument: function updateDocument(params) {
|
|
208
217
|
return client.post('/Model/updateDocument', params).then(res => res.data);
|
|
218
|
+
},
|
|
219
|
+
updateDocuments: function updateDocument(params) {
|
|
220
|
+
return client.post('/Model/updateDocuments', params).then(res => res.data);
|
|
209
221
|
}
|
|
210
222
|
};
|
|
211
223
|
}
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
Output
|
|
14
14
|
</button>
|
|
15
15
|
<div class="ml-auto mr-1 flex">
|
|
16
|
+
<button
|
|
17
|
+
v-if="activeTab === 'output'"
|
|
18
|
+
class="px-2 py-1 mr-1 text-xs bg-gray-500 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center"
|
|
19
|
+
@click="copyOutput">
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
21
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
|
|
22
|
+
</svg>
|
|
23
|
+
</button>
|
|
16
24
|
<button
|
|
17
25
|
v-if="activeTab === 'output'"
|
|
18
26
|
class="px-2 py-1 mr-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center"
|
|
@@ -31,19 +39,17 @@
|
|
|
31
39
|
|
|
32
40
|
<pre class="p-3 whitespace-pre-wrap max-h-[30vh] overflow-y-auto" v-show="activeTab === 'code'"><code v-text="script" ref="code" :class="'language-' + language"></code></pre>
|
|
33
41
|
|
|
34
|
-
<
|
|
42
|
+
<div class="p-3 whitespace-pre-wrap max-h-[30vh] overflow-y-auto bg-white border-t max-w-[70vw] relative" v-show="activeTab === 'output'">
|
|
35
43
|
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" />
|
|
36
|
-
<
|
|
37
|
-
</
|
|
44
|
+
<pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>
|
|
45
|
+
</div>
|
|
38
46
|
|
|
39
47
|
<modal ref="outputModal" v-if="showDetailModal" containerClass="!h-[90vh] !w-[90vw]">
|
|
40
48
|
<template #body>
|
|
41
49
|
<div class="absolute font-mono right-1 top-1 cursor-pointer text-xl" @click="showDetailModal = false;">×</div>
|
|
42
50
|
<div class="h-full overflow-auto">
|
|
43
51
|
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" />
|
|
44
|
-
<pre v-else class="whitespace-pre-wrap">
|
|
45
|
-
{{ message.executionResult?.output ? JSON.stringify(message.executionResult.output, null, 2) : 'No output' }}
|
|
46
|
-
</pre>
|
|
52
|
+
<pre v-else class="whitespace-pre-wrap">{{ message.executionResult?.output || 'No output' }}</pre>
|
|
47
53
|
</div>
|
|
48
54
|
</template>
|
|
49
55
|
</modal>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const api = require('../../api');
|
|
4
4
|
const marked = require('marked').marked;
|
|
5
5
|
const template = require('./chat-message-script.html');
|
|
6
|
+
const vanillatoasts = require('vanillatoasts');
|
|
6
7
|
|
|
7
8
|
module.exports = app => app.component('chat-message-script', {
|
|
8
9
|
template: template,
|
|
@@ -24,6 +25,16 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
24
25
|
},
|
|
25
26
|
openDetailModal() {
|
|
26
27
|
this.showDetailModal = true;
|
|
28
|
+
},
|
|
29
|
+
async copyOutput() {
|
|
30
|
+
await navigator.clipboard.writeText(this.message.executionResult.output);
|
|
31
|
+
vanillatoasts.create({
|
|
32
|
+
title: 'Text copied!',
|
|
33
|
+
type: 'success',
|
|
34
|
+
timeout: 3000,
|
|
35
|
+
icon: 'images/success.png',
|
|
36
|
+
positionClass: 'bottomRight'
|
|
37
|
+
});
|
|
27
38
|
}
|
|
28
39
|
},
|
|
29
40
|
mounted() {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<div class="documents-menu">
|
|
29
29
|
<div class="flex flex-row items-center w-full gap-2">
|
|
30
30
|
<form @submit.prevent="search" class="flex-grow m-0">
|
|
31
|
-
<input ref="searchInput" class="w-full font-mono rounded-md p-1 border border-gray-300 outline-gray-300 text-lg focus:ring-1 focus:ring-ultramarine-200 focus:ring-offset-0 focus:outline-none" type="text" placeholder="Filter
|
|
31
|
+
<input ref="searchInput" class="w-full font-mono rounded-md p-1 border border-gray-300 outline-gray-300 text-lg focus:ring-1 focus:ring-ultramarine-200 focus:ring-offset-0 focus:outline-none" type="text" placeholder="Filter" v-model="searchText" @click="initFilter" />
|
|
32
32
|
</form>
|
|
33
33
|
<div>
|
|
34
34
|
<span v-if="status === 'loading'">Loading ...</span>
|
|
@@ -37,24 +37,52 @@
|
|
|
37
37
|
<button
|
|
38
38
|
@click="shouldShowExportModal = true"
|
|
39
39
|
type="button"
|
|
40
|
+
v-show="!selectMultiple"
|
|
40
41
|
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">
|
|
41
42
|
Export
|
|
42
43
|
</button>
|
|
44
|
+
<button
|
|
45
|
+
@click="stagingSelect"
|
|
46
|
+
type="button"
|
|
47
|
+
:class="{ 'bg-ultramarine-500 ring-inset ring-2 ring-gray-300 hover:bg-ultramarine-600': selectMultiple }"
|
|
48
|
+
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"
|
|
49
|
+
>
|
|
50
|
+
Select
|
|
51
|
+
</button>
|
|
52
|
+
<button
|
|
53
|
+
v-show="selectMultiple"
|
|
54
|
+
@click="shouldShowUpdateMultipleModal=true;"
|
|
55
|
+
type="button"
|
|
56
|
+
class="rounded bg-green-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600"
|
|
57
|
+
>
|
|
58
|
+
Update
|
|
59
|
+
</button>
|
|
60
|
+
<button
|
|
61
|
+
@click="shouldShowDeleteMultipleModal=true;"
|
|
62
|
+
type="button"
|
|
63
|
+
v-show="selectMultiple"
|
|
64
|
+
class="rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
|
|
65
|
+
>
|
|
66
|
+
Delete
|
|
67
|
+
</button>
|
|
43
68
|
<button
|
|
44
69
|
@click="openIndexModal"
|
|
45
70
|
type="button"
|
|
71
|
+
v-show="!selectMultiple"
|
|
46
72
|
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">
|
|
47
73
|
Indexes
|
|
48
74
|
</button>
|
|
49
75
|
<button
|
|
50
76
|
@click="shouldShowCreateModal = true;"
|
|
51
77
|
type="button"
|
|
78
|
+
v-show="!selectMultiple"
|
|
52
79
|
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">
|
|
53
80
|
Create
|
|
54
81
|
</button>
|
|
55
82
|
<button
|
|
56
83
|
@click="openFieldSelection"
|
|
57
84
|
type="button"
|
|
85
|
+
v-show="!selectMultiple"
|
|
58
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">
|
|
59
87
|
Fields
|
|
60
88
|
</button>
|
|
@@ -90,8 +118,8 @@
|
|
|
90
118
|
</th>
|
|
91
119
|
</thead>
|
|
92
120
|
<tbody>
|
|
93
|
-
<tr v-for="document in documents" @click="
|
|
94
|
-
<td v-for="schemaPath in filteredPaths">
|
|
121
|
+
<tr v-for="document in documents" @click="handleDocumentClick(document)" :key="document._id">
|
|
122
|
+
<td v-for="schemaPath in filteredPaths" :class="{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }">
|
|
95
123
|
<component
|
|
96
124
|
:is="getComponentForPath(schemaPath)"
|
|
97
125
|
:value="getValueForPath(document, schemaPath.path)"
|
|
@@ -102,7 +130,7 @@
|
|
|
102
130
|
</tbody>
|
|
103
131
|
</table>
|
|
104
132
|
<div v-if="outputType === 'json'">
|
|
105
|
-
<div v-for="document in documents" @click="
|
|
133
|
+
<div v-for="document in documents" @click="handleDocumentClick(document)" :key="document._id" :class="{ 'bg-blue-200': selectedDocuments.some(x => x._id.toString() === document._id.toString()) }">
|
|
106
134
|
<list-json :value="filterDocument(document)">
|
|
107
135
|
</list-json>
|
|
108
136
|
</div>
|
|
@@ -162,4 +190,27 @@
|
|
|
162
190
|
<create-document :currentModel="currentModel" :paths="schemaPaths" @close="closeCreationModal"></create-document>
|
|
163
191
|
</template>
|
|
164
192
|
</modal>
|
|
193
|
+
<modal v-if="shouldShowUpdateMultipleModal">
|
|
194
|
+
<template v-slot:body>
|
|
195
|
+
<div class="modal-exit" @click="shouldShowUpdateMultipleModal = false;">×</div>
|
|
196
|
+
<update-document :currentModel="currentModel" :document="selectedDocuments" :multiple="true" @update="updateDocuments" @close="shouldShowUpdateMultipleModal=false;"></update-document>
|
|
197
|
+
</template>
|
|
198
|
+
</modal>
|
|
199
|
+
<modal v-if="shouldShowDeleteMultipleModal">
|
|
200
|
+
<template v-slot:body>
|
|
201
|
+
<div class="modal-exit" @click="shouldShowDeleteMultipleModal = false;">×</div>
|
|
202
|
+
<h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>
|
|
203
|
+
<div>
|
|
204
|
+
<list-json :value="selectedDocuments"></list-json>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="flex gap-4">
|
|
207
|
+
<async-button @click="deleteDocuments" class="rounded bg-red-500 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600">
|
|
208
|
+
Confirm
|
|
209
|
+
</async-button>
|
|
210
|
+
<button @click="shouldShowDeleteMultipleModal = false;" class="rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500">
|
|
211
|
+
Cancel
|
|
212
|
+
</button>
|
|
213
|
+
</div>
|
|
214
|
+
</template>
|
|
215
|
+
</modal>
|
|
165
216
|
</div>
|
|
@@ -38,11 +38,15 @@ module.exports = app => app.component('models', {
|
|
|
38
38
|
edittingDoc: null,
|
|
39
39
|
docEdits: null,
|
|
40
40
|
filter: null,
|
|
41
|
+
selectMultiple: false,
|
|
42
|
+
selectedDocuments: [],
|
|
41
43
|
searchText: '',
|
|
42
44
|
shouldShowExportModal: false,
|
|
43
45
|
shouldShowCreateModal: false,
|
|
44
46
|
shouldShowFieldModal: false,
|
|
45
47
|
shouldShowIndexModal: false,
|
|
48
|
+
shouldShowUpdateMultipleModal: false,
|
|
49
|
+
shouldShowDeleteMultipleModal: false,
|
|
46
50
|
shouldExport: {},
|
|
47
51
|
sortBy: {},
|
|
48
52
|
query: {},
|
|
@@ -89,6 +93,14 @@ module.exports = app => app.component('models', {
|
|
|
89
93
|
this.status = 'loaded';
|
|
90
94
|
},
|
|
91
95
|
methods: {
|
|
96
|
+
initFilter(ev) {
|
|
97
|
+
if (!this.searchText) {
|
|
98
|
+
this.searchText = '{}';
|
|
99
|
+
this.$nextTick(() => {
|
|
100
|
+
ev.target.setSelectionRange(1, 1);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
},
|
|
92
104
|
clickFilter(path) {
|
|
93
105
|
if (this.searchText) {
|
|
94
106
|
if (this.searchText.endsWith('}')) {
|
|
@@ -319,6 +331,46 @@ module.exports = app => app.component('models', {
|
|
|
319
331
|
this.documents[index] = res.doc;
|
|
320
332
|
}
|
|
321
333
|
this.edittingDoc = null;
|
|
334
|
+
},
|
|
335
|
+
handleDocumentClick(document) {
|
|
336
|
+
console.log(this.selectedDocuments);
|
|
337
|
+
if (this.selectMultiple) {
|
|
338
|
+
const exists = this.selectedDocuments.find(x => x._id.toString() == document._id.toString())
|
|
339
|
+
if (exists) {
|
|
340
|
+
const index = this.selectedDocuments.findIndex(x => x._id.toString() == document._id.toString());
|
|
341
|
+
if (index !== -1) {
|
|
342
|
+
this.selectedDocuments.splice(index, 1);
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
this.selectedDocuments.push(document);
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
this.$router.push('/model/' + this.currentModel + '/document/' + document._id)
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
async deleteDocuments() {
|
|
352
|
+
const documentIds = this.selectedDocuments.map(x => x._id);
|
|
353
|
+
await api.Model.deleteDocuments({
|
|
354
|
+
documentIds,
|
|
355
|
+
model: this.currentModel
|
|
356
|
+
});
|
|
357
|
+
await this.getDocuments();
|
|
358
|
+
this.selectedDocuments.length = 0;
|
|
359
|
+
this.shouldShowDeleteMultipleModal = false;
|
|
360
|
+
this.selectMultiple = false;
|
|
361
|
+
},
|
|
362
|
+
async updateDocuments() {
|
|
363
|
+
await this.getDocuments();
|
|
364
|
+
this.selectedDocuments.length = 0;
|
|
365
|
+
this.selectMultiple = false;
|
|
366
|
+
},
|
|
367
|
+
stagingSelect() {
|
|
368
|
+
if (this.selectMultiple) {
|
|
369
|
+
this.selectMultiple = false;
|
|
370
|
+
this.selectedDocuments.length = 0;
|
|
371
|
+
} else {
|
|
372
|
+
this.selectMultiple = true;
|
|
373
|
+
}
|
|
322
374
|
}
|
|
323
375
|
}
|
|
324
376
|
});
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<div class="mb-2">
|
|
3
|
+
<textarea class="border border-gray-200 p-2 h-[300px] w-full" ref="codeEditor"></textarea>
|
|
4
|
+
</div>
|
|
5
|
+
<button @click="updateDocument()" class="rounded-md bg-ultramarine-600 px-2.5 py-1.5 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-teal-600">Submit</button>
|
|
6
|
+
<div v-if="errors.length > 0" class="rounded-md bg-red-50 p-4 mt-1">
|
|
7
|
+
<div class="flex">
|
|
8
|
+
<div class="flex-shrink-0">
|
|
9
|
+
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
10
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
|
|
11
|
+
</svg>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="ml-3">
|
|
14
|
+
<h3 class="text-sm font-medium text-red-800">There were {{errors.length}} errors with your submission</h3>
|
|
15
|
+
<div class="mt-2 text-sm text-red-700">
|
|
16
|
+
<ul role="list" class="list-disc space-y-1 pl-5">
|
|
17
|
+
<li v-for="error in errors">
|
|
18
|
+
{{error}}
|
|
19
|
+
</li>
|
|
20
|
+
</ul>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const api = require('../api');
|
|
4
|
+
|
|
5
|
+
const { BSON, EJSON } = require('bson');
|
|
6
|
+
|
|
7
|
+
const ObjectId = new Proxy(BSON.ObjectId, {
|
|
8
|
+
apply (target, thisArg, argumentsList) {
|
|
9
|
+
return new target(...argumentsList);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const appendCSS = require('../appendCSS');
|
|
14
|
+
|
|
15
|
+
appendCSS(require('./update-document.css'));
|
|
16
|
+
|
|
17
|
+
const template = require('./update-document.html')
|
|
18
|
+
|
|
19
|
+
module.exports = app => app.component('update-document', {
|
|
20
|
+
props: ['currentModel', 'document', 'multiple'],
|
|
21
|
+
template,
|
|
22
|
+
data: function() {
|
|
23
|
+
return {
|
|
24
|
+
editor: null,
|
|
25
|
+
errors: []
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
methods: {
|
|
29
|
+
async updateDocument() {
|
|
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;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.errors.length = 0;
|
|
58
|
+
this.$emit('update');
|
|
59
|
+
this.$emit('close');
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
mounted: function() {
|
|
63
|
+
this.$refs.codeEditor.value = `{\n \n}`
|
|
64
|
+
this.editor = CodeMirror.fromTextArea(this.$refs.codeEditor, {
|
|
65
|
+
mode: 'javascript',
|
|
66
|
+
lineNumbers: true,
|
|
67
|
+
smartIndent: false
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.84",
|
|
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": {
|