@mongoosejs/studio 0.2.13 → 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.
Files changed (81) hide show
  1. package/backend/actions/ChatMessage/executeScript.js +5 -1
  2. package/backend/actions/ChatThread/createChatMessage.js +2 -1
  3. package/backend/actions/ChatThread/streamChatMessage.js +2 -2
  4. package/eslint.config.js +4 -1
  5. package/frontend/public/app.js +24642 -543
  6. package/frontend/public/dark-theme.css +365 -0
  7. package/frontend/public/images/mongoose-studio.svg +4 -0
  8. package/frontend/public/index.html +21 -1
  9. package/frontend/public/style.css +5 -7
  10. package/frontend/public/theme-variables.css +294 -0
  11. package/frontend/public/tw.css +305 -252
  12. package/frontend/src/ace-editor/ace-editor.html +4 -0
  13. package/frontend/src/ace-editor/ace-editor.js +89 -0
  14. package/frontend/src/aceEditor.js +69 -0
  15. package/frontend/src/chat/chat-message/chat-message.html +1 -1
  16. package/frontend/src/chat/chat-message/chat-message.js +1 -1
  17. package/frontend/src/chat/chat-message-script/chat-message-script.html +51 -34
  18. package/frontend/src/chat/chat-message-script/chat-message-script.js +12 -55
  19. package/frontend/src/chat/chat.html +68 -39
  20. package/frontend/src/chat/chat.js +26 -2
  21. package/frontend/src/clone-document/clone-document.html +7 -2
  22. package/frontend/src/clone-document/clone-document.js +1 -8
  23. package/frontend/src/create-dashboard/create-dashboard.html +11 -6
  24. package/frontend/src/create-dashboard/create-dashboard.js +0 -7
  25. package/frontend/src/create-document/create-document.html +15 -9
  26. package/frontend/src/create-document/create-document.js +5 -12
  27. package/frontend/src/dashboard/dashboard.html +14 -12
  28. package/frontend/src/dashboard/dashboard.js +12 -4
  29. package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +13 -7
  30. package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +13 -21
  31. package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +19 -17
  32. package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +97 -2
  33. package/frontend/src/dashboard-result/dashboard-map/dashboard-map.js +27 -3
  34. package/frontend/src/dashboard-result/dashboard-result.html +3 -3
  35. package/frontend/src/dashboards/dashboards.html +101 -109
  36. package/frontend/src/dashboards/dashboards.js +25 -1
  37. package/frontend/src/detail-default/detail-default.html +2 -2
  38. package/frontend/src/detail-default/detail-default.js +24 -3
  39. package/frontend/src/document/confirm-changes/confirm-changes.html +1 -1
  40. package/frontend/src/document/confirm-delete/confirm-delete.html +1 -1
  41. package/frontend/src/document/document.css +1 -1
  42. package/frontend/src/document/document.html +28 -28
  43. package/frontend/src/document/execute-script/execute-script.html +20 -21
  44. package/frontend/src/document/execute-script/execute-script.js +1 -43
  45. package/frontend/src/document-details/document-details.css +4 -9
  46. package/frontend/src/document-details/document-details.html +34 -33
  47. package/frontend/src/document-details/document-details.js +2 -53
  48. package/frontend/src/document-details/document-property/document-property.html +12 -12
  49. package/frontend/src/edit-array/edit-array.html +7 -6
  50. package/frontend/src/edit-array/edit-array.js +10 -50
  51. package/frontend/src/edit-boolean/edit-boolean.html +12 -12
  52. package/frontend/src/edit-date/edit-date.html +2 -2
  53. package/frontend/src/edit-default/edit-default.html +1 -1
  54. package/frontend/src/edit-string/edit-string.html +3 -3
  55. package/frontend/src/edit-subdocument/edit-subdocument.html +5 -3
  56. package/frontend/src/edit-subdocument/edit-subdocument.js +1 -15
  57. package/frontend/src/export-query-results/export-query-results.html +3 -3
  58. package/frontend/src/json-node/json-node.html +3 -3
  59. package/frontend/src/list-json/json-node.html +1 -1
  60. package/frontend/src/models/document-search/document-search.html +3 -3
  61. package/frontend/src/models/model-switcher/model-switcher.html +53 -0
  62. package/frontend/src/models/model-switcher/model-switcher.js +123 -0
  63. package/frontend/src/models/models.css +3 -10
  64. package/frontend/src/models/models.html +146 -80
  65. package/frontend/src/models/models.js +108 -4
  66. package/frontend/src/navbar/navbar.html +157 -97
  67. package/frontend/src/navbar/navbar.js +31 -12
  68. package/frontend/src/routes.js +1 -1
  69. package/frontend/src/splash/splash.html +5 -5
  70. package/frontend/src/task-single/task-single.html +29 -29
  71. package/frontend/src/task-single/task-single.js +10 -10
  72. package/frontend/src/tasks/task-details/task-details.html +38 -38
  73. package/frontend/src/tasks/task-details/task-details.js +7 -2
  74. package/frontend/src/tasks/tasks.html +36 -35
  75. package/frontend/src/tasks/tasks.js +2 -25
  76. package/frontend/src/team/new-invitation/new-invitation.html +8 -8
  77. package/frontend/src/team/team.html +27 -27
  78. package/frontend/src/update-document/update-document.html +7 -2
  79. package/frontend/src/update-document/update-document.js +2 -11
  80. package/package.json +2 -1
  81. 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-white p-4 border-b border-gray-200 shadow-sm">
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-gray-700 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-gray-300 border-r-0 rounded-l-lg rounded-r-none"
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-gray-700 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-gray-300 rounded-r-lg rounded-l-none"
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-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">
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-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
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-white ring-1 ring-black ring-opacity-5 z-50"
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-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']"
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-gray-700 hover:bg-slate-100']"
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-gray-700 hover:bg-green-100"
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-gray-700 hover:bg-blue-100"
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-gray-700 hover:bg-indigo-100"
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-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']"
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-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']"
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-gray-700 hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
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-white ring-1 ring-black ring-opacity-5 z-50"
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-gray-700', !canEdit ? 'cursor-not-allowed opacity-50' : 'hover:bg-ultramarine-100']"
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-gray-700 hover:bg-slate-100"
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-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-green-100']"
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-gray-700', isRefreshing ? 'cursor-not-allowed opacity-50' : 'hover:bg-slate-100']"
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-gray-700 hover:bg-slate-100"
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-gray-700 hover:bg-green-100"
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-gray-700 hover:bg-blue-100"
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-gray-700 hover:bg-indigo-100"
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-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-red-100']"
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-gray-700', !canManipulate ? 'cursor-not-allowed opacity-50' : 'hover:bg-pink-100']"
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
@@ -297,7 +297,7 @@
297
297
  type="button"
