@mongoosejs/studio 0.5.1 → 0.5.3
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/ChatThread/streamChatMessage.js +12 -12
- package/backend/actions/Dashboard/getDashboard.js +29 -2
- package/backend/actions/Model/dropCollection.js +29 -0
- package/backend/actions/Model/index.js +1 -0
- package/backend/authorize.js +1 -0
- package/backend/chatAgent/agentSystemPrompt.js +22 -10
- package/backend/chatAgent/getAgentTools.js +19 -8
- package/backend/chatAgent/runChatAgent.js +17 -0
- package/backend/db/dashboardSchema.js +0 -32
- package/backend/index.js +4 -1
- package/backend/integrations/callLLM.js +5 -20
- package/backend/integrations/streamLLM.js +5 -24
- package/backend/sandbox/createSandbox.js +6 -0
- package/backend/vercel.js +3 -0
- package/debugging.js +11 -0
- package/eval/agent/cases.js +168 -0
- package/eval/agent/fixtures/carsharing.js +147 -0
- package/eval/agent/fixtures/ecommerce.js +152 -0
- package/eval/agent/run.js +323 -0
- package/frontend/index.js +2 -1
- package/frontend/public/app.js +581 -203
- package/frontend/public/tw.css +81 -0
- package/frontend/src/_util/recent-pages-history.js +116 -0
- package/frontend/src/api.js +96 -164
- package/frontend/src/chat/chat-message-script/chat-message-script.html +1 -6
- package/frontend/src/chat/chat.html +1 -1
- package/frontend/src/document/confirm-changes/confirm-changes.js +20 -0
- package/frontend/src/document/document.html +2 -2
- package/frontend/src/index.js +148 -1
- package/frontend/src/json-node/json-node.html +41 -39
- package/frontend/src/json-node/json-node.js +38 -0
- package/frontend/src/list-json/list-json.html +3 -2
- package/frontend/src/list-json/list-json.js +5 -0
- package/frontend/src/modal/modal.css +26 -1
- package/frontend/src/modal/modal.html +2 -2
- package/frontend/src/modal/modal.js +5 -1
- package/frontend/src/models/models.html +45 -5
- package/frontend/src/models/models.js +26 -0
- package/frontend/src/navbar/navbar.html +92 -5
- package/frontend/src/navbar/navbar.js +69 -1
- package/index.js +2 -1
- package/package.json +3 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<div>
|
|
1
2
|
<div class="navbar w-full bg-page border-b border-edge !h-[55px] hidden md:grid grid-cols-[1fr_auto_1fr] items-stretch px-4">
|
|
2
3
|
<!-- Left: Logo + Brand -->
|
|
3
4
|
<div class="flex items-center gap-2 self-center">
|
|
@@ -31,10 +32,18 @@
|
|
|
31
32
|
<path fill-rule="evenodd" d="M10 2a4 4 0 00-4 4v2H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-1V6a4 4 0 00-4-4zm-3 6V6a3 3 0 116 0v2H7z" clip-rule="evenodd" />
|
|
32
33
|
</svg>
|
|
33
34
|
</span>
|
|
34
|
-
<a v-if="hasAccess(roles, 'chat')"
|
|
35
|
+
<a v-if="hasAccess(roles, 'chat') && hasLLMAPIKey"
|
|
35
36
|
href="#/chat"
|
|
36
37
|
class="inline-flex items-center px-1 border-b-2 text-sm font-medium"
|
|
37
38
|
:class="chatView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'">Chat</a>
|
|
39
|
+
<span v-else-if="hasAccess(roles, 'chat') && !hasLLMAPIKey"
|
|
40
|
+
class="inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-gray-300 cursor-not-allowed"
|
|
41
|
+
:title="chatDisabledReason">
|
|
42
|
+
Chat
|
|
43
|
+
<svg class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
44
|
+
<path fill-rule="evenodd" d="M10 2a4 4 0 00-4 4v2H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-1V6a4 4 0 00-4-4zm-3 6V6a3 3 0 116 0v2H7z" clip-rule="evenodd" />
|
|
45
|
+
</svg>
|
|
46
|
+
</span>
|
|
38
47
|
<span v-else class="inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-gray-300 cursor-not-allowed">
|
|
39
48
|
Chat
|
|
40
49
|
<svg class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
@@ -59,6 +68,19 @@
|
|
|
59
68
|
</nav>
|
|
60
69
|
<!-- Right: Env Badge + User -->
|
|
61
70
|
<div class="flex items-center justify-end gap-3 self-center">
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
class="inline-flex items-center justify-center rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary"
|
|
74
|
+
title="Recent pages"
|
|
75
|
+
aria-label="Recent pages"
|
|
76
|
+
aria-haspopup="dialog"
|
|
77
|
+
:aria-expanded="showRecentPagesModal ? 'true' : 'false'"
|
|
78
|
+
@click="openRecentPagesModal"
|
|
79
|
+
>
|
|
80
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-5 w-5" aria-hidden="true">
|
|
81
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
82
|
+
</svg>
|
|
83
|
+
</button>
|
|
62
84
|
<div
|
|
63
85
|
v-if="!!state.nodeEnv"
|
|
64
86
|
title="NODE_ENV"
|
|
@@ -141,9 +163,22 @@
|
|
|
141
163
|
<span class="text-base font-semibold text-content">Mongoose Studio</span>
|
|
142
164
|
</router-link>
|
|
143
165
|
</div>
|
|
144
|
-
<div class="flex items-center">
|
|
166
|
+
<div class="flex items-center gap-1 pr-2">
|
|
167
|
+
<button
|
|
168
|
+
type="button"
|
|
169
|
+
class="rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary md:hidden"
|
|
170
|
+
title="Recent pages"
|
|
171
|
+
aria-label="Recent pages"
|
|
172
|
+
aria-haspopup="dialog"
|
|
173
|
+
:aria-expanded="showRecentPagesModal ? 'true' : 'false'"
|
|
174
|
+
@click="openRecentPagesModal"
|
|
175
|
+
>
|
|
176
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-6 w-6" aria-hidden="true">
|
|
177
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
178
|
+
</svg>
|
|
179
|
+
</button>
|
|
145
180
|
<!-- Mobile menu toggle, controls the 'mobileMenuOpen' state. -->
|
|
146
|
-
<button type="button" id="open-mobile-menu" class="-ml-2 rounded-md p-2
|
|
181
|
+
<button type="button" id="open-mobile-menu" class="-ml-2 rounded-md p-2 text-gray-400">
|
|
147
182
|
<span class="sr-only">Open menu</span>
|
|
148
183
|
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
149
184
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
|
@@ -154,7 +189,7 @@
|
|
|
154
189
|
<!-- Mobile menu mask -->
|
|
155
190
|
<div id="mobile-menu-mask" class="fixed inset-0 bg-black bg-opacity-40 z-40 hidden"></div>
|
|
156
191
|
<!-- Mobile menu drawer -->
|
|
157
|
-
<div id="mobile-menu" style="z-index:
|
|
192
|
+
<div id="mobile-menu" style="z-index: 100000" class="fixed inset-0 bg-page shadow-lg transform translate-x-full transition-transform duration-200 ease-in-out flex flex-col">
|
|
158
193
|
<div class="flex items-center justify-between px-4 !h-[55px] border-b border-edge">
|
|
159
194
|
<router-link :to="{ name: defaultRoute }">
|
|
160
195
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-[32px] text-primary" viewBox="0 0 250 250" fill="currentColor" aria-label="Mongoose Studio Logo">
|
|
@@ -201,10 +236,18 @@
|
|
|
201
236
|
<path fill-rule="evenodd" d="M10 2a4 4 0 00-4 4v2H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-1V6a4 4 0 00-4-4zm-3 6V6a3 3 0 116 0v2H7z" clip-rule="evenodd" />
|
|
202
237
|
</svg>
|
|
203
238
|
</span>
|
|
204
|
-
<a v-if="hasAccess(roles, 'chat')"
|
|
239
|
+
<a v-if="hasAccess(roles, 'chat') && hasLLMAPIKey"
|
|
205
240
|
href="#/chat"
|
|
206
241
|
class="block px-3 py-2 rounded-md text-base font-medium"
|
|
207
242
|
:class="chatView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'">Chat</a>
|
|
243
|
+
<span v-else-if="hasAccess(roles, 'chat') && !hasLLMAPIKey"
|
|
244
|
+
class="block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed"
|
|
245
|
+
:title="chatDisabledReason">
|
|
246
|
+
Chat
|
|
247
|
+
<svg class="h-4 w-4 ml-1 inline" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
248
|
+
<path fill-rule="evenodd" d="M10 2a4 4 0 00-4 4v2H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-1V6a4 4 0 00-4-4zm-3 6V6a3 3 0 116 0v2H7z" clip-rule="evenodd" />
|
|
249
|
+
</svg>
|
|
250
|
+
</span>
|
|
208
251
|
<span v-else class="block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed">
|
|
209
252
|
Chat
|
|
210
253
|
<svg class="h-4 w-4 ml-1 inline" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
@@ -250,3 +293,47 @@
|
|
|
250
293
|
</nav>
|
|
251
294
|
</div>
|
|
252
295
|
</div>
|
|
296
|
+
|
|
297
|
+
<modal
|
|
298
|
+
v-if="showRecentPagesModal"
|
|
299
|
+
flush-container
|
|
300
|
+
containerClass="!max-w-md !w-[min(94vw,28rem)] !overflow-hidden !rounded-lg !border !border-edge !bg-surface !shadow-xl dark:!bg-shark-900 text-content"
|
|
301
|
+
bodyClass="modal-recent-pages-body !p-0"
|
|
302
|
+
>
|
|
303
|
+
<template v-slot:body>
|
|
304
|
+
<div class="modal-exit" @click="closeRecentPagesModal" role="button" aria-label="Close recent pages">×</div>
|
|
305
|
+
<div
|
|
306
|
+
class="shrink-0 flex items-center gap-3 border-b border-edge bg-surface px-4 py-4 pr-12 dark:bg-shark-900"
|
|
307
|
+
>
|
|
308
|
+
<h2 class="m-0 text-lg font-semibold text-content">Recent pages</h2>
|
|
309
|
+
<button
|
|
310
|
+
type="button"
|
|
311
|
+
class="rounded px-2 py-1 text-sm font-medium text-content-secondary hover:bg-muted disabled:opacity-50"
|
|
312
|
+
@click="clearRecentPagesHistory"
|
|
313
|
+
:disabled="recentPagesList.length === 0"
|
|
314
|
+
>
|
|
315
|
+
Clear
|
|
316
|
+
</button>
|
|
317
|
+
</div>
|
|
318
|
+
<div class="modal-recent-pages-scroll">
|
|
319
|
+
<div
|
|
320
|
+
v-if="recentPagesList.length === 0"
|
|
321
|
+
class="m-4 rounded border border-dashed border-edge px-3 py-6 text-center text-sm text-content-tertiary"
|
|
322
|
+
>
|
|
323
|
+
No recent pages yet.
|
|
324
|
+
</div>
|
|
325
|
+
<button
|
|
326
|
+
v-for="entry in recentPagesList"
|
|
327
|
+
:key="entry.path + '-' + entry.visitedAt"
|
|
328
|
+
type="button"
|
|
329
|
+
class="w-full px-4 py-2.5 text-left hover:bg-muted"
|
|
330
|
+
:class="entry.path === $route.fullPath ? 'bg-primary-subtle' : ''"
|
|
331
|
+
@click="goToRecentPage(entry)"
|
|
332
|
+
>
|
|
333
|
+
<div class="truncate text-sm font-medium text-content">{{ entry.label }}</div>
|
|
334
|
+
<div class="truncate font-mono text-xs text-content-tertiary">{{ entry.path }}</div>
|
|
335
|
+
</button>
|
|
336
|
+
</div>
|
|
337
|
+
</template>
|
|
338
|
+
</modal>
|
|
339
|
+
</div>
|
|
@@ -4,6 +4,13 @@ const api = require('../api');
|
|
|
4
4
|
const mothership = require('../mothership');
|
|
5
5
|
const template = require('./navbar.html');
|
|
6
6
|
const { routes, hasAccess } = require('../routes');
|
|
7
|
+
const {
|
|
8
|
+
RECENT_PAGES_STORAGE_KEY,
|
|
9
|
+
RECENT_PAGES_CHANGED_EVENT,
|
|
10
|
+
safeReadRecentPages,
|
|
11
|
+
saveRecentPages,
|
|
12
|
+
withRecentPagesStorageLock
|
|
13
|
+
} = require('../_util/recent-pages-history');
|
|
7
14
|
|
|
8
15
|
const appendCSS = require('../appendCSS');
|
|
9
16
|
|
|
@@ -15,7 +22,9 @@ module.exports = app => app.component('navbar', {
|
|
|
15
22
|
inject: ['state'],
|
|
16
23
|
data: () => ({
|
|
17
24
|
showFlyout: false,
|
|
18
|
-
darkMode: typeof localStorage !== 'undefined' && localStorage.getItem('studio-theme') === 'dark'
|
|
25
|
+
darkMode: typeof localStorage !== 'undefined' && localStorage.getItem('studio-theme') === 'dark',
|
|
26
|
+
showRecentPagesModal: false,
|
|
27
|
+
localRecentPages: []
|
|
19
28
|
}),
|
|
20
29
|
mounted: function() {
|
|
21
30
|
window.navbar = this;
|
|
@@ -37,6 +46,32 @@ module.exports = app => app.component('navbar', {
|
|
|
37
46
|
mobileMenu.classList.add('translate-x-full');
|
|
38
47
|
});
|
|
39
48
|
}
|
|
49
|
+
|
|
50
|
+
this.localRecentPages = safeReadRecentPages();
|
|
51
|
+
|
|
52
|
+
this._syncRecentPagesFromOtherTab = ev => {
|
|
53
|
+
if (ev.storageArea !== window.localStorage || ev.key !== RECENT_PAGES_STORAGE_KEY) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.refreshRecentPagesFromStorage();
|
|
57
|
+
};
|
|
58
|
+
this._syncRecentPagesFromBroadcast = () => this.refreshRecentPagesFromStorage();
|
|
59
|
+
|
|
60
|
+
window.addEventListener('storage', this._syncRecentPagesFromOtherTab);
|
|
61
|
+
window.addEventListener(RECENT_PAGES_CHANGED_EVENT, this._syncRecentPagesFromBroadcast);
|
|
62
|
+
},
|
|
63
|
+
beforeUnmount() {
|
|
64
|
+
if (this._syncRecentPagesFromOtherTab) {
|
|
65
|
+
window.removeEventListener('storage', this._syncRecentPagesFromOtherTab);
|
|
66
|
+
}
|
|
67
|
+
if (this._syncRecentPagesFromBroadcast) {
|
|
68
|
+
window.removeEventListener(RECENT_PAGES_CHANGED_EVENT, this._syncRecentPagesFromBroadcast);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
watch: {
|
|
72
|
+
'$route.fullPath'() {
|
|
73
|
+
this.refreshRecentPagesFromStorage();
|
|
74
|
+
}
|
|
40
75
|
},
|
|
41
76
|
computed: {
|
|
42
77
|
dashboardView() {
|
|
@@ -68,6 +103,15 @@ module.exports = app => app.component('navbar', {
|
|
|
68
103
|
},
|
|
69
104
|
hasTaskVisualizer() {
|
|
70
105
|
return !!window.MONGOOSE_STUDIO_CONFIG.enableTaskVisualizer;
|
|
106
|
+
},
|
|
107
|
+
recentPagesList() {
|
|
108
|
+
return this.localRecentPages;
|
|
109
|
+
},
|
|
110
|
+
hasLLMAPIKey() {
|
|
111
|
+
return !!window.MONGOOSE_STUDIO_CONFIG.hasLLMAPIKey;
|
|
112
|
+
},
|
|
113
|
+
chatDisabledReason() {
|
|
114
|
+
return 'Chat requires an Anthropic, Gemini, or OpenAI API key.';
|
|
71
115
|
}
|
|
72
116
|
},
|
|
73
117
|
methods: {
|
|
@@ -97,6 +141,30 @@ module.exports = app => app.component('navbar', {
|
|
|
97
141
|
const meta = document.querySelector('meta[name="theme-color"]');
|
|
98
142
|
if (meta) meta.setAttribute('content', this.darkMode ? '#0f0f0f' : '#ffffff');
|
|
99
143
|
document.documentElement.dispatchEvent(new CustomEvent('studio-theme-changed', { detail: { dark: this.darkMode } }));
|
|
144
|
+
},
|
|
145
|
+
refreshRecentPagesFromStorage() {
|
|
146
|
+
this.localRecentPages = safeReadRecentPages();
|
|
147
|
+
},
|
|
148
|
+
openRecentPagesModal() {
|
|
149
|
+
this.showRecentPagesModal = true;
|
|
150
|
+
this.refreshRecentPagesFromStorage();
|
|
151
|
+
},
|
|
152
|
+
closeRecentPagesModal() {
|
|
153
|
+
this.showRecentPagesModal = false;
|
|
154
|
+
},
|
|
155
|
+
clearRecentPagesHistory() {
|
|
156
|
+
this.localRecentPages = [];
|
|
157
|
+
void withRecentPagesStorageLock(() => saveRecentPages([]));
|
|
158
|
+
},
|
|
159
|
+
goToRecentPage(entry) {
|
|
160
|
+
if (!entry || !entry.path) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this.showRecentPagesModal = false;
|
|
164
|
+
if (entry.path === this.$route.fullPath) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.$router.push(entry.path);
|
|
100
168
|
}
|
|
101
169
|
},
|
|
102
170
|
directives: {
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.",
|
|
5
5
|
"homepage": "https://mongoosestudio.app/",
|
|
6
6
|
"repository": {
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"tailwind": "tailwindcss -o ./frontend/public/tw.css",
|
|
54
54
|
"tailwind:watch": "tailwindcss -o ./frontend/public/tw.css --watch",
|
|
55
55
|
"test": "mocha test/*.test.js",
|
|
56
|
-
"test:frontend": "mocha test/frontend/*.test.js"
|
|
56
|
+
"test:frontend": "mocha test/frontend/*.test.js",
|
|
57
|
+
"eval:agent": "node eval/agent/run.js"
|
|
57
58
|
}
|
|
58
59
|
}
|