@mongoosejs/studio 0.2.12 → 0.3.0
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/ChatMessage/executeScript.js +5 -1
- package/backend/actions/ChatThread/createChatMessage.js +2 -1
- package/backend/actions/ChatThread/streamChatMessage.js +2 -2
- package/backend/actions/Model/getEstimatedDocumentCounts.js +38 -0
- package/backend/actions/Model/index.js +1 -0
- package/backend/actions/Model/streamDocumentChanges.js +8 -7
- package/backend/actions/Task/getTasks.js +9 -6
- package/backend/authorize.js +1 -0
- package/backend/index.js +11 -3
- package/eslint.config.js +5 -1
- package/express.js +1 -0
- package/frontend/public/app.js +25235 -662
- package/frontend/public/dark-theme.css +365 -0
- package/frontend/public/images/mongoose-studio.svg +4 -0
- package/frontend/public/index.html +21 -1
- package/frontend/public/style.css +5 -7
- package/frontend/public/theme-variables.css +294 -0
- package/frontend/public/tw.css +461 -239
- package/frontend/src/ace-editor/ace-editor.html +4 -0
- package/frontend/src/ace-editor/ace-editor.js +89 -0
- package/frontend/src/aceEditor.js +69 -0
- package/frontend/src/api.js +6 -0
- package/frontend/src/chat/chat-message/chat-message.html +1 -1
- package/frontend/src/chat/chat-message/chat-message.js +1 -1
- package/frontend/src/chat/chat-message-script/chat-message-script.html +51 -34
- package/frontend/src/chat/chat-message-script/chat-message-script.js +12 -55
- package/frontend/src/chat/chat.html +72 -37
- package/frontend/src/chat/chat.js +26 -2
- package/frontend/src/clone-document/clone-document.html +7 -2
- package/frontend/src/clone-document/clone-document.js +1 -8
- package/frontend/src/create-dashboard/create-dashboard.html +11 -6
- package/frontend/src/create-dashboard/create-dashboard.js +0 -7
- package/frontend/src/create-document/create-document.html +15 -9
- package/frontend/src/create-document/create-document.js +5 -12
- package/frontend/src/dashboard/dashboard.html +14 -12
- package/frontend/src/dashboard/dashboard.js +12 -4
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +13 -7
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +13 -21
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +19 -17
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +97 -2
- package/frontend/src/dashboard-result/dashboard-map/dashboard-map.js +27 -3
- package/frontend/src/dashboard-result/dashboard-result.html +3 -3
- package/frontend/src/dashboards/dashboards.html +101 -109
- package/frontend/src/dashboards/dashboards.js +25 -1
- package/frontend/src/detail-default/detail-default.html +2 -2
- package/frontend/src/detail-default/detail-default.js +24 -3
- package/frontend/src/document/confirm-changes/confirm-changes.html +1 -1
- package/frontend/src/document/confirm-delete/confirm-delete.html +1 -1
- package/frontend/src/document/document.css +1 -1
- package/frontend/src/document/document.html +53 -27
- package/frontend/src/document/document.js +27 -1
- package/frontend/src/document/execute-script/execute-script.html +20 -21
- package/frontend/src/document/execute-script/execute-script.js +1 -43
- package/frontend/src/document-details/document-details.css +4 -9
- package/frontend/src/document-details/document-details.html +34 -33
- package/frontend/src/document-details/document-details.js +2 -53
- package/frontend/src/document-details/document-property/document-property.html +12 -12
- package/frontend/src/edit-array/edit-array.html +7 -6
- package/frontend/src/edit-array/edit-array.js +10 -50
- package/frontend/src/edit-boolean/edit-boolean.html +12 -12
- package/frontend/src/edit-date/edit-date.html +2 -2
- package/frontend/src/edit-default/edit-default.html +1 -1
- package/frontend/src/edit-string/edit-string.html +3 -3
- package/frontend/src/edit-subdocument/edit-subdocument.html +5 -3
- package/frontend/src/edit-subdocument/edit-subdocument.js +1 -15
- package/frontend/src/export-query-results/export-query-results.html +3 -3
- package/frontend/src/json-node/json-node.html +3 -3
- package/frontend/src/list-json/json-node.html +1 -1
- package/frontend/src/models/document-search/document-search.html +3 -3
- package/frontend/src/models/model-switcher/model-switcher.html +53 -0
- package/frontend/src/models/model-switcher/model-switcher.js +123 -0
- package/frontend/src/models/models.css +3 -10
- package/frontend/src/models/models.html +146 -74
- package/frontend/src/models/models.js +142 -4
- package/frontend/src/navbar/navbar.html +157 -97
- package/frontend/src/navbar/navbar.js +32 -13
- package/frontend/src/routes.js +20 -4
- package/frontend/src/splash/splash.html +5 -5
- package/frontend/src/task-by-name/task-by-name.html +15 -0
- package/frontend/src/task-by-name/task-by-name.js +78 -0
- package/frontend/src/task-single/task-single.html +157 -0
- package/frontend/src/task-single/task-single.js +116 -0
- package/frontend/src/tasks/task-details/task-details.html +124 -73
- package/frontend/src/tasks/task-details/task-details.js +166 -10
- package/frontend/src/tasks/tasks.html +37 -48
- package/frontend/src/tasks/tasks.js +11 -50
- package/frontend/src/team/new-invitation/new-invitation.html +8 -8
- package/frontend/src/team/team.html +27 -27
- package/frontend/src/update-document/update-document.html +7 -2
- package/frontend/src/update-document/update-document.js +2 -11
- package/package.json +3 -1
- package/tailwind.config.js +75 -11
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<div class="document px-1 pt-4 pb-16 md:px-0 bg-slate-50 w-full">
|
|
2
2
|
<div class="max-w-7xl mx-auto">
|
|
3
|
-
<div class="flex gap-4 items-center sticky top-0 z-50 bg-
|
|
3
|
+
<div class="flex gap-4 items-center sticky top-0 z-50 bg-surface p-4 border-b border-edge shadow-sm">
|
|
4
4
|
<div class="font-bold overflow-hidden text-ellipsis">{{model}}: {{documentId}}</div>
|
|
5
5
|
<div class="flex grow">
|
|
6
6
|
<button
|
|
7
7
|
@click="viewMode = 'fields'"
|
|
8
8
|
:class="viewMode === 'fields'
|
|
9
9
|
? 'bg-blue-600 text-white z-10'
|
|
10
|
-
: 'bg-gray-200 text-
|
|
11
|
-
class="px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-
|
|
10
|
+
: 'bg-gray-200 text-content-secondary hover:bg-gray-300'"
|
|
11
|
+
class="px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-edge-strong border-r-0 rounded-l-lg rounded-r-none"
|
|
12
12
|
>
|
|
13
13
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
14
14
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path>
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
@click="viewMode = 'json'"
|
|
20
20
|
:class="viewMode === 'json'
|
|
21
21
|
? 'bg-blue-600 text-white z-10'
|
|
22
|
-
: 'bg-gray-200 text-
|
|
23
|
-
class="px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-
|
|
22
|
+
: 'bg-gray-200 text-content-secondary hover:bg-gray-300'"
|
|
23
|
+
class="px-2 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center gap-2 border border-edge-strong rounded-r-lg rounded-l-none"
|
|
24
24
|
>
|
|
25
25
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
26
26
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
:disabled="!canEdit"
|
|
49
49
|
:class="{'cursor-not-allowed opacity-50': !canEdit}"
|
|
50
50
|
type="button"
|
|
51
|
-
class="rounded-md bg-
|
|
51
|
+
class="rounded-md bg-primary px-2.5 py-1.5 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600">
|
|
52
52
|
<img src="images/edit.svg" class="inline" /> Edit
|
|
53
53
|
</button>
|
|
54
54
|
<button
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<button
|
|
74
74
|
@click="desktopMenuOpen = !desktopMenuOpen"
|
|
75
75
|
type="button"
|
|
76
|
-
class="inline-flex items-center justify-center rounded-md bg-gray-200 px-2.5 py-1.5 text-sm font-medium text-
|
|
76
|
+
class="inline-flex items-center justify-center rounded-md bg-gray-200 px-2.5 py-1.5 text-sm font-medium text-content-secondary hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
77
77
|
aria-expanded="desktopMenuOpen"
|
|
78
78
|
aria-label="More options"
|
|
79
79
|
>
|
|
@@ -86,13 +86,13 @@
|
|
|
86
86
|
<div
|
|
87
87
|
v-show="desktopMenuOpen"
|
|
88
88
|
@click.away="desktopMenuOpen = false"
|
|
89
|
-
class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-
|
|
89
|
+
class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-surface ring-1 ring-black ring-opacity-5 z-50"
|
|
90
90
|
>
|
|
91
91
|
<div class="py-1 flex flex-col">
|
|
92
92
|
<button
|
|
93
93
|
@click="refreshDocument({ force: true, source: 'manual' }); desktopMenuOpen = false"
|
|
94
94
|
:disabled="isRefreshing"
|
|
95
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
95
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']"
|
|
96
96
|
type="button"
|
|
97
97
|
>
|
|
98
98
|
{{isRefreshing ? 'Refreshing...' : 'Refresh'}}
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
@click="toggleAutoRefresh(); desktopMenuOpen = false"
|
|
102
102
|
:disabled="isLambda"
|
|
103
103
|
type="button"
|
|
104
|
-
:class="['flex items-center px-4 py-2 text-sm', isLambda ? 'text-gray-400 cursor-not-allowed' : 'text-
|
|
104
|
+
:class="['flex items-center px-4 py-2 text-sm', isLambda ? 'text-gray-400 cursor-not-allowed' : 'text-content-secondary hover:bg-slate-100']"
|
|
105
105
|
:title="isLambda ? 'Auto-refresh only available on Express deployments' : ''"
|
|
106
106
|
>
|
|
107
107
|
{{autoRefreshEnabled ? 'Disable Auto-Refresh' : 'Enable Auto-Refresh'}}
|
|
@@ -109,28 +109,28 @@
|
|
|
109
109
|
<button
|
|
110
110
|
@click="addField(); desktopMenuOpen = false"
|
|
111
111
|
type="button"
|
|
112
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
112
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-green-100"
|
|
113
113
|
>
|
|
114
114
|
Add Field
|
|
115
115
|
</button>
|
|
116
116
|
<button
|
|
117
117
|
@click="copyDocument(); desktopMenuOpen = false"
|
|
118
118
|
type="button"
|
|
119
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
119
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-blue-100"
|
|
120
120
|
>
|
|
121
121
|
Copy Document
|
|
122
122
|
</button>
|
|
123
123
|
<button
|
|
124
124
|
@click="openScriptDrawer()"
|
|
125
125
|
type="button"
|
|
126
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
126
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-indigo-100"
|
|
127
127
|
>
|
|
128
128
|
Run Script
|
|
129
129
|
</button>
|
|
130
130
|
<button
|
|
131
131
|
@click="shouldShowDeleteModal=true; desktopMenuOpen = false"
|
|
132
132
|
:disabled="!canManipulate"
|
|
133
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
133
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']"
|
|
134
134
|
type="button"
|
|
135
135
|
>
|
|
136
136
|
Delete
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
<button
|
|
139
139
|
@click="shouldShowCloneModal=true; desktopMenuOpen = false"
|
|
140
140
|
:disabled="!canManipulate"
|
|
141
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
141
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']"
|
|
142
142
|
type="button"
|
|
143
143
|
>
|
|
144
144
|
Clone
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
<button
|
|
153
153
|
@click="mobileMenuOpen = !mobileMenuOpen"
|
|
154
154
|
type="button"
|
|
155
|
-
class="inline-flex items-center justify-center rounded-md bg-gray-200 px-3 py-2 text-sm font-medium text-
|
|
155
|
+
class="inline-flex items-center justify-center rounded-md bg-gray-200 px-3 py-2 text-sm font-medium text-content-secondary hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
156
156
|
aria-expanded="mobileMenuOpen"
|
|
157
157
|
aria-label="Open menu"
|
|
158
158
|
>
|
|
@@ -164,14 +164,14 @@
|
|
|
164
164
|
<div
|
|
165
165
|
v-show="mobileMenuOpen"
|
|
166
166
|
@click.away="mobileMenuOpen = false"
|
|
167
|
-
class="origin-top-right absolute right-0 mt-2 w-52 rounded-md shadow-lg bg-
|
|
167
|
+
class="origin-top-right absolute right-0 mt-2 w-52 rounded-md shadow-lg bg-surface ring-1 ring-black ring-opacity-5 z-50"
|
|
168
168
|
>
|
|
169
169
|
<div class="py-1 flex flex-col">
|
|
170
170
|
<button
|
|
171
171
|
v-if="!editting"
|
|
172
172
|
@click="editting = true; mobileMenuOpen = false"
|
|
173
173
|
:disabled="!canEdit"
|
|
174
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
174
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canEdit ? 'cursor-not-allowed opacity-50' : 'hover:bg-primary-subtle']"
|
|
175
175
|
type="button"
|
|
176
176
|
>
|
|
177
177
|
Edit
|
|
@@ -180,14 +180,14 @@
|
|
|
180
180
|
v-if="editting"
|
|
181
181
|
@click="editting = false; mobileMenuOpen = false"
|
|
182
182
|
type="button"
|
|
183
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
183
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-slate-100"
|
|
184
184
|
>
|
|
185
185
|
Cancel
|
|
186
186
|
</button>
|
|
187
187
|
<button
|
|
188
188
|
v-if="editting"
|
|
189
189
|
:disabled="!canManipulate"
|
|
190
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
190
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-green-100']"
|
|
191
191
|
@click="shouldShowConfirmModal=true; mobileMenuOpen = false"
|
|
192
192
|
type="button"
|
|
193
193
|
>
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
<button
|
|
197
197
|
@click="refreshDocument({ force: true, source: 'manual' }); mobileMenuOpen = false"
|
|
198
198
|
:disabled="isRefreshing"
|
|
199
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
199
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']"
|
|
200
200
|
type="button"
|
|
201
201
|
>
|
|
202
202
|
{{isRefreshing ? 'Refreshing...' : 'Refresh'}}
|
|
@@ -204,35 +204,35 @@
|
|
|
204
204
|
<button
|
|
205
205
|
@click="toggleAutoRefresh(); mobileMenuOpen = false"
|
|
206
206
|
type="button"
|
|
207
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
207
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-slate-100"
|
|
208
208
|
>
|
|
209
209
|
Auto-Refresh {{autoRefreshEnabled ? 'ON' : 'OFF'}}
|
|
210
210
|
</button>
|
|
211
211
|
<button
|
|
212
212
|
@click="addField(); mobileMenuOpen = false"
|
|
213
213
|
type="button"
|
|
214
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
214
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-green-100"
|
|
215
215
|
>
|
|
216
216
|
Add Field
|
|
217
217
|
</button>
|
|
218
218
|
<button
|
|
219
219
|
@click="copyDocument(); mobileMenuOpen = false"
|
|
220
220
|
type="button"
|
|
221
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
221
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-blue-100"
|
|
222
222
|
>
|
|
223
223
|
Copy Document
|
|
224
224
|
</button>
|
|
225
225
|
<button
|
|
226
226
|
@click="openScriptDrawer()"
|
|
227
227
|
type="button"
|
|
228
|
-
class="flex items-center px-4 py-2 text-sm text-
|
|
228
|
+
class="flex items-center px-4 py-2 text-sm text-content-secondary hover:bg-indigo-100"
|
|
229
229
|
>
|
|
230
230
|
Run Script
|
|
231
231
|
</button>
|
|
232
232
|
<button
|
|
233
233
|
@click="shouldShowDeleteModal=true; mobileMenuOpen = false"
|
|
234
234
|
:disabled="!canManipulate"
|
|
235
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
235
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']"
|
|
236
236
|
type="button"
|
|
237
237
|
>
|
|
238
238
|
Delete
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
<button
|
|
241
241
|
@click="shouldShowCloneModal=true; mobileMenuOpen = false"
|
|
242
242
|
:disabled="!canManipulate"
|
|
243
|
-
:class="['flex items-center px-4 py-2 text-sm text-
|
|
243
|
+
:class="['flex items-center px-4 py-2 text-sm text-content-secondary', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']"
|
|
244
244
|
type="button"
|
|
245
245
|
>
|
|
246
246
|
Clone
|
|
@@ -289,5 +289,31 @@
|
|
|
289
289
|
@close="closeScriptDrawer"
|
|
290
290
|
@refresh="handleScriptRefresh"
|
|
291
291
|
></execute-script>
|
|
292
|
+
<div
|
|
293
|
+
v-if="keyboardShortcuts.length > 0"
|
|
294
|
+
class="fixed bottom-4 left-4 z-40 group"
|
|
295
|
+
>
|
|
296
|
+
<button
|
|
297
|
+
type="button"
|
|
298
|
+
aria-label="Keyboard shortcuts"
|
|
299
|
+
title="Keyboard shortcuts"
|
|
300
|
+
class="rounded-full border border-slate-300 bg-surface p-2 text-slate-700 shadow-sm transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-primary"
|
|
301
|
+
>
|
|
302
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
|
|
303
|
+
<rect x="2.5" y="6.5" width="19" height="11" rx="2" stroke-width="1.5"></rect>
|
|
304
|
+
<path d="M6 10.5h1.5M9 10.5h1.5M12 10.5h1.5M15 10.5h1.5M18 10.5h.01M6 13.5h1.5M9 13.5h6M16.5 13.5h1.5" stroke-width="1.5" stroke-linecap="round"></path>
|
|
305
|
+
</svg>
|
|
306
|
+
</button>
|
|
307
|
+
<div class="pointer-events-none absolute left-0 bottom-full mb-2 min-w-[220px] translate-y-1 rounded-lg bg-slate-900 px-3 py-2.5 text-slate-200 opacity-0 shadow-xl transition-all duration-150 group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-y-0 group-focus-within:opacity-100">
|
|
308
|
+
<div
|
|
309
|
+
v-for="shortcut in keyboardShortcuts"
|
|
310
|
+
:key="shortcut.command + shortcut.description"
|
|
311
|
+
class="flex items-center justify-between gap-3 text-xs"
|
|
312
|
+
>
|
|
313
|
+
<span class="font-mono font-semibold text-slate-50">{{shortcut.command}}</span>
|
|
314
|
+
<span class="text-slate-300">{{shortcut.description}}</span>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
292
318
|
</div>
|
|
293
319
|
</div>
|
|
@@ -40,11 +40,17 @@ module.exports = app => app.component('document', {
|
|
|
40
40
|
}),
|
|
41
41
|
async mounted() {
|
|
42
42
|
window.pageState = this;
|
|
43
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
44
|
+
window.addEventListener('keydown', this.handleSaveShortcut);
|
|
45
|
+
}
|
|
43
46
|
// Store query parameters from the route (preserved from models page)
|
|
44
47
|
this.previousQuery = Object.assign({}, this.$route.query);
|
|
45
48
|
await this.refreshDocument({ force: true, source: 'initial' });
|
|
46
49
|
},
|
|
47
|
-
|
|
50
|
+
beforeUnmount() {
|
|
51
|
+
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
52
|
+
window.removeEventListener('keydown', this.handleSaveShortcut);
|
|
53
|
+
}
|
|
48
54
|
this.stopAutoRefresh();
|
|
49
55
|
},
|
|
50
56
|
computed: {
|
|
@@ -74,6 +80,13 @@ module.exports = app => app.component('document', {
|
|
|
74
80
|
canEdit() {
|
|
75
81
|
return this.canManipulate && this.viewMode === 'fields';
|
|
76
82
|
},
|
|
83
|
+
keyboardShortcuts() {
|
|
84
|
+
const shortcuts = [];
|
|
85
|
+
if (this.editting && this.canManipulate) {
|
|
86
|
+
shortcuts.push({ command: 'Ctrl + S', description: 'Save document' });
|
|
87
|
+
}
|
|
88
|
+
return shortcuts;
|
|
89
|
+
},
|
|
77
90
|
isLambda() {
|
|
78
91
|
return !!window?.MONGOOSE_STUDIO_CONFIG?.isLambda;
|
|
79
92
|
}
|
|
@@ -86,6 +99,19 @@ module.exports = app => app.component('document', {
|
|
|
86
99
|
}
|
|
87
100
|
},
|
|
88
101
|
methods: {
|
|
102
|
+
handleSaveShortcut(event) {
|
|
103
|
+
const key = typeof event?.key === 'string' ? event.key.toLowerCase() : '';
|
|
104
|
+
const isSaveShortcut = (event.ctrlKey || event.metaKey) && key === 's';
|
|
105
|
+
if (!isSaveShortcut) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!this.editting || !this.canManipulate) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
this.shouldShowConfirmModal = true;
|
|
114
|
+
},
|
|
89
115
|
cancelEdit() {
|
|
90
116
|
this.changes = {};
|
|
91
117
|
this.editting = false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<div v-if="isOpen" class="fixed inset-0 z-50 execute-script-drawer" :class="{ 'is-closing': isClosing }">
|
|
2
2
|
<div class="execute-script-backdrop absolute inset-0 bg-black/40" @click="close"></div>
|
|
3
|
-
<div class="execute-script-panel absolute right-0 top-0 h-full w-full max-w-xl bg-
|
|
4
|
-
<div class="flex items-center justify-between px-5 py-4 border-b border-
|
|
3
|
+
<div class="execute-script-panel absolute right-0 top-0 h-full w-full max-w-xl bg-surface shadow-xl flex flex-col">
|
|
4
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-edge">
|
|
5
5
|
<div>
|
|
6
|
-
<h2 class="text-lg font-semibold text-
|
|
7
|
-
<p class="text-xs text-
|
|
6
|
+
<h2 class="text-lg font-semibold text-content">Run Script</h2>
|
|
7
|
+
<p class="text-xs text-content-tertiary">Use <code class="bg-muted px-1 rounded">doc</code> for this document.</p>
|
|
8
8
|
</div>
|
|
9
9
|
<button
|
|
10
10
|
type="button"
|
|
@@ -17,16 +17,15 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
<div class="flex-1 overflow-auto p-5 space-y-4">
|
|
19
19
|
<div class="space-y-2">
|
|
20
|
-
<label class="text-sm font-medium text-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<p class="text-xs text-gray-500">Return a value to see it in the output panel.</p>
|
|
20
|
+
<label class="text-sm font-medium text-content-secondary">Script</label>
|
|
21
|
+
<ace-editor
|
|
22
|
+
v-model="scriptText"
|
|
23
|
+
mode="javascript"
|
|
24
|
+
:line-numbers="true"
|
|
25
|
+
:wrap="true"
|
|
26
|
+
class="min-h-[200px]"
|
|
27
|
+
/>
|
|
28
|
+
<p class="text-xs text-content-tertiary">Return a value to see it in the output panel.</p>
|
|
30
29
|
</div>
|
|
31
30
|
<div class="flex items-center gap-3">
|
|
32
31
|
<button
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
<button
|
|
42
41
|
type="button"
|
|
43
42
|
@click="clearScript"
|
|
44
|
-
class="text-sm text-
|
|
43
|
+
class="text-sm text-content-tertiary hover:text-content-secondary"
|
|
45
44
|
>
|
|
46
45
|
Clear
|
|
47
46
|
</button>
|
|
@@ -50,17 +49,17 @@
|
|
|
50
49
|
<div v-if="scriptError" class="rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-700">
|
|
51
50
|
{{scriptError}}
|
|
52
51
|
</div>
|
|
53
|
-
<div v-if="scriptHasRun" class="rounded-md border border-
|
|
54
|
-
<div class="text-xs uppercase tracking-wide text-
|
|
52
|
+
<div v-if="scriptHasRun" class="rounded-md border border-edge bg-page p-3">
|
|
53
|
+
<div class="text-xs uppercase tracking-wide text-content-tertiary mb-2">Output</div>
|
|
55
54
|
<pre class="whitespace-pre-wrap text-sm text-gray-800">{{formatScriptOutput(scriptResult)}}</pre>
|
|
56
55
|
</div>
|
|
57
|
-
<div v-if="scriptLogs" class="rounded-md border border-
|
|
58
|
-
<div class="text-xs uppercase tracking-wide text-
|
|
59
|
-
<pre class="whitespace-pre-wrap text-xs text-
|
|
56
|
+
<div v-if="scriptLogs" class="rounded-md border border-edge bg-surface p-3">
|
|
57
|
+
<div class="text-xs uppercase tracking-wide text-content-tertiary mb-2">Logs</div>
|
|
58
|
+
<pre class="whitespace-pre-wrap text-xs text-content-secondary">{{scriptLogs}}</pre>
|
|
60
59
|
</div>
|
|
61
60
|
</div>
|
|
62
61
|
</div>
|
|
63
|
-
<div class="border-t border-
|
|
62
|
+
<div class="border-t border-edge px-5 py-3 text-xs text-content-tertiary">
|
|
64
63
|
Scripts run on the server with access to the Mongoose document instance.
|
|
65
64
|
</div>
|
|
66
65
|
</div>
|
|
@@ -17,7 +17,6 @@ module.exports = app => app.component('execute-script', {
|
|
|
17
17
|
scriptError: null,
|
|
18
18
|
scriptHasRun: false,
|
|
19
19
|
scriptRunning: false,
|
|
20
|
-
scriptEditor: null,
|
|
21
20
|
isOpen: false,
|
|
22
21
|
isClosing: false
|
|
23
22
|
};
|
|
@@ -29,19 +28,11 @@ module.exports = app => app.component('execute-script', {
|
|
|
29
28
|
this.isClosing = false;
|
|
30
29
|
} else if (this.isOpen) {
|
|
31
30
|
this.isClosing = true;
|
|
32
|
-
this.destroyScriptEditor();
|
|
33
31
|
setTimeout(() => {
|
|
34
32
|
this.isOpen = false;
|
|
35
33
|
this.isClosing = false;
|
|
36
34
|
}, 200);
|
|
37
35
|
}
|
|
38
|
-
},
|
|
39
|
-
isOpen(newVal) {
|
|
40
|
-
if (newVal) {
|
|
41
|
-
this.$nextTick(() => {
|
|
42
|
-
this.initializeScriptEditor();
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
36
|
}
|
|
46
37
|
},
|
|
47
38
|
mounted() {
|
|
@@ -49,46 +40,16 @@ module.exports = app => app.component('execute-script', {
|
|
|
49
40
|
this.isOpen = true;
|
|
50
41
|
}
|
|
51
42
|
},
|
|
52
|
-
beforeDestroy() {
|
|
53
|
-
this.destroyScriptEditor();
|
|
54
|
-
},
|
|
55
43
|
methods: {
|
|
56
44
|
close() {
|
|
57
45
|
this.$emit('close');
|
|
58
46
|
},
|
|
59
|
-
initializeScriptEditor() {
|
|
60
|
-
if (!this.$refs.scriptEditor || this.scriptEditor || typeof CodeMirror === 'undefined') {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.$refs.scriptEditor.value = this.scriptText;
|
|
65
|
-
this.scriptEditor = CodeMirror.fromTextArea(this.$refs.scriptEditor, {
|
|
66
|
-
mode: 'javascript',
|
|
67
|
-
lineNumbers: true,
|
|
68
|
-
lineWrapping: true
|
|
69
|
-
});
|
|
70
|
-
this.scriptEditor.on('change', () => {
|
|
71
|
-
this.scriptText = this.scriptEditor.getValue();
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
destroyScriptEditor() {
|
|
75
|
-
if (this.scriptEditor) {
|
|
76
|
-
this.scriptEditor.toTextArea();
|
|
77
|
-
this.scriptEditor = null;
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
updateScriptText(event) {
|
|
81
|
-
this.scriptText = event.target.value;
|
|
82
|
-
},
|
|
83
47
|
clearScript() {
|
|
84
48
|
this.scriptText = '';
|
|
85
49
|
this.scriptResult = null;
|
|
86
50
|
this.scriptLogs = '';
|
|
87
51
|
this.scriptError = null;
|
|
88
52
|
this.scriptHasRun = false;
|
|
89
|
-
if (this.scriptEditor) {
|
|
90
|
-
this.scriptEditor.setValue('');
|
|
91
|
-
}
|
|
92
53
|
},
|
|
93
54
|
formatScriptOutput(value) {
|
|
94
55
|
if (value === undefined) {
|
|
@@ -107,7 +68,7 @@ module.exports = app => app.component('execute-script', {
|
|
|
107
68
|
}
|
|
108
69
|
},
|
|
109
70
|
async runDocumentScript() {
|
|
110
|
-
const scriptToRun = (this.
|
|
71
|
+
const scriptToRun = (this.scriptText || '').trim();
|
|
111
72
|
if (!scriptToRun) {
|
|
112
73
|
this.$toast.error('Script cannot be empty.');
|
|
113
74
|
return;
|
|
@@ -123,9 +84,6 @@ module.exports = app => app.component('execute-script', {
|
|
|
123
84
|
script: scriptToRun
|
|
124
85
|
});
|
|
125
86
|
this.scriptText = scriptToRun;
|
|
126
|
-
if (this.scriptEditor) {
|
|
127
|
-
this.scriptEditor.setValue(scriptToRun);
|
|
128
|
-
}
|
|
129
87
|
this.scriptResult = result;
|
|
130
88
|
this.scriptLogs = logs;
|
|
131
89
|
this.scriptHasRun = true;
|
|
@@ -70,21 +70,16 @@
|
|
|
70
70
|
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/*
|
|
74
|
-
.add-field-modal .
|
|
73
|
+
/* Ace editor styling in modal */
|
|
74
|
+
.add-field-modal .add-field-ace-editor.ace_editor {
|
|
75
75
|
border: 1px solid #d1d5db;
|
|
76
76
|
border-radius: 0.375rem;
|
|
77
77
|
font-size: 14px;
|
|
78
|
-
height: auto;
|
|
79
78
|
min-height: 100px;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
.add-field-modal .
|
|
83
|
-
|
|
84
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.add-field-modal .CodeMirror.CodeMirror-focused {
|
|
81
|
+
.add-field-modal .add-field-ace-editor:focus-within.ace_editor,
|
|
82
|
+
.add-field-modal .add-field-ace-editor.ace_focus {
|
|
88
83
|
border-color: #3b82f6;
|
|
89
84
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
90
85
|
}
|