298
298
  aria-label="Keyboard shortcuts"
299
299
  title="Keyboard shortcuts"
300
- class="rounded-full border border-slate-300 bg-white p-2 text-slate-700 shadow-sm transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-ultramarine-500"
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
301
  >
302
302
  <svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
303
303
  <rect x="2.5" y="6.5" width="19" height="11" rx="2" stroke-width="1.5"></rect>
@@ -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-white shadow-xl flex flex-col">
4
- <div class="flex items-center justify-between px-5 py-4 border-b border-gray-200">
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-gray-900">Run Script</h2>
7
- <p class="text-xs text-gray-500">Use <code class="bg-gray-100 px-1 rounded">doc</code> for this document.</p>
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-gray-700">Script</label>
21
- <textarea
22
- ref="scriptEditor"
23
- :value="scriptText"
24
- @input="updateScriptText"
25
- rows="8"
26
- placeholder="await doc.updateName('new name')&#10;return doc"
27
- class="w-full rounded-md border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 font-mono text-sm"
28
- ></textarea>
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-gray-500 hover:text-gray-700"
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-gray-200 bg-gray-50 p-3">
54
- <div class="text-xs uppercase tracking-wide text-gray-500 mb-2">Output</div>
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-gray-200 bg-white p-3">
58
- <div class="text-xs uppercase tracking-wide text-gray-500 mb-2">Logs</div>
59
- <pre class="whitespace-pre-wrap text-xs text-gray-700">{{scriptLogs}}</pre>
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-gray-200 px-5 py-3 text-xs text-gray-500">
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.scriptEditor ? this.scriptEditor.getValue() : this.scriptText || '').trim();
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
- /* CodeMirror styling in modal */
74
- .add-field-modal .CodeMirror {
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 .CodeMirror:focus-within {
83
- border-color: #3b82f6;
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
  }
@@ -1,6 +1,6 @@
1
1
  <div class="document-details">
2
2
  <!-- View Toggle and Search/Filter Bar -->
3
- <div class="sticky top-[60px] z-40 bg-white rounded-md p-4 border-b border-gray-200 shadow-sm">
3
+ <div class="sticky top-[60px] z-40 bg-surface rounded-md p-4 border-b border-edge shadow-sm">
4
4
 
5
5
  <!-- Search and Filter Bar (only show in fields view) -->
6
6
  <div v-if="viewMode === 'fields'" class="flex md:gap-3">
@@ -11,7 +11,7 @@
11
11
  v-model="searchQuery"
12
12
  type="text"
13
13
  placeholder="Search fields..."
14
- class="w-full px-4 py-2 pl-10 pr-4 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
14
+ class="w-full px-4 py-2 pl-10 pr-4 text-sm border border-edge-strong rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
15
15
  />
16
16
  <div class="absolute inset-y-0 left-0 flex items-center pl-3">
17
17
  <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -24,7 +24,7 @@
24
24
  <div class="relative hidden md:block">
25
25
  <select
26
26
  v-model="selectedType"
27
- class="px-4 py-2 pr-8 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white min-w-[140px] appearance-none"
27
+ class="px-4 py-2 pr-8 text-sm border border-edge-strong rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-surface min-w-[140px] appearance-none"
28
28
  >
29
29
  <option value="">All Types</option>
30
30
  <option v-for="type in availableTypes" :key="type" :value="type">
@@ -62,24 +62,24 @@
62
62
  <div
63
63
  v-for="path in matchedVirtuals"
64
64
  :key="path.name"
65
- class="border border-gray-200 rounded-lg mb-2 transition-all duration-200 ease-in-out mt-4"
65
+ class="border border-edge rounded-lg mb-2 transition-all duration-200 ease-in-out mt-4"
66
66
  >
67
67
  <!-- Virtual Field Header (Always Visible) -->
68
68
  <div
69
69
  @click="toggleVirtualField(path.name)"
70
- class="p-3 bg-amber-100 hover:bg-amber-200 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
70
+ class="p-3 bg-amber-100 hover:bg-amber-200 cursor-pointer flex items-center justify-between border-b border-edge transition-colors duration-200 ease-in-out"
71
71
  >
72
72
  <div class="flex items-center">
73
73
  <svg
74
74
  :class="isVirtualFieldCollapsed(path.name) ? 'rotate-0' : 'rotate-90'"
75
- class="w-4 h-4 text-gray-500 mr-2 transition-transform duration-200"
75
+ class="w-4 h-4 text-content-tertiary mr-2 transition-transform duration-200"
76
76
  fill="none"
77
77
  stroke="currentColor"
78
78
  viewBox="0 0 24 24"
79
79
  >
80
80
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
81
81
  </svg>
82
- <span class="font-medium text-gray-900">{{path.name}}</span>
82
+ <span class="font-medium text-content">{{path.name}}</span>
83
83
  <span v-if="path.isVirtual" class="ml-2 text-sm text-purple-600">(virtual - {{getVirtualFieldType(path)}})</span>
84
84
  <span v-else class="ml-2 text-sm text-blue-600">(user-added - {{getVirtualFieldType(path)}})</span>
85
85
  </div>
@@ -116,24 +116,24 @@
116
116
  <div
117
117
  v-for="path in unmatchedVirtuals"
118
118
  :key="path.name"
119
- class="border border-gray-200 rounded-lg mb-2 transition-all duration-200 ease-in-out"
119
+ class="border border-edge rounded-lg mb-2 transition-all duration-200 ease-in-out"
120
120
  >
121
121
  <!-- Virtual Field Header (Always Visible) -->
122
122
  <div
123
123
  @click="toggleVirtualField(path.name)"
124
- class="p-3 bg-gray-50 hover:bg-gray-100 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
124
+ class="p-3 bg-page hover:bg-muted cursor-pointer flex items-center justify-between border-b border-edge transition-colors duration-200 ease-in-out"
125
125
  >
126
126
  <div class="flex items-center">
127
127
  <svg
128
128
  :class="isVirtualFieldCollapsed(path.name) ? 'rotate-0' : 'rotate-90'"
129
- class="w-4 h-4 text-gray-500 mr-2 transition-transform duration-200"
129
+ class="w-4 h-4 text-content-tertiary mr-2 transition-transform duration-200"
130
130
  fill="none"
131
131
  stroke="currentColor"
132
132
  viewBox="0 0 24 24"
133
133
  >
134
134
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
135
135
  </svg>
136
- <span class="font-medium text-gray-900">{{path.name}}</span>
136
+ <span class="font-medium text-content">{{path.name}}</span>
137
137
  <span v-if="path.isVirtual" class="ml-2 text-sm text-purple-600">(virtual - {{getVirtualFieldType(path)}})</span>
138
138
  <span v-else class="ml-2 text-sm text-blue-600">(user-added - {{getVirtualFieldType(path)}})</span>
139
139
  </div>
@@ -151,7 +151,7 @@
151
151
  </div>
152
152
 
153
153
  <!-- No Results Message -->
154
- <div v-if="searchQuery.trim() && !hasSearchMatches" class="text-center py-8 text-gray-500">
154
+ <div v-if="searchQuery.trim() && !hasSearchMatches" class="text-center py-8 text-content-tertiary">
155
155
  <svg class="w-12 h-12 mx-auto mb-4 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
156
156
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.29-1.009-5.824-2.709M15 6.291A7.962 7.962 0 0012 5c-2.34 0-4.29 1.009-5.824 2.709"></path>
157
157
  </svg>
@@ -161,7 +161,7 @@
161
161
 
162
162
  <!-- JSON View -->
163
163
  <div v-if="viewMode === 'json'" class="json-view">
164
- <div class="border border-gray-300 rounded-lg bg-gray-50 p-4 overflow-auto">
164
+ <div class="border border-edge-strong rounded-lg bg-page p-4 overflow-auto">
165
165
  <pre class="text-sm font-mono text-gray-800 whitespace-pre">{{formattedJson}}</pre>
166
166
  </div>
167
167
  </div>
@@ -172,14 +172,14 @@
172
172
  <div class="modal-exit" @click="closeAddFieldModal">&times;</div>
173
173
  <div class="add-field-modal">
174
174
  <div class="mb-6">
175
- <h2 class="text-xl font-semibold text-gray-900 mb-2">Add New Field</h2>
175
+ <h2 class="text-xl font-semibold text-content mb-2">Add New Field</h2>
176
176
  <p class="text-sm text-gray-600">Create a new field for this document</p>
177
177
  </div>
178
178
 
179
179
  <form @submit.prevent="handleAddFieldSubmit" class="space-y-4">
180
180
  <!-- Field Name -->
181
181
  <div>
182
- <label for="fieldName" class="block text-sm font-medium text-gray-700 mb-1">
182
+ <label for="fieldName" class="block text-sm font-medium text-content-secondary mb-1">
183
183
  Field Name *
184
184
  </label>
185
185
  <input
@@ -188,7 +188,7 @@
188
188
  type="text"
189
189
  required
190
190
  placeholder="Enter field name..."
191
- class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
191
+ class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
192
192
  :class="{ 'border-red-500': fieldErrors.name }"
193
193
  />
194
194
  <p v-if="fieldErrors.name" class="mt-1 text-sm text-red-600">{{fieldErrors.name}}</p>
@@ -199,14 +199,14 @@
199
199
 
200
200
  <!-- Field Type -->
201
201
  <div>
202
- <label for="fieldType" class="block text-sm font-medium text-gray-700 mb-1">
202
+ <label for="fieldType" class="block text-sm font-medium text-content-secondary mb-1">
203
203
  Field Type *
204
204
  </label>
205
205
  <select
206
206
  id="fieldType"
207
207
  v-model="fieldData.type"
208
208
  required
209
- class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
209
+ class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
210
210
  :class="{ 'border-red-500': fieldErrors.type }"
211
211
  >
212
212
  <option value="">Select field type...</option>
@@ -219,7 +219,7 @@
219
219
 
220
220
  <!-- Field Value -->
221
221
  <div>
222
- <label for="fieldValue" class="block text-sm font-medium text-gray-700 mb-1">
222
+ <label for="fieldValue" class="block text-sm font-medium text-content-secondary mb-1">
223
223
  Initial Value
224
224
  </label>
225
225
 
@@ -229,47 +229,48 @@
229
229
  v-model="fieldData.value"
230
230
  type="date"
231
231
  id="fieldValue"
232
- class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
232
+ class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
233
233
  :class="{ 'border-red-500': fieldErrors.value }"
234
234
  />
235
235
 
236
236
  <!-- Simple input for basic types -->
237
237
  <input
238
- v-else-if="!shouldUseCodeMirror"
238
+ v-else-if="!shouldUseAce"
239
239
  v-model="fieldData.value"
240
240
  type="text"
241
241
  id="fieldValue"
242
242
  placeholder="Enter initial value (optional)..."
243
- class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
243
+ class="w-full px-3 py-2 border border-edge-strong rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
244
244
  :class="{ 'border-red-500': fieldErrors.value }"
245
245
  />
246
246
 
247
- <!-- CodeMirror textarea for complex types -->
248
- <textarea
247
+ <!-- Ace editor for complex types (Array/Object/Embedded) -->
248
+ <ace-editor
249
249
  v-else
250
- ref="fieldValueEditor"
251
250
  id="fieldValue"
252
- rows="3"
253
- placeholder="Enter initial value (optional)..."
254
- class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
251
+ v-model="fieldData.value"
252
+ mode="json"
253
+ :line-numbers="true"
254
+ :min-lines="3"
255
+ class="add-field-ace-editor w-full min-h-[100px]"
255
256
  :class="{ 'border-red-500': fieldErrors.value }"
256
- ></textarea>
257
+ />
257
258
 
258
259
  <p v-if="fieldErrors.value" class="mt-1 text-sm text-red-600">{{fieldErrors.value}}</p>
259
- <p class="mt-1 text-xs text-gray-500">
260
+ <p class="mt-1 text-xs text-content-tertiary">
260
261
  <span v-if="shouldUseDatePicker">Select a date or leave empty for null/undefined values.</span>
261
- <span v-else-if="shouldUseCodeMirror">Leave empty for null/undefined values. Use valid JSON format.</span>
262
+ <span v-else-if="shouldUseAce">Leave empty for null/undefined values. Use valid JSON format.</span>
262
263
  <span v-else>Leave empty for null/undefined values.</span>
263
264
  </p>
264
265
  </div>
265
266
 
266
267
 
267
268
  <!-- Action Buttons -->
268
- <div class="flex justify-end gap-3 pt-4 border-t border-gray-200">
269
+ <div class="flex justify-end gap-3 pt-4 border-t border-edge">
269
270
  <button
270
271
  type="button"
271
272
  @click="closeAddFieldModal"
272
- class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
273
+ class="px-4 py-2 text-sm font-medium text-content-secondary bg-surface border border-edge-strong rounded-md hover:bg-page focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
273
274
  >
274
275
  Cancel
275
276
  </button>