@mongoosejs/studio 0.5.13 → 0.6.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/AGENTS.md +74 -0
- package/README.md +27 -0
- package/backend/actions/ChatMessage/executeScript.js +15 -5
- package/backend/actions/ChatThread/createChatMessage.js +7 -2
- package/backend/actions/ChatThread/getChatThread.js +8 -2
- package/backend/actions/ChatThread/listChatThreads.js +6 -1
- package/backend/actions/ChatThread/shareChatThread.js +8 -2
- package/backend/actions/ChatThread/streamChatMessage.js +7 -2
- package/backend/actions/ChatThread/toggleAgentMode.js +8 -2
- package/backend/actions/Dashboard/createDashboard.js +3 -0
- package/backend/actions/Dashboard/deleteDashboard.js +13 -3
- package/backend/actions/Dashboard/getDashboard.js +33 -10
- package/backend/actions/Dashboard/getDashboards.js +9 -1
- package/backend/actions/Dashboard/updateDashboard.js +9 -2
- package/backend/actions/Model/addField.js +9 -2
- package/backend/actions/Model/analyzeSchema.js +16 -4
- package/backend/actions/Model/createChatMessage.js +3 -0
- package/backend/actions/Model/createDocument.js +3 -0
- package/backend/actions/Model/deleteDocument.js +9 -3
- package/backend/actions/Model/deleteDocuments.js +9 -1
- package/backend/actions/Model/dropCollection.js +3 -0
- package/backend/actions/Model/dropIndex.js +3 -0
- package/backend/actions/Model/executeDocumentScript.js +33 -26
- package/backend/actions/Model/exportQueryResults.js +13 -1
- package/backend/actions/Model/getCollectionInfo.js +15 -3
- package/backend/actions/Model/getDocument.js +13 -2
- package/backend/actions/Model/getDocuments.js +25 -5
- package/backend/actions/Model/getDocumentsStream.js +38 -18
- package/backend/actions/Model/getEstimatedDocumentCounts.js +15 -2
- package/backend/actions/Model/getIndexes.js +3 -0
- package/backend/actions/Model/getSuggestedProjection.js +3 -0
- package/backend/actions/Model/listModels.js +3 -0
- package/backend/actions/Model/streamChatMessage.js +3 -0
- package/backend/actions/Model/streamDocumentChanges.js +3 -0
- package/backend/actions/Model/updateDocument.js +10 -2
- package/backend/actions/Model/updateDocuments.js +10 -2
- package/backend/actions/Model/validateDocument.js +15 -2
- package/backend/actions/Script/createScript.js +36 -0
- package/backend/actions/Script/executeScript.js +89 -0
- package/backend/actions/Script/getScript.js +43 -0
- package/backend/actions/Script/index.js +5 -0
- package/backend/actions/Task/cancelTask.js +9 -3
- package/backend/actions/Task/getTaskOverview.js +7 -3
- package/backend/actions/Task/getTasks.js +7 -3
- package/backend/actions/Task/getTasksOverTime.js +7 -3
- package/backend/actions/Task/rescheduleTask.js +9 -3
- package/backend/actions/Task/runTask.js +9 -3
- package/backend/actions/index.js +1 -0
- package/backend/authorize.js +6 -1
- package/backend/db/scriptSchema.js +29 -0
- package/backend/helpers/omitNullish.js +5 -0
- package/backend/helpers/operationOptions.js +26 -0
- package/backend/helpers/readOperationOptions.js +31 -0
- package/backend/index.js +6 -4
- package/backend/integrations/mothership.js +28 -0
- package/backend/mcp.js +140 -0
- package/backend/netlify.js +5 -3
- package/backend/next.js +5 -3
- package/backend/sandbox/createSandbox.js +2 -2
- package/backend/sandbox/createScriptDb.js +60 -20
- package/backend/util/archetypeToZodSchema.js +74 -0
- package/docs/mcp-oauth.md +106 -0
- package/eslint.config.js +1 -0
- package/eval/agent/run.js +1 -1
- package/express.js +183 -41
- package/frontend/index.js +3 -0
- package/frontend/public/app.js +740 -124
- package/frontend/public/tw.css +76 -0
- package/frontend/src/api.js +27 -1
- package/frontend/src/index.js +9 -1
- package/frontend/src/mcp/mcp.html +55 -0
- package/frontend/src/mcp/mcp.js +27 -0
- package/frontend/src/models/models.html +29 -8
- package/frontend/src/models/models.js +30 -2
- package/frontend/src/navbar/navbar.html +8 -0
- package/frontend/src/navbar/navbar.js +3 -0
- package/frontend/src/routes.js +16 -0
- package/frontend/src/script/script.html +105 -0
- package/frontend/src/script/script.js +98 -0
- package/frontend/src/tooltip/tooltip.html +28 -0
- package/frontend/src/tooltip/tooltip.js +94 -0
- package/index.d.ts +10 -1
- package/local.js +2 -1
- package/nest.d.ts +4 -0
- package/package.json +5 -3
- package/vercel.d.ts +4 -0
package/frontend/public/app.js
CHANGED
|
@@ -1204,6 +1204,17 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
1204
1204
|
return client.post('', { action: 'ChatMessage.executeScript', ...params }).then(res => res.data);
|
|
1205
1205
|
}
|
|
1206
1206
|
};
|
|
1207
|
+
exports.Script = {
|
|
1208
|
+
createScript(params) {
|
|
1209
|
+
return client.post('', { action: 'Script.createScript', ...params }).then(res => res.data);
|
|
1210
|
+
},
|
|
1211
|
+
executeScript(params) {
|
|
1212
|
+
return client.post('', { action: 'Script.executeScript', ...params }).then(res => res.data);
|
|
1213
|
+
},
|
|
1214
|
+
getScript(params) {
|
|
1215
|
+
return client.post('', { action: 'Script.getScript', ...params }).then(res => res.data);
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1207
1218
|
exports.Model = {
|
|
1208
1219
|
addField(params) {
|
|
1209
1220
|
return client.post('', { action: 'Model.addField', ...params }).then(res => res.data);
|
|
@@ -1269,7 +1280,11 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
1269
1280
|
getDocumentsStream: async function* getDocumentsStream(params) {
|
|
1270
1281
|
const data = await client.post('', { action: 'Model.getDocuments', ...params }).then(res => res.data);
|
|
1271
1282
|
yield { schemaPaths: data.schemaPaths, suggestedFields: data.suggestedFields };
|
|
1272
|
-
|
|
1283
|
+
if (data.numDocsError) {
|
|
1284
|
+
yield { numDocsError: data.numDocsError };
|
|
1285
|
+
} else {
|
|
1286
|
+
yield { numDocs: data.numDocs };
|
|
1287
|
+
}
|
|
1273
1288
|
for (const doc of data.docs) {
|
|
1274
1289
|
yield { document: doc };
|
|
1275
1290
|
}
|
|
@@ -1399,6 +1414,17 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
1399
1414
|
return client.post('/ChatMessage/executeScript', params).then(res => res.data);
|
|
1400
1415
|
}
|
|
1401
1416
|
};
|
|
1417
|
+
exports.Script = {
|
|
1418
|
+
createScript: function createScript(params) {
|
|
1419
|
+
return client.post('/Script/createScript', params).then(res => res.data);
|
|
1420
|
+
},
|
|
1421
|
+
executeScript: function executeScript(params) {
|
|
1422
|
+
return client.post('/Script/executeScript', params).then(res => res.data);
|
|
1423
|
+
},
|
|
1424
|
+
getScript: function getScript(params) {
|
|
1425
|
+
return client.post('/Script/getScript', params).then(res => res.data);
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1402
1428
|
exports.Model = {
|
|
1403
1429
|
addField(params) {
|
|
1404
1430
|
return client.post('/Model/addField', params).then(res => res.data);
|
|
@@ -7847,7 +7873,7 @@ const {
|
|
|
7847
7873
|
} = __webpack_require__(/*! ./_util/recent-pages-history */ "./frontend/src/_util/recent-pages-history.js");
|
|
7848
7874
|
appendCSS(__webpack_require__(/*! vue-toastification/dist/index.css */ "./node_modules/vue-toastification/dist/index.css"));
|
|
7849
7875
|
|
|
7850
|
-
const TRACKED_RECENT_PAGE_ROUTE_NAMES = new Set(['model', 'document', 'dashboard', 'chat']);
|
|
7876
|
+
const TRACKED_RECENT_PAGE_ROUTE_NAMES = new Set(['model', 'document', 'dashboard', 'chat', 'script']);
|
|
7851
7877
|
const CHAT_ROUTE_NAMES = new Set(['chat index', 'chat']);
|
|
7852
7878
|
|
|
7853
7879
|
function formatHistoryLabel(route) {
|
|
@@ -7869,6 +7895,9 @@ function formatHistoryLabel(route) {
|
|
|
7869
7895
|
if (route.name === 'chat') {
|
|
7870
7896
|
return route.params?.threadId ? `Chat: ${route.params.threadId}` : 'Chat';
|
|
7871
7897
|
}
|
|
7898
|
+
if (route.name === 'script') {
|
|
7899
|
+
return route.params?.scriptId ? `Script: ${route.params.scriptId}` : 'Script';
|
|
7900
|
+
}
|
|
7872
7901
|
const normalizedPath = route.path.replace(/^\//, '');
|
|
7873
7902
|
return normalizedPath || 'Home';
|
|
7874
7903
|
}
|
|
@@ -8156,6 +8185,11 @@ const router = VueRouter.createRouter({
|
|
|
8156
8185
|
|
|
8157
8186
|
// Add global navigation guard
|
|
8158
8187
|
router.beforeEach((to, from, next) => {
|
|
8188
|
+
if (to.name === 'mcp' && window.MONGOOSE_STUDIO_CONFIG.mcp === false) {
|
|
8189
|
+
next({ name: window.state?.roles?.[0] === 'dashboards' ? 'dashboards' : 'root' });
|
|
8190
|
+
return;
|
|
8191
|
+
}
|
|
8192
|
+
|
|
8159
8193
|
// Skip auth check for authorized (public) routes
|
|
8160
8194
|
if (to.meta.authorized) {
|
|
8161
8195
|
next();
|
|
@@ -8884,6 +8918,44 @@ module.exports = app => app.component('list-subdocument', {
|
|
|
8884
8918
|
});
|
|
8885
8919
|
|
|
8886
8920
|
|
|
8921
|
+
/***/ },
|
|
8922
|
+
|
|
8923
|
+
/***/ "./frontend/src/mcp/mcp.js"
|
|
8924
|
+
/*!*********************************!*\
|
|
8925
|
+
!*** ./frontend/src/mcp/mcp.js ***!
|
|
8926
|
+
\*********************************/
|
|
8927
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
8928
|
+
|
|
8929
|
+
"use strict";
|
|
8930
|
+
|
|
8931
|
+
|
|
8932
|
+
const template = __webpack_require__(/*! ./mcp.html */ "./frontend/src/mcp/mcp.html");
|
|
8933
|
+
|
|
8934
|
+
module.exports = {
|
|
8935
|
+
template,
|
|
8936
|
+
computed: {
|
|
8937
|
+
mcpUrl() {
|
|
8938
|
+
const configuredUrl = window.MONGOOSE_STUDIO_CONFIG.mcpUrl;
|
|
8939
|
+
if (configuredUrl) {
|
|
8940
|
+
return configuredUrl;
|
|
8941
|
+
}
|
|
8942
|
+
|
|
8943
|
+
const url = new URL(window.location.href);
|
|
8944
|
+
url.hash = '';
|
|
8945
|
+
url.search = '';
|
|
8946
|
+
url.pathname = `${url.pathname.replace(/\/+$/, '')}/mcp`;
|
|
8947
|
+
return url.toString();
|
|
8948
|
+
}
|
|
8949
|
+
},
|
|
8950
|
+
methods: {
|
|
8951
|
+
async copyMCPUrl() {
|
|
8952
|
+
await navigator.clipboard.writeText(this.mcpUrl);
|
|
8953
|
+
this.$toast.success('MCP URL copied!');
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
};
|
|
8957
|
+
|
|
8958
|
+
|
|
8887
8959
|
/***/ },
|
|
8888
8960
|
|
|
8889
8961
|
/***/ "./frontend/src/modal/modal.js"
|
|
@@ -9621,6 +9693,8 @@ module.exports = app => app.component('models', {
|
|
|
9621
9693
|
filteredPaths: [],
|
|
9622
9694
|
selectedPaths: [],
|
|
9623
9695
|
numDocuments: null,
|
|
9696
|
+
numDocumentsError: null,
|
|
9697
|
+
documentsError: null,
|
|
9624
9698
|
mongoDBIndexes: [],
|
|
9625
9699
|
schemaIndexes: [],
|
|
9626
9700
|
status: 'loading',
|
|
@@ -10308,7 +10382,8 @@ module.exports = app => app.component('models', {
|
|
|
10308
10382
|
return filteredDoc;
|
|
10309
10383
|
},
|
|
10310
10384
|
async checkIfScrolledToBottom() {
|
|
10311
|
-
if
|
|
10385
|
+
// Stop infinite scroll if the last load failed, otherwise we would retry the same failing request forever.
|
|
10386
|
+
if (this.status === 'loading' || this.loadedAllDocs || this.documentsError) {
|
|
10312
10387
|
return;
|
|
10313
10388
|
}
|
|
10314
10389
|
// Infinite scroll only applies to table/json views.
|
|
@@ -10334,11 +10409,20 @@ module.exports = app => app.component('models', {
|
|
|
10334
10409
|
try {
|
|
10335
10410
|
const skip = this.documents.length;
|
|
10336
10411
|
const params = this.buildDocumentFetchParams({ skip });
|
|
10337
|
-
const { docs } = await api.Model.getDocuments(params);
|
|
10412
|
+
const { docs, numDocs, numDocsError } = await api.Model.getDocuments(params);
|
|
10413
|
+
if (numDocsError) {
|
|
10414
|
+
this.numDocumentsError = numDocsError;
|
|
10415
|
+
} else if (numDocs !== undefined) {
|
|
10416
|
+
this.numDocuments = numDocs;
|
|
10417
|
+
this.numDocumentsError = null;
|
|
10418
|
+
}
|
|
10338
10419
|
if (docs.length < limit) {
|
|
10339
10420
|
this.loadedAllDocs = true;
|
|
10340
10421
|
}
|
|
10341
10422
|
this.documents.push(...docs);
|
|
10423
|
+
this.documentsError = null;
|
|
10424
|
+
} catch (err) {
|
|
10425
|
+
this.documentsError = err?.message;
|
|
10342
10426
|
} finally {
|
|
10343
10427
|
this.loadingMore = false;
|
|
10344
10428
|
this.status = 'loaded';
|
|
@@ -10551,6 +10635,8 @@ module.exports = app => app.component('models', {
|
|
|
10551
10635
|
// Clear previous data
|
|
10552
10636
|
this.documents = [];
|
|
10553
10637
|
this.numDocuments = null;
|
|
10638
|
+
this.numDocumentsError = null;
|
|
10639
|
+
this.documentsError = null;
|
|
10554
10640
|
this.loadedAllDocs = false;
|
|
10555
10641
|
this.lastSelectedIndex = null;
|
|
10556
10642
|
|
|
@@ -10600,6 +10686,10 @@ module.exports = app => app.component('models', {
|
|
|
10600
10686
|
}
|
|
10601
10687
|
if (event.numDocs !== undefined) {
|
|
10602
10688
|
this.numDocuments = event.numDocs;
|
|
10689
|
+
this.numDocumentsError = null;
|
|
10690
|
+
}
|
|
10691
|
+
if (event.numDocsError) {
|
|
10692
|
+
this.numDocumentsError = event.numDocsError;
|
|
10603
10693
|
}
|
|
10604
10694
|
if (event.document) {
|
|
10605
10695
|
this.documents.push(event.document);
|
|
@@ -10613,6 +10703,9 @@ module.exports = app => app.component('models', {
|
|
|
10613
10703
|
if (docsCount < limit) {
|
|
10614
10704
|
this.loadedAllDocs = true;
|
|
10615
10705
|
}
|
|
10706
|
+
this.documentsError = null;
|
|
10707
|
+
} catch (err) {
|
|
10708
|
+
this.documentsError = err?.message;
|
|
10616
10709
|
} finally {
|
|
10617
10710
|
this.status = 'loaded';
|
|
10618
10711
|
}
|
|
@@ -10639,8 +10732,12 @@ module.exports = app => app.component('models', {
|
|
|
10639
10732
|
for await (const event of api.Model.getDocumentsStream(params)) {
|
|
10640
10733
|
if (event.numDocs !== undefined && !numDocsReceived) {
|
|
10641
10734
|
this.numDocuments = event.numDocs;
|
|
10735
|
+
this.numDocumentsError = null;
|
|
10642
10736
|
numDocsReceived = true;
|
|
10643
10737
|
}
|
|
10738
|
+
if (event.numDocsError) {
|
|
10739
|
+
this.numDocumentsError = event.numDocsError;
|
|
10740
|
+
}
|
|
10644
10741
|
if (event.document) {
|
|
10645
10742
|
this.documents.push(event.document);
|
|
10646
10743
|
docsCount++;
|
|
@@ -10653,6 +10750,9 @@ module.exports = app => app.component('models', {
|
|
|
10653
10750
|
if (docsCount < limit) {
|
|
10654
10751
|
this.loadedAllDocs = true;
|
|
10655
10752
|
}
|
|
10753
|
+
this.documentsError = null;
|
|
10754
|
+
} catch (err) {
|
|
10755
|
+
this.documentsError = err?.message;
|
|
10656
10756
|
} finally {
|
|
10657
10757
|
this.loadingMore = false;
|
|
10658
10758
|
this.status = 'loaded';
|
|
@@ -11707,6 +11807,9 @@ module.exports = app => app.component('navbar', {
|
|
|
11707
11807
|
hasTaskVisualizer() {
|
|
11708
11808
|
return !!window.MONGOOSE_STUDIO_CONFIG.enableTaskVisualizer;
|
|
11709
11809
|
},
|
|
11810
|
+
mcpEnabled() {
|
|
11811
|
+
return window.MONGOOSE_STUDIO_CONFIG.mcp !== false;
|
|
11812
|
+
},
|
|
11710
11813
|
recentPagesList() {
|
|
11711
11814
|
return this.localRecentPages;
|
|
11712
11815
|
},
|
|
@@ -11906,6 +12009,14 @@ module.exports = {
|
|
|
11906
12009
|
authorized: false
|
|
11907
12010
|
}
|
|
11908
12011
|
},
|
|
12012
|
+
{
|
|
12013
|
+
path: '/mcp',
|
|
12014
|
+
name: 'mcp',
|
|
12015
|
+
component: 'mcp',
|
|
12016
|
+
meta: {
|
|
12017
|
+
authorized: true
|
|
12018
|
+
}
|
|
12019
|
+
},
|
|
11909
12020
|
{
|
|
11910
12021
|
path: '/tasks',
|
|
11911
12022
|
name: 'tasks',
|
|
@@ -11945,6 +12056,14 @@ module.exports = {
|
|
|
11945
12056
|
meta: {
|
|
11946
12057
|
authorized: true
|
|
11947
12058
|
}
|
|
12059
|
+
},
|
|
12060
|
+
{
|
|
12061
|
+
path: '/script/:scriptId',
|
|
12062
|
+
name: 'script',
|
|
12063
|
+
component: 'script',
|
|
12064
|
+
meta: {
|
|
12065
|
+
authorized: true
|
|
12066
|
+
}
|
|
11948
12067
|
}
|
|
11949
12068
|
],
|
|
11950
12069
|
roleAccess,
|
|
@@ -11952,6 +12071,115 @@ module.exports = {
|
|
|
11952
12071
|
};
|
|
11953
12072
|
|
|
11954
12073
|
|
|
12074
|
+
/***/ },
|
|
12075
|
+
|
|
12076
|
+
/***/ "./frontend/src/script/script.js"
|
|
12077
|
+
/*!***************************************!*\
|
|
12078
|
+
!*** ./frontend/src/script/script.js ***!
|
|
12079
|
+
\***************************************/
|
|
12080
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
12081
|
+
|
|
12082
|
+
"use strict";
|
|
12083
|
+
/* global Prism */
|
|
12084
|
+
|
|
12085
|
+
|
|
12086
|
+
const api = __webpack_require__(/*! ../api */ "./frontend/src/api.js");
|
|
12087
|
+
const baseComponent = __webpack_require__(/*! ../_util/baseComponent */ "./frontend/src/_util/baseComponent.js");
|
|
12088
|
+
const template = __webpack_require__(/*! ./script.html */ "./frontend/src/script/script.html");
|
|
12089
|
+
|
|
12090
|
+
module.exports = {
|
|
12091
|
+
template,
|
|
12092
|
+
extends: baseComponent,
|
|
12093
|
+
props: ['scriptId'],
|
|
12094
|
+
inject: ['state'],
|
|
12095
|
+
data() {
|
|
12096
|
+
return {
|
|
12097
|
+
status: 'loading',
|
|
12098
|
+
script: null,
|
|
12099
|
+
editedScript: '',
|
|
12100
|
+
isEditing: false,
|
|
12101
|
+
activeTab: 'code',
|
|
12102
|
+
selectedRunMode: 'run',
|
|
12103
|
+
showRunDropdown: false
|
|
12104
|
+
};
|
|
12105
|
+
},
|
|
12106
|
+
computed: {
|
|
12107
|
+
canUseDryRun() {
|
|
12108
|
+
return this.state.capabilities?.supportsTransactions !== false;
|
|
12109
|
+
},
|
|
12110
|
+
selectedRunLabel() {
|
|
12111
|
+
return this.selectedRunMode === 'dryRun' ? 'Dry Run' : 'Run';
|
|
12112
|
+
},
|
|
12113
|
+
isDryRunResult() {
|
|
12114
|
+
return this.script?.executionFinishedAt != null && this.script?.dryRun === true;
|
|
12115
|
+
}
|
|
12116
|
+
},
|
|
12117
|
+
methods: {
|
|
12118
|
+
async loadScript() {
|
|
12119
|
+
this.status = 'loading';
|
|
12120
|
+
try {
|
|
12121
|
+
const { script } = await api.Script.getScript({ scriptId: this.scriptId });
|
|
12122
|
+
this.script = script;
|
|
12123
|
+
this.editedScript = script.script;
|
|
12124
|
+
this.activeTab = script.executionResult == null ? 'code' : 'output';
|
|
12125
|
+
} finally {
|
|
12126
|
+
this.status = 'loaded';
|
|
12127
|
+
this.highlightCode();
|
|
12128
|
+
}
|
|
12129
|
+
},
|
|
12130
|
+
startEditing() {
|
|
12131
|
+
this.editedScript = this.script.script;
|
|
12132
|
+
this.isEditing = true;
|
|
12133
|
+
this.activeTab = 'code';
|
|
12134
|
+
},
|
|
12135
|
+
cancelEditing() {
|
|
12136
|
+
this.editedScript = this.script.script;
|
|
12137
|
+
this.isEditing = false;
|
|
12138
|
+
this.highlightCode();
|
|
12139
|
+
},
|
|
12140
|
+
selectRunMode(mode) {
|
|
12141
|
+
if (mode === 'dryRun' && !this.canUseDryRun) {
|
|
12142
|
+
return;
|
|
12143
|
+
}
|
|
12144
|
+
this.selectedRunMode = mode;
|
|
12145
|
+
this.showRunDropdown = false;
|
|
12146
|
+
},
|
|
12147
|
+
async executeScript() {
|
|
12148
|
+
this.showRunDropdown = false;
|
|
12149
|
+
try {
|
|
12150
|
+
const { script } = await api.Script.executeScript({
|
|
12151
|
+
scriptId: this.scriptId,
|
|
12152
|
+
script: this.isEditing ? this.editedScript : this.script.script,
|
|
12153
|
+
dryRun: this.selectedRunMode === 'dryRun'
|
|
12154
|
+
});
|
|
12155
|
+
this.script = script;
|
|
12156
|
+
this.editedScript = script.script;
|
|
12157
|
+
this.isEditing = false;
|
|
12158
|
+
this.activeTab = 'output';
|
|
12159
|
+
this.$toast.success(this.script.dryRun ? 'Dry run completed!' : 'Script executed successfully!');
|
|
12160
|
+
} catch (err) {
|
|
12161
|
+
const { script } = await api.Script.getScript({ scriptId: this.scriptId });
|
|
12162
|
+
this.script = script;
|
|
12163
|
+
this.editedScript = script.script;
|
|
12164
|
+
this.isEditing = false;
|
|
12165
|
+
this.activeTab = 'output';
|
|
12166
|
+
throw err;
|
|
12167
|
+
}
|
|
12168
|
+
},
|
|
12169
|
+
highlightCode() {
|
|
12170
|
+
this.$nextTick(() => {
|
|
12171
|
+
if (this.$refs.code) {
|
|
12172
|
+
Prism.highlightElement(this.$refs.code);
|
|
12173
|
+
}
|
|
12174
|
+
});
|
|
12175
|
+
}
|
|
12176
|
+
},
|
|
12177
|
+
mounted() {
|
|
12178
|
+
return this.loadScript();
|
|
12179
|
+
}
|
|
12180
|
+
};
|
|
12181
|
+
|
|
12182
|
+
|
|
11955
12183
|
/***/ },
|
|
11956
12184
|
|
|
11957
12185
|
/***/ "./frontend/src/splash/splash.js"
|
|
@@ -13175,6 +13403,111 @@ module.exports = app => app.component('team', {
|
|
|
13175
13403
|
});
|
|
13176
13404
|
|
|
13177
13405
|
|
|
13406
|
+
/***/ },
|
|
13407
|
+
|
|
13408
|
+
/***/ "./frontend/src/tooltip/tooltip.js"
|
|
13409
|
+
/*!*****************************************!*\
|
|
13410
|
+
!*** ./frontend/src/tooltip/tooltip.js ***!
|
|
13411
|
+
\*****************************************/
|
|
13412
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
13413
|
+
|
|
13414
|
+
"use strict";
|
|
13415
|
+
|
|
13416
|
+
|
|
13417
|
+
const template = __webpack_require__(/*! ./tooltip.html */ "./frontend/src/tooltip/tooltip.html");
|
|
13418
|
+
|
|
13419
|
+
let nextTooltipId = 0;
|
|
13420
|
+
|
|
13421
|
+
module.exports = app => app.component('tooltip', {
|
|
13422
|
+
props: {
|
|
13423
|
+
text: {
|
|
13424
|
+
type: String,
|
|
13425
|
+
required: true
|
|
13426
|
+
}
|
|
13427
|
+
},
|
|
13428
|
+
template,
|
|
13429
|
+
data() {
|
|
13430
|
+
return {
|
|
13431
|
+
isOpen: false,
|
|
13432
|
+
isPinned: false,
|
|
13433
|
+
placement: 'bottom',
|
|
13434
|
+
tooltipId: `tooltip-${++nextTooltipId}`,
|
|
13435
|
+
tooltipStyle: {
|
|
13436
|
+
visibility: 'hidden'
|
|
13437
|
+
}
|
|
13438
|
+
};
|
|
13439
|
+
},
|
|
13440
|
+
mounted() {
|
|
13441
|
+
document.addEventListener('click', this.handleOutsideClick);
|
|
13442
|
+
window.addEventListener('resize', this.updatePosition);
|
|
13443
|
+
window.addEventListener('scroll', this.updatePosition, true);
|
|
13444
|
+
},
|
|
13445
|
+
beforeUnmount() {
|
|
13446
|
+
document.removeEventListener('click', this.handleOutsideClick);
|
|
13447
|
+
window.removeEventListener('resize', this.updatePosition);
|
|
13448
|
+
window.removeEventListener('scroll', this.updatePosition, true);
|
|
13449
|
+
},
|
|
13450
|
+
methods: {
|
|
13451
|
+
show() {
|
|
13452
|
+
this.isOpen = true;
|
|
13453
|
+
this.tooltipStyle = { visibility: 'hidden' };
|
|
13454
|
+
this.$nextTick(this.updatePosition);
|
|
13455
|
+
},
|
|
13456
|
+
hide() {
|
|
13457
|
+
this.isOpen = false;
|
|
13458
|
+
this.isPinned = false;
|
|
13459
|
+
},
|
|
13460
|
+
hideUnlessPinned() {
|
|
13461
|
+
if (!this.isPinned) {
|
|
13462
|
+
this.isOpen = false;
|
|
13463
|
+
}
|
|
13464
|
+
},
|
|
13465
|
+
toggle() {
|
|
13466
|
+
if (this.isPinned) {
|
|
13467
|
+
this.hide();
|
|
13468
|
+
return;
|
|
13469
|
+
}
|
|
13470
|
+
|
|
13471
|
+
this.isPinned = true;
|
|
13472
|
+
this.show();
|
|
13473
|
+
},
|
|
13474
|
+
handleFocusOut(event) {
|
|
13475
|
+
if (!this.$el.contains(event.relatedTarget)) {
|
|
13476
|
+
this.hideUnlessPinned();
|
|
13477
|
+
}
|
|
13478
|
+
},
|
|
13479
|
+
handleOutsideClick(event) {
|
|
13480
|
+
if (!this.$el.contains(event.target)) {
|
|
13481
|
+
this.hide();
|
|
13482
|
+
}
|
|
13483
|
+
},
|
|
13484
|
+
updatePosition() {
|
|
13485
|
+
if (!this.isOpen || !this.$refs.trigger || !this.$refs.tooltip) {
|
|
13486
|
+
return;
|
|
13487
|
+
}
|
|
13488
|
+
|
|
13489
|
+
const gap = 8;
|
|
13490
|
+
const viewportPadding = 8;
|
|
13491
|
+
const triggerRect = this.$refs.trigger.getBoundingClientRect();
|
|
13492
|
+
const tooltipRect = this.$refs.tooltip.getBoundingClientRect();
|
|
13493
|
+
const fitsBelow = triggerRect.bottom + gap + tooltipRect.height <= window.innerHeight - viewportPadding;
|
|
13494
|
+
const top = fitsBelow ?
|
|
13495
|
+
triggerRect.bottom + gap :
|
|
13496
|
+
Math.max(viewportPadding, triggerRect.top - gap - tooltipRect.height);
|
|
13497
|
+
const centeredLeft = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
13498
|
+
const maxLeft = Math.max(viewportPadding, window.innerWidth - tooltipRect.width - viewportPadding);
|
|
13499
|
+
const left = Math.min(Math.max(viewportPadding, centeredLeft), maxLeft);
|
|
13500
|
+
|
|
13501
|
+
this.placement = fitsBelow ? 'bottom' : 'top';
|
|
13502
|
+
this.tooltipStyle = {
|
|
13503
|
+
left: `${Math.round(left)}px`,
|
|
13504
|
+
top: `${Math.round(top)}px`
|
|
13505
|
+
};
|
|
13506
|
+
}
|
|
13507
|
+
}
|
|
13508
|
+
});
|
|
13509
|
+
|
|
13510
|
+
|
|
13178
13511
|
/***/ },
|
|
13179
13512
|
|
|
13180
13513
|
/***/ "./frontend/src/update-document/update-document.js"
|
|
@@ -13436,6 +13769,9 @@ const map = {
|
|
|
13436
13769
|
"./list-subdocument/list-subdocument.css": "./frontend/src/list-subdocument/list-subdocument.css",
|
|
13437
13770
|
"./list-subdocument/list-subdocument.html": "./frontend/src/list-subdocument/list-subdocument.html",
|
|
13438
13771
|
"./list-subdocument/list-subdocument.js": "./frontend/src/list-subdocument/list-subdocument.js",
|
|
13772
|
+
"./mcp/mcp": "./frontend/src/mcp/mcp.js",
|
|
13773
|
+
"./mcp/mcp.html": "./frontend/src/mcp/mcp.html",
|
|
13774
|
+
"./mcp/mcp.js": "./frontend/src/mcp/mcp.js",
|
|
13439
13775
|
"./modal/modal": "./frontend/src/modal/modal.js",
|
|
13440
13776
|
"./modal/modal.css": "./frontend/src/modal/modal.css",
|
|
13441
13777
|
"./modal/modal.html": "./frontend/src/modal/modal.html",
|
|
@@ -13469,6 +13805,9 @@ const map = {
|
|
|
13469
13805
|
"./pro-upgrade-modal/pro-upgrade-modal.js": "./frontend/src/pro-upgrade-modal/pro-upgrade-modal.js",
|
|
13470
13806
|
"./routes": "./frontend/src/routes.js",
|
|
13471
13807
|
"./routes.js": "./frontend/src/routes.js",
|
|
13808
|
+
"./script/script": "./frontend/src/script/script.js",
|
|
13809
|
+
"./script/script.html": "./frontend/src/script/script.html",
|
|
13810
|
+
"./script/script.js": "./frontend/src/script/script.js",
|
|
13472
13811
|
"./splash/splash": "./frontend/src/splash/splash.js",
|
|
13473
13812
|
"./splash/splash.html": "./frontend/src/splash/splash.html",
|
|
13474
13813
|
"./splash/splash.js": "./frontend/src/splash/splash.js",
|
|
@@ -13491,6 +13830,9 @@ const map = {
|
|
|
13491
13830
|
"./team/team": "./frontend/src/team/team.js",
|
|
13492
13831
|
"./team/team.html": "./frontend/src/team/team.html",
|
|
13493
13832
|
"./team/team.js": "./frontend/src/team/team.js",
|
|
13833
|
+
"./tooltip/tooltip": "./frontend/src/tooltip/tooltip.js",
|
|
13834
|
+
"./tooltip/tooltip.html": "./frontend/src/tooltip/tooltip.html",
|
|
13835
|
+
"./tooltip/tooltip.js": "./frontend/src/tooltip/tooltip.js",
|
|
13494
13836
|
"./update-document/update-document": "./frontend/src/update-document/update-document.js",
|
|
13495
13837
|
"./update-document/update-document.css": "./frontend/src/update-document/update-document.css",
|
|
13496
13838
|
"./update-document/update-document.html": "./frontend/src/update-document/update-document.html",
|
|
@@ -13581,7 +13923,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
13581
13923
|
/* harmony export */ });
|
|
13582
13924
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
13583
13925
|
/**
|
|
13584
|
-
* @vue/reactivity v3.5.
|
|
13926
|
+
* @vue/reactivity v3.5.43
|
|
13585
13927
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
13586
13928
|
* @license MIT
|
|
13587
13929
|
**/
|
|
@@ -14356,7 +14698,9 @@ function reactiveReadArray(array) {
|
|
|
14356
14698
|
const raw = toRaw(array);
|
|
14357
14699
|
if (raw === array) return raw;
|
|
14358
14700
|
track(raw, "iterate", ARRAY_ITERATE_KEY);
|
|
14359
|
-
|
|
14701
|
+
if (isShallow(array)) return raw;
|
|
14702
|
+
if (!isReadonly(array)) return raw.map(toReactive);
|
|
14703
|
+
return isReactive(array) ? raw.map((item) => toReadonly(toReactive(item))) : raw.map(toReadonly);
|
|
14360
14704
|
}
|
|
14361
14705
|
function shallowReadArray(arr) {
|
|
14362
14706
|
track(arr = toRaw(arr), "iterate", ARRAY_ITERATE_KEY);
|
|
@@ -15754,7 +16098,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
15754
16098
|
/* harmony import */ var _vue_reactivity__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/reactivity */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
15755
16099
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
15756
16100
|
/**
|
|
15757
|
-
* @vue/runtime-core v3.5.
|
|
16101
|
+
* @vue/runtime-core v3.5.43
|
|
15758
16102
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
15759
16103
|
* @license MIT
|
|
15760
16104
|
**/
|
|
@@ -17822,13 +18166,15 @@ function createHydrationFunctions(rendererInternals) {
|
|
|
17822
18166
|
getContainerType(container),
|
|
17823
18167
|
optimized
|
|
17824
18168
|
);
|
|
17825
|
-
if (isAsyncWrapper(vnode) && !vnode.
|
|
18169
|
+
if ((isAsyncWrapper(vnode) || vnode.component.asyncDep) && !vnode.component.subTree) {
|
|
17826
18170
|
let subTree;
|
|
17827
18171
|
if (isFragmentStart) {
|
|
17828
|
-
subTree = createVNode(
|
|
18172
|
+
subTree = createVNode(Static);
|
|
17829
18173
|
subTree.anchor = nextNode ? nextNode.previousSibling : container.lastChild;
|
|
17830
18174
|
} else {
|
|
17831
|
-
subTree = node.nodeType === 3 ? createTextVNode("") : createVNode(
|
|
18175
|
+
subTree = node.nodeType === 3 ? createTextVNode("") : createVNode(
|
|
18176
|
+
node.nodeType === 8 ? Comment : "div"
|
|
18177
|
+
);
|
|
17832
18178
|
}
|
|
17833
18179
|
subTree.el = node;
|
|
17834
18180
|
vnode.component.subTree = subTree;
|
|
@@ -18736,7 +19082,10 @@ const KeepAliveImpl = {
|
|
|
18736
19082
|
if (pendingCacheKey != null) {
|
|
18737
19083
|
if (isSuspense(instance.subTree.type)) {
|
|
18738
19084
|
queuePostRenderEffect(() => {
|
|
18739
|
-
|
|
19085
|
+
const vnode = getInnerChild(instance.subTree);
|
|
19086
|
+
if (vnode.component) {
|
|
19087
|
+
cache.set(pendingCacheKey, vnode);
|
|
19088
|
+
}
|
|
18740
19089
|
}, instance.subTree.suspense);
|
|
18741
19090
|
} else {
|
|
18742
19091
|
cache.set(pendingCacheKey, getInnerChild(instance.subTree));
|
|
@@ -19137,12 +19486,41 @@ const getPublicInstance = (i) => {
|
|
|
19137
19486
|
if (isStatefulComponent(i)) return getComponentPublicInstance(i);
|
|
19138
19487
|
return getPublicInstance(i.parent);
|
|
19139
19488
|
};
|
|
19489
|
+
const resolveDevRootEl = (vnode) => {
|
|
19490
|
+
let found = false;
|
|
19491
|
+
while (true) {
|
|
19492
|
+
if (vnode.patchFlag > 0 && vnode.patchFlag & 2048) {
|
|
19493
|
+
const root = filterSingleRoot(vnode.children);
|
|
19494
|
+
if (!root) {
|
|
19495
|
+
return;
|
|
19496
|
+
}
|
|
19497
|
+
vnode = root;
|
|
19498
|
+
found = true;
|
|
19499
|
+
continue;
|
|
19500
|
+
}
|
|
19501
|
+
const component = vnode.component;
|
|
19502
|
+
if (component && component.subTree) {
|
|
19503
|
+
vnode = component.subTree;
|
|
19504
|
+
continue;
|
|
19505
|
+
}
|
|
19506
|
+
const suspense = vnode.suspense;
|
|
19507
|
+
if (suspense && suspense.activeBranch) {
|
|
19508
|
+
vnode = suspense.activeBranch;
|
|
19509
|
+
continue;
|
|
19510
|
+
}
|
|
19511
|
+
return found ? vnode.el : void 0;
|
|
19512
|
+
}
|
|
19513
|
+
};
|
|
19514
|
+
const getDevRootFragmentEl = (i) => {
|
|
19515
|
+
const el = i.subTree && resolveDevRootEl(i.subTree);
|
|
19516
|
+
return el === void 0 ? i.vnode.el : el;
|
|
19517
|
+
};
|
|
19140
19518
|
const publicPropertiesMap = (
|
|
19141
19519
|
// Move PURE marker to new line to workaround compiler discarding it
|
|
19142
19520
|
// due to type annotation
|
|
19143
19521
|
/* @__PURE__ */ (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.extend)(/* @__PURE__ */ Object.create(null), {
|
|
19144
19522
|
$: (i) => i,
|
|
19145
|
-
$el: (i) => i
|
|
19523
|
+
$el: (i) => true ? getDevRootFragmentEl(i) : 0,
|
|
19146
19524
|
$data: (i) => i.data,
|
|
19147
19525
|
$props: (i) => true ? (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.shallowReadonly)(i.props) : 0,
|
|
19148
19526
|
$attrs: (i) => true ? (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.shallowReadonly)(i.attrs) : 0,
|
|
@@ -20248,7 +20626,7 @@ function emit(instance, event, ...rawArgs) {
|
|
|
20248
20626
|
args = rawArgs.map((a) => (0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.isString)(a) ? a.trim() : a);
|
|
20249
20627
|
}
|
|
20250
20628
|
if (modifiers.number) {
|
|
20251
|
-
args =
|
|
20629
|
+
args = args.map(_vue_shared__WEBPACK_IMPORTED_MODULE_1__.looseToNumber);
|
|
20252
20630
|
}
|
|
20253
20631
|
}
|
|
20254
20632
|
if (true) {
|
|
@@ -21274,6 +21652,12 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
21274
21652
|
optimized = false;
|
|
21275
21653
|
n2.dynamicChildren = null;
|
|
21276
21654
|
}
|
|
21655
|
+
if (n2.dynamicChildren && n1 && n1.dynamicChildren && n1.dynamicChildren.hasOnce) {
|
|
21656
|
+
if (n2.dynamicChildren === _vue_shared__WEBPACK_IMPORTED_MODULE_1__.EMPTY_ARR) {
|
|
21657
|
+
n2.dynamicChildren = [];
|
|
21658
|
+
}
|
|
21659
|
+
n2.dynamicChildren.hasOnce = true;
|
|
21660
|
+
}
|
|
21277
21661
|
const { type, ref, shapeFlag } = n2;
|
|
21278
21662
|
switch (type) {
|
|
21279
21663
|
case Text:
|
|
@@ -21880,6 +22264,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
21880
22264
|
if (true) {
|
|
21881
22265
|
pushWarningContext(n2);
|
|
21882
22266
|
}
|
|
22267
|
+
n2.el = n1.el;
|
|
21883
22268
|
updateComponentPreRender(instance, n2, optimized);
|
|
21884
22269
|
if (true) {
|
|
21885
22270
|
popWarningContext();
|
|
@@ -22471,7 +22856,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
22471
22856
|
cacheIndex,
|
|
22472
22857
|
memo
|
|
22473
22858
|
} = vnode;
|
|
22474
|
-
if (patchFlag === -2) {
|
|
22859
|
+
if (patchFlag === -2 || dynamicChildren && dynamicChildren.hasOnce) {
|
|
22475
22860
|
optimized = false;
|
|
22476
22861
|
}
|
|
22477
22862
|
if (ref != null) {
|
|
@@ -22479,7 +22864,7 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
22479
22864
|
setRef(ref, null, parentSuspense, vnode, true);
|
|
22480
22865
|
(0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.resetTracking)();
|
|
22481
22866
|
}
|
|
22482
|
-
if (cacheIndex != null) {
|
|
22867
|
+
if (cacheIndex != null && (!vnode.ctx || vnode.ctx === parentComponent)) {
|
|
22483
22868
|
parentComponent.renderCache[cacheIndex] = void 0;
|
|
22484
22869
|
}
|
|
22485
22870
|
if (shapeFlag & 256) {
|
|
@@ -22560,6 +22945,9 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
22560
22945
|
}
|
|
22561
22946
|
if (type === Static) {
|
|
22562
22947
|
removeStaticNode(vnode);
|
|
22948
|
+
if (transition && !transition.persisted && transition.afterLeave) {
|
|
22949
|
+
transition.afterLeave();
|
|
22950
|
+
}
|
|
22563
22951
|
return;
|
|
22564
22952
|
}
|
|
22565
22953
|
const performRemove = () => {
|
|
@@ -22603,6 +22991,9 @@ function baseCreateRenderer(options, createHydrationFns) {
|
|
|
22603
22991
|
if (job) {
|
|
22604
22992
|
job.flags |= 8;
|
|
22605
22993
|
unmount(subTree, instance, parentSuspense, doRemove);
|
|
22994
|
+
} else if (instance.vnode.el && subTree) {
|
|
22995
|
+
subTree.transition = instance.vnode.transition;
|
|
22996
|
+
unmount(subTree, instance, parentSuspense, doRemove);
|
|
22606
22997
|
}
|
|
22607
22998
|
if (um) {
|
|
22608
22999
|
queuePostRenderEffect(um, parentSuspense);
|
|
@@ -22817,7 +23208,7 @@ const SuspenseImpl = {
|
|
|
22817
23208
|
rendererInternals
|
|
22818
23209
|
);
|
|
22819
23210
|
} else {
|
|
22820
|
-
if (parentSuspense && parentSuspense.deps > 0 && !n1.suspense.isInFallback) {
|
|
23211
|
+
if (parentSuspense && parentSuspense.deps > 0 && !n1.suspense.isInFallback && !parentSuspense.isHydrating) {
|
|
22821
23212
|
n2.suspense = n1.suspense;
|
|
22822
23213
|
n2.suspense.vnode = n2;
|
|
22823
23214
|
n2.el = n1.el;
|
|
@@ -22903,10 +23294,12 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, namespace, sl
|
|
|
22903
23294
|
if (pendingBranch) {
|
|
22904
23295
|
suspense.pendingBranch = newBranch;
|
|
22905
23296
|
if (isSameVNodeType(pendingBranch, newBranch)) {
|
|
23297
|
+
suspense.deps++;
|
|
22906
23298
|
patch(
|
|
22907
23299
|
pendingBranch,
|
|
22908
23300
|
newBranch,
|
|
22909
|
-
|
|
23301
|
+
// a hydrating pending branch is adopted SSR DOM, already in place
|
|
23302
|
+
isHydrating ? container : suspense.hiddenContainer,
|
|
22910
23303
|
null,
|
|
22911
23304
|
parentComponent,
|
|
22912
23305
|
suspense,
|
|
@@ -22914,10 +23307,11 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, namespace, sl
|
|
|
22914
23307
|
slotScopeIds,
|
|
22915
23308
|
optimized
|
|
22916
23309
|
);
|
|
23310
|
+
suspense.deps--;
|
|
22917
23311
|
if (suspense.deps <= 0) {
|
|
22918
23312
|
suspense.resolve();
|
|
22919
23313
|
} else if (isInFallback) {
|
|
22920
|
-
if (!isHydrating) {
|
|
23314
|
+
if (!isHydrating && !suspense.isFallbackMountPending) {
|
|
22921
23315
|
patch(
|
|
22922
23316
|
activeBranch,
|
|
22923
23317
|
newFallback,
|
|
@@ -22958,7 +23352,7 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, namespace, sl
|
|
|
22958
23352
|
);
|
|
22959
23353
|
if (suspense.deps <= 0) {
|
|
22960
23354
|
suspense.resolve();
|
|
22961
|
-
} else {
|
|
23355
|
+
} else if (!suspense.isFallbackMountPending) {
|
|
22962
23356
|
patch(
|
|
22963
23357
|
activeBranch,
|
|
22964
23358
|
newFallback,
|
|
@@ -23179,6 +23573,7 @@ function createSuspenseBoundary(vnode, parentSuspense, parentComponent, containe
|
|
|
23179
23573
|
suspense.effects = [];
|
|
23180
23574
|
if (isSuspensible) {
|
|
23181
23575
|
if (parentSuspense && parentSuspense.pendingBranch && parentSuspenseId === parentSuspense.pendingId) {
|
|
23576
|
+
parentSuspenseId = void 0;
|
|
23182
23577
|
parentSuspense.deps--;
|
|
23183
23578
|
if (parentSuspense.deps === 0 && !sync) {
|
|
23184
23579
|
parentSuspense.resolve();
|
|
@@ -23199,9 +23594,10 @@ function createSuspenseBoundary(vnode, parentSuspense, parentComponent, containe
|
|
|
23199
23594
|
if (!suspense.isInFallback) {
|
|
23200
23595
|
return;
|
|
23201
23596
|
}
|
|
23597
|
+
const latestFallback = suspense.vnode.ssFallback;
|
|
23202
23598
|
patch(
|
|
23203
23599
|
null,
|
|
23204
|
-
|
|
23600
|
+
latestFallback,
|
|
23205
23601
|
container2,
|
|
23206
23602
|
anchor2,
|
|
23207
23603
|
parentComponent2,
|
|
@@ -23211,7 +23607,7 @@ function createSuspenseBoundary(vnode, parentSuspense, parentComponent, containe
|
|
|
23211
23607
|
slotScopeIds,
|
|
23212
23608
|
optimized
|
|
23213
23609
|
);
|
|
23214
|
-
setActiveBranch(suspense,
|
|
23610
|
+
setActiveBranch(suspense, latestFallback);
|
|
23215
23611
|
};
|
|
23216
23612
|
const delayEnter = fallbackVNode.transition && fallbackVNode.transition.mode === "out-in";
|
|
23217
23613
|
if (delayEnter) {
|
|
@@ -23251,6 +23647,12 @@ function createSuspenseBoundary(vnode, parentSuspense, parentComponent, containe
|
|
|
23251
23647
|
return;
|
|
23252
23648
|
}
|
|
23253
23649
|
unsetCurrentInstance();
|
|
23650
|
+
if (hydratedEl && !instance.scope.active) {
|
|
23651
|
+
if (isInPendingSuspense && --suspense.deps === 0) {
|
|
23652
|
+
suspense.resolve();
|
|
23653
|
+
}
|
|
23654
|
+
return;
|
|
23655
|
+
}
|
|
23254
23656
|
instance.asyncResolved = true;
|
|
23255
23657
|
const { vnode: vnode2 } = instance;
|
|
23256
23658
|
if (true) {
|
|
@@ -23672,7 +24074,8 @@ function cloneVNode(vnode, extraProps, mergeRef = false, cloneTransition = false
|
|
|
23672
24074
|
el: vnode.el,
|
|
23673
24075
|
anchor: vnode.anchor,
|
|
23674
24076
|
ctx: vnode.ctx,
|
|
23675
|
-
ce: vnode.ce
|
|
24077
|
+
ce: vnode.ce,
|
|
24078
|
+
cacheIndex: vnode.cacheIndex
|
|
23676
24079
|
};
|
|
23677
24080
|
if (transition && cloneTransition) {
|
|
23678
24081
|
setTransitionHooks(
|
|
@@ -24479,7 +24882,7 @@ function isMemoSame(cached, memo) {
|
|
|
24479
24882
|
return true;
|
|
24480
24883
|
}
|
|
24481
24884
|
|
|
24482
|
-
const version = "3.5.
|
|
24885
|
+
const version = "3.5.43";
|
|
24483
24886
|
const warn = true ? warn$1 : 0;
|
|
24484
24887
|
const ErrorTypeStrings = ErrorTypeStrings$1 ;
|
|
24485
24888
|
const devtools = true ? devtools$1 : 0;
|
|
@@ -24690,7 +25093,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
24690
25093
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-core */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
24691
25094
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
24692
25095
|
/**
|
|
24693
|
-
* @vue/runtime-dom v3.5.
|
|
25096
|
+
* @vue/runtime-dom v3.5.43
|
|
24694
25097
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
24695
25098
|
* @license MIT
|
|
24696
25099
|
**/
|
|
@@ -25273,7 +25676,11 @@ function setStyle(style, name, val) {
|
|
|
25273
25676
|
}
|
|
25274
25677
|
}
|
|
25275
25678
|
if (name.startsWith("--")) {
|
|
25276
|
-
|
|
25679
|
+
if (importantRE.test(val)) {
|
|
25680
|
+
style.setProperty(name, val.replace(importantRE, ""), "important");
|
|
25681
|
+
} else {
|
|
25682
|
+
style.setProperty(name, val);
|
|
25683
|
+
}
|
|
25277
25684
|
} else {
|
|
25278
25685
|
const prefixed = autoPrefix(style, name);
|
|
25279
25686
|
if (importantRE.test(val)) {
|
|
@@ -26407,13 +26814,21 @@ const vModelSelect = {
|
|
|
26407
26814
|
const selectedVal = Array.prototype.filter.call(el.options, (o) => o.selected).map(
|
|
26408
26815
|
(o) => number ? (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.looseToNumber)(getValue(o)) : getValue(o)
|
|
26409
26816
|
);
|
|
26410
|
-
el
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
|
|
26415
|
-
|
|
26416
|
-
|
|
26817
|
+
const multiple = el.multiple;
|
|
26818
|
+
const assignedValue = multiple ? (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.isSet)(el._modelValue) ? new Set(selectedVal) : selectedVal : selectedVal[0];
|
|
26819
|
+
const pending = el._pendingValue = [
|
|
26820
|
+
multiple,
|
|
26821
|
+
multiple ? (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.isArray)(assignedValue) ? selectedVal.slice() : selectedVal : assignedValue
|
|
26822
|
+
];
|
|
26823
|
+
try {
|
|
26824
|
+
el[assignKey](assignedValue);
|
|
26825
|
+
} finally {
|
|
26826
|
+
;(0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_0__.nextTick)(() => {
|
|
26827
|
+
if (el._pendingValue === pending) {
|
|
26828
|
+
el._pendingValue = void 0;
|
|
26829
|
+
}
|
|
26830
|
+
});
|
|
26831
|
+
}
|
|
26417
26832
|
});
|
|
26418
26833
|
el[assignKey] = getModelAssigner(vnode);
|
|
26419
26834
|
},
|
|
@@ -26427,11 +26842,25 @@ const vModelSelect = {
|
|
|
26427
26842
|
el[assignKey] = getModelAssigner(vnode);
|
|
26428
26843
|
},
|
|
26429
26844
|
updated(el, { value }) {
|
|
26430
|
-
|
|
26845
|
+
const pending = el._pendingValue;
|
|
26846
|
+
el._pendingValue = void 0;
|
|
26847
|
+
if (!pending || pending[0] !== el.multiple || !isSameSelectValue(value, pending[1], pending[0])) {
|
|
26431
26848
|
setSelected(el, value);
|
|
26432
26849
|
}
|
|
26433
26850
|
}
|
|
26434
26851
|
};
|
|
26852
|
+
function isSameSelectValue(value, assignedValue, multiple) {
|
|
26853
|
+
if (!multiple) return (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.looseEqual)(value, assignedValue);
|
|
26854
|
+
if ((0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.isArray)(value)) return (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.looseEqual)(value, assignedValue);
|
|
26855
|
+
if ((0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.isSet)(value)) {
|
|
26856
|
+
if (value.size !== assignedValue.length) return false;
|
|
26857
|
+
for (const item of assignedValue) {
|
|
26858
|
+
if (!value.has(item)) return false;
|
|
26859
|
+
}
|
|
26860
|
+
return true;
|
|
26861
|
+
}
|
|
26862
|
+
return false;
|
|
26863
|
+
}
|
|
26435
26864
|
function setSelected(el, value) {
|
|
26436
26865
|
const isMultiple = el.multiple;
|
|
26437
26866
|
const isArrayValue = (0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__.isArray)(value);
|
|
@@ -26812,7 +27241,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26812
27241
|
/* harmony export */ toTypeString: () => (/* binding */ toTypeString)
|
|
26813
27242
|
/* harmony export */ });
|
|
26814
27243
|
/**
|
|
26815
|
-
* @vue/shared v3.5.
|
|
27244
|
+
* @vue/shared v3.5.43
|
|
26816
27245
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
26817
27246
|
* @license MIT
|
|
26818
27247
|
**/
|
|
@@ -27080,10 +27509,10 @@ function normalizeStyle(value) {
|
|
|
27080
27509
|
}
|
|
27081
27510
|
const listDelimiterRE = /;(?![^(]*\))/g;
|
|
27082
27511
|
const propertyDelimiterRE = /:([^]+)/;
|
|
27083
|
-
const styleCommentRE =
|
|
27512
|
+
const styleCommentRE = /"(?:[^"\\]|\\[^])*"|'(?:[^'\\]|\\[^])*'|\\[^]|\/\*[^]*?\*\//g;
|
|
27084
27513
|
function parseStringStyle(cssText) {
|
|
27085
27514
|
const ret = {};
|
|
27086
|
-
cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => {
|
|
27515
|
+
cssText.replace(styleCommentRE, (match) => match.startsWith("/*") ? "" : match).split(listDelimiterRE).forEach((item) => {
|
|
27087
27516
|
if (item) {
|
|
27088
27517
|
const tmp = item.split(propertyDelimiterRE);
|
|
27089
27518
|
tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());
|
|
@@ -27153,7 +27582,7 @@ const isBooleanAttr = /* @__PURE__ */ makeMap(
|
|
|
27153
27582
|
function includeBooleanAttr(value) {
|
|
27154
27583
|
return !!value || value === "";
|
|
27155
27584
|
}
|
|
27156
|
-
const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/;
|
|
27585
|
+
const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u000d\u0020]/;
|
|
27157
27586
|
const attrValidationCache = {};
|
|
27158
27587
|
function isSSRSafeAttrName(name) {
|
|
27159
27588
|
if (attrValidationCache.hasOwnProperty(name)) {
|
|
@@ -27244,15 +27673,72 @@ function getEscapedCssVarName(key, doubleEscape) {
|
|
|
27244
27673
|
);
|
|
27245
27674
|
}
|
|
27246
27675
|
|
|
27247
|
-
function looseCompareArrays(a, b) {
|
|
27676
|
+
function looseCompareArrays(a, b, seen) {
|
|
27248
27677
|
if (a.length !== b.length) return false;
|
|
27249
27678
|
let equal = true;
|
|
27250
27679
|
for (let i = 0; equal && i < a.length; i++) {
|
|
27251
|
-
equal = looseEqual(a[i], b[i]);
|
|
27680
|
+
equal = looseEqual(a[i], b[i], seen);
|
|
27252
27681
|
}
|
|
27253
27682
|
return equal;
|
|
27254
27683
|
}
|
|
27255
|
-
function
|
|
27684
|
+
function looseCompareCollections(a, b, seen) {
|
|
27685
|
+
if (a.size !== b.size) return false;
|
|
27686
|
+
const candidates = Array.from(b);
|
|
27687
|
+
const matched = new Uint8Array(candidates.length);
|
|
27688
|
+
for (const item of a) {
|
|
27689
|
+
let index = -1;
|
|
27690
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
27691
|
+
if (!matched[i] && looseEqual(item, candidates[i], seen)) {
|
|
27692
|
+
index = i;
|
|
27693
|
+
break;
|
|
27694
|
+
}
|
|
27695
|
+
}
|
|
27696
|
+
if (index < 0) return false;
|
|
27697
|
+
matched[index] = 1;
|
|
27698
|
+
}
|
|
27699
|
+
return true;
|
|
27700
|
+
}
|
|
27701
|
+
function looseCompareObjects(a, b, seen) {
|
|
27702
|
+
let aValidType = isMap(a);
|
|
27703
|
+
let bValidType = isMap(b);
|
|
27704
|
+
if (aValidType || bValidType) {
|
|
27705
|
+
return aValidType && bValidType ? looseCompareCollections(a, b, seen) : false;
|
|
27706
|
+
}
|
|
27707
|
+
aValidType = isSet(a);
|
|
27708
|
+
bValidType = isSet(b);
|
|
27709
|
+
if (aValidType || bValidType) {
|
|
27710
|
+
return aValidType && bValidType ? looseCompareCollections(a, b, seen) : false;
|
|
27711
|
+
}
|
|
27712
|
+
const aKeysCount = Object.keys(a).length;
|
|
27713
|
+
const bKeysCount = Object.keys(b).length;
|
|
27714
|
+
if (aKeysCount !== bKeysCount) {
|
|
27715
|
+
return false;
|
|
27716
|
+
}
|
|
27717
|
+
for (const key in a) {
|
|
27718
|
+
const aHasKey = a.hasOwnProperty(key);
|
|
27719
|
+
const bHasKey = b.hasOwnProperty(key);
|
|
27720
|
+
if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key], seen)) {
|
|
27721
|
+
return false;
|
|
27722
|
+
}
|
|
27723
|
+
}
|
|
27724
|
+
return String(a) === String(b);
|
|
27725
|
+
}
|
|
27726
|
+
function looseCompareNested(a, b, seen, compare) {
|
|
27727
|
+
if (!seen) {
|
|
27728
|
+
seen = [/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map()];
|
|
27729
|
+
}
|
|
27730
|
+
const [seenA, seenB] = seen;
|
|
27731
|
+
if (seenA.has(a) || seenB.has(b)) {
|
|
27732
|
+
return seenA.get(a) === b && seenB.get(b) === a;
|
|
27733
|
+
}
|
|
27734
|
+
seenA.set(a, b);
|
|
27735
|
+
seenB.set(b, a);
|
|
27736
|
+
const equal = compare(a, b, seen);
|
|
27737
|
+
seenA.delete(a);
|
|
27738
|
+
seenB.delete(b);
|
|
27739
|
+
return equal;
|
|
27740
|
+
}
|
|
27741
|
+
function looseEqual(a, b, seen) {
|
|
27256
27742
|
if (a === b) return true;
|
|
27257
27743
|
let aValidType = isDate(a);
|
|
27258
27744
|
let bValidType = isDate(b);
|
|
@@ -27267,7 +27753,7 @@ function looseEqual(a, b) {
|
|
|
27267
27753
|
aValidType = isArray(a);
|
|
27268
27754
|
bValidType = isArray(b);
|
|
27269
27755
|
if (aValidType || bValidType) {
|
|
27270
|
-
return aValidType && bValidType ?
|
|
27756
|
+
return aValidType && bValidType ? looseCompareNested(a, b, seen, looseCompareArrays) : false;
|
|
27271
27757
|
}
|
|
27272
27758
|
aValidType = isObject(a);
|
|
27273
27759
|
bValidType = isObject(b);
|
|
@@ -27275,18 +27761,7 @@ function looseEqual(a, b) {
|
|
|
27275
27761
|
if (!aValidType || !bValidType) {
|
|
27276
27762
|
return false;
|
|
27277
27763
|
}
|
|
27278
|
-
|
|
27279
|
-
const bKeysCount = Object.keys(b).length;
|
|
27280
|
-
if (aKeysCount !== bKeysCount) {
|
|
27281
|
-
return false;
|
|
27282
|
-
}
|
|
27283
|
-
for (const key in a) {
|
|
27284
|
-
const aHasKey = a.hasOwnProperty(key);
|
|
27285
|
-
const bHasKey = b.hasOwnProperty(key);
|
|
27286
|
-
if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {
|
|
27287
|
-
return false;
|
|
27288
|
-
}
|
|
27289
|
-
}
|
|
27764
|
+
return looseCompareNested(a, b, seen, looseCompareObjects);
|
|
27290
27765
|
}
|
|
27291
27766
|
return String(a) === String(b);
|
|
27292
27767
|
}
|
|
@@ -51775,6 +52250,128 @@ function parseUtf8ValidationOption(options) {
|
|
|
51775
52250
|
|
|
51776
52251
|
/***/ },
|
|
51777
52252
|
|
|
52253
|
+
/***/ "./node_modules/mongoose/node_modules/mongodb/lib/bson.js"
|
|
52254
|
+
/*!****************************************************************!*\
|
|
52255
|
+
!*** ./node_modules/mongoose/node_modules/mongodb/lib/bson.js ***!
|
|
52256
|
+
\****************************************************************/
|
|
52257
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
52258
|
+
|
|
52259
|
+
"use strict";
|
|
52260
|
+
|
|
52261
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
52262
|
+
exports.setUint32LE = exports.readUint8 = exports.readInt32LE = exports.UUID = exports.Timestamp = exports.serialize = exports.ObjectId = exports.NumberUtils = exports.MinKey = exports.MaxKey = exports.Long = exports.Int32 = exports.EJSON = exports.Double = exports.deserialize = exports.Decimal128 = exports.DBRef = exports.Code = exports.calculateObjectSize = exports.ByteUtils = exports.BSONType = exports.BSONSymbol = exports.BSONRegExp = exports.BSONError = exports.BSON = exports.Binary = void 0;
|
|
52263
|
+
exports.parseToElementsToArray = parseToElementsToArray;
|
|
52264
|
+
exports.pluckBSONSerializeOptions = pluckBSONSerializeOptions;
|
|
52265
|
+
exports.resolveBSONOptions = resolveBSONOptions;
|
|
52266
|
+
exports.parseUtf8ValidationOption = parseUtf8ValidationOption;
|
|
52267
|
+
/* eslint-disable no-restricted-imports */
|
|
52268
|
+
const bson_1 = __webpack_require__(/*! bson */ "./node_modules/bson/lib/bson.mjs");
|
|
52269
|
+
var bson_2 = __webpack_require__(/*! bson */ "./node_modules/bson/lib/bson.mjs");
|
|
52270
|
+
Object.defineProperty(exports, "Binary", ({ enumerable: true, get: function () { return bson_2.Binary; } }));
|
|
52271
|
+
Object.defineProperty(exports, "BSON", ({ enumerable: true, get: function () { return bson_2.BSON; } }));
|
|
52272
|
+
Object.defineProperty(exports, "BSONError", ({ enumerable: true, get: function () { return bson_2.BSONError; } }));
|
|
52273
|
+
Object.defineProperty(exports, "BSONRegExp", ({ enumerable: true, get: function () { return bson_2.BSONRegExp; } }));
|
|
52274
|
+
Object.defineProperty(exports, "BSONSymbol", ({ enumerable: true, get: function () { return bson_2.BSONSymbol; } }));
|
|
52275
|
+
Object.defineProperty(exports, "BSONType", ({ enumerable: true, get: function () { return bson_2.BSONType; } }));
|
|
52276
|
+
Object.defineProperty(exports, "ByteUtils", ({ enumerable: true, get: function () { return bson_2.ByteUtils; } }));
|
|
52277
|
+
Object.defineProperty(exports, "calculateObjectSize", ({ enumerable: true, get: function () { return bson_2.calculateObjectSize; } }));
|
|
52278
|
+
Object.defineProperty(exports, "Code", ({ enumerable: true, get: function () { return bson_2.Code; } }));
|
|
52279
|
+
Object.defineProperty(exports, "DBRef", ({ enumerable: true, get: function () { return bson_2.DBRef; } }));
|
|
52280
|
+
Object.defineProperty(exports, "Decimal128", ({ enumerable: true, get: function () { return bson_2.Decimal128; } }));
|
|
52281
|
+
Object.defineProperty(exports, "deserialize", ({ enumerable: true, get: function () { return bson_2.deserialize; } }));
|
|
52282
|
+
Object.defineProperty(exports, "Double", ({ enumerable: true, get: function () { return bson_2.Double; } }));
|
|
52283
|
+
Object.defineProperty(exports, "EJSON", ({ enumerable: true, get: function () { return bson_2.EJSON; } }));
|
|
52284
|
+
Object.defineProperty(exports, "Int32", ({ enumerable: true, get: function () { return bson_2.Int32; } }));
|
|
52285
|
+
Object.defineProperty(exports, "Long", ({ enumerable: true, get: function () { return bson_2.Long; } }));
|
|
52286
|
+
Object.defineProperty(exports, "MaxKey", ({ enumerable: true, get: function () { return bson_2.MaxKey; } }));
|
|
52287
|
+
Object.defineProperty(exports, "MinKey", ({ enumerable: true, get: function () { return bson_2.MinKey; } }));
|
|
52288
|
+
Object.defineProperty(exports, "NumberUtils", ({ enumerable: true, get: function () { return bson_2.NumberUtils; } }));
|
|
52289
|
+
Object.defineProperty(exports, "ObjectId", ({ enumerable: true, get: function () { return bson_2.ObjectId; } }));
|
|
52290
|
+
Object.defineProperty(exports, "serialize", ({ enumerable: true, get: function () { return bson_2.serialize; } }));
|
|
52291
|
+
Object.defineProperty(exports, "Timestamp", ({ enumerable: true, get: function () { return bson_2.Timestamp; } }));
|
|
52292
|
+
Object.defineProperty(exports, "UUID", ({ enumerable: true, get: function () { return bson_2.UUID; } }));
|
|
52293
|
+
function parseToElementsToArray(bytes, offset) {
|
|
52294
|
+
const res = bson_1.BSON.onDemand.parseToElements(bytes, offset);
|
|
52295
|
+
return Array.isArray(res) ? res : [...res];
|
|
52296
|
+
}
|
|
52297
|
+
// validates buffer inputs, used for read operations
|
|
52298
|
+
const validateBufferInputs = (buffer, offset, length) => {
|
|
52299
|
+
if (offset < 0 || offset + length > buffer.length) {
|
|
52300
|
+
throw new RangeError(`Attempt to access memory outside buffer bounds: buffer length: ${buffer.length}, offset: ${offset}, length: ${length}`);
|
|
52301
|
+
}
|
|
52302
|
+
};
|
|
52303
|
+
// readInt32LE, reads a 32-bit integer from buffer at given offset
|
|
52304
|
+
// throws if offset is out of bounds
|
|
52305
|
+
const readInt32LE = (buffer, offset) => {
|
|
52306
|
+
validateBufferInputs(buffer, offset, 4);
|
|
52307
|
+
return bson_1.NumberUtils.getInt32LE(buffer, offset);
|
|
52308
|
+
};
|
|
52309
|
+
exports.readInt32LE = readInt32LE;
|
|
52310
|
+
// readUint8, reads a single unsigned byte from buffer at given offset
|
|
52311
|
+
const readUint8 = (buffer, offset) => {
|
|
52312
|
+
validateBufferInputs(buffer, offset, 1);
|
|
52313
|
+
return buffer[offset];
|
|
52314
|
+
};
|
|
52315
|
+
exports.readUint8 = readUint8;
|
|
52316
|
+
const setUint32LE = (destination, offset, value) => {
|
|
52317
|
+
destination[offset] = value;
|
|
52318
|
+
value >>>= 8;
|
|
52319
|
+
destination[offset + 1] = value;
|
|
52320
|
+
value >>>= 8;
|
|
52321
|
+
destination[offset + 2] = value;
|
|
52322
|
+
value >>>= 8;
|
|
52323
|
+
destination[offset + 3] = value;
|
|
52324
|
+
return 4;
|
|
52325
|
+
};
|
|
52326
|
+
exports.setUint32LE = setUint32LE;
|
|
52327
|
+
function pluckBSONSerializeOptions(options) {
|
|
52328
|
+
const { fieldsAsRaw, useBigInt64, promoteValues, promoteBuffers, promoteLongs, serializeFunctions, ignoreUndefined, bsonRegExp, raw, enableUtf8Validation } = options;
|
|
52329
|
+
return {
|
|
52330
|
+
fieldsAsRaw,
|
|
52331
|
+
useBigInt64,
|
|
52332
|
+
promoteValues,
|
|
52333
|
+
promoteBuffers,
|
|
52334
|
+
promoteLongs,
|
|
52335
|
+
serializeFunctions,
|
|
52336
|
+
ignoreUndefined,
|
|
52337
|
+
bsonRegExp,
|
|
52338
|
+
raw,
|
|
52339
|
+
enableUtf8Validation
|
|
52340
|
+
};
|
|
52341
|
+
}
|
|
52342
|
+
/**
|
|
52343
|
+
* Merge the given BSONSerializeOptions, preferring options over the parent's options, and
|
|
52344
|
+
* substituting defaults for values not set.
|
|
52345
|
+
*
|
|
52346
|
+
* @internal
|
|
52347
|
+
*/
|
|
52348
|
+
function resolveBSONOptions(options, parent) {
|
|
52349
|
+
const parentOptions = parent?.bsonOptions;
|
|
52350
|
+
return {
|
|
52351
|
+
raw: options?.raw ?? parentOptions?.raw ?? false,
|
|
52352
|
+
useBigInt64: options?.useBigInt64 ?? parentOptions?.useBigInt64 ?? false,
|
|
52353
|
+
promoteLongs: options?.promoteLongs ?? parentOptions?.promoteLongs ?? true,
|
|
52354
|
+
promoteValues: options?.promoteValues ?? parentOptions?.promoteValues ?? true,
|
|
52355
|
+
promoteBuffers: options?.promoteBuffers ?? parentOptions?.promoteBuffers ?? false,
|
|
52356
|
+
ignoreUndefined: options?.ignoreUndefined ?? parentOptions?.ignoreUndefined ?? false,
|
|
52357
|
+
bsonRegExp: options?.bsonRegExp ?? parentOptions?.bsonRegExp ?? false,
|
|
52358
|
+
serializeFunctions: options?.serializeFunctions ?? parentOptions?.serializeFunctions ?? false,
|
|
52359
|
+
fieldsAsRaw: options?.fieldsAsRaw ?? parentOptions?.fieldsAsRaw ?? {},
|
|
52360
|
+
enableUtf8Validation: options?.enableUtf8Validation ?? parentOptions?.enableUtf8Validation ?? true
|
|
52361
|
+
};
|
|
52362
|
+
}
|
|
52363
|
+
/** @internal */
|
|
52364
|
+
function parseUtf8ValidationOption(options) {
|
|
52365
|
+
const enableUtf8Validation = options?.enableUtf8Validation;
|
|
52366
|
+
if (enableUtf8Validation === false) {
|
|
52367
|
+
return { utf8: false };
|
|
52368
|
+
}
|
|
52369
|
+
return { utf8: { writeErrors: false } };
|
|
52370
|
+
}
|
|
52371
|
+
//# sourceMappingURL=bson.js.map
|
|
52372
|
+
|
|
52373
|
+
/***/ },
|
|
52374
|
+
|
|
51778
52375
|
/***/ "./node_modules/mpath/index.js"
|
|
51779
52376
|
/*!*************************************!*\
|
|
51780
52377
|
!*** ./node_modules/mpath/index.js ***!
|
|
@@ -52532,7 +53129,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
52532
53129
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js");
|
|
52533
53130
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js");
|
|
52534
53131
|
/**
|
|
52535
|
-
* vue v3.5.
|
|
53132
|
+
* vue v3.5.43
|
|
52536
53133
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
52537
53134
|
* @license MIT
|
|
52538
53135
|
**/
|
|
@@ -54317,6 +54914,17 @@ module.exports = "<div class=\"list-subdocument tooltip\">\n <div>{{shortenValu
|
|
|
54317
54914
|
|
|
54318
54915
|
/***/ },
|
|
54319
54916
|
|
|
54917
|
+
/***/ "./frontend/src/mcp/mcp.html"
|
|
54918
|
+
/*!***********************************!*\
|
|
54919
|
+
!*** ./frontend/src/mcp/mcp.html ***!
|
|
54920
|
+
\***********************************/
|
|
54921
|
+
(module) {
|
|
54922
|
+
|
|
54923
|
+
"use strict";
|
|
54924
|
+
module.exports = "<div class=\"mx-auto max-w-5xl py-6 px-2\">\n <h1 class=\"text-xl font-bold text-content\">MCP</h1>\n <p class=\"mt-2 text-sm text-content-secondary\">\n Connect an MCP client such as Claude or ChatGPT to this Mongoose Studio workspace.\n </p>\n\n <div class=\"mt-6 rounded-lg border border-edge bg-surface p-4\">\n <label for=\"mcp-url\" class=\"block text-sm font-medium text-content\">MCP URL</label>\n <div class=\"mt-2 flex gap-2\">\n <input\n id=\"mcp-url\"\n type=\"text\"\n readonly\n :value=\"mcpUrl\"\n class=\"min-w-0 flex-1 rounded-md bg-muted px-3 py-2 font-mono text-sm text-content outline outline-1 -outline-offset-1 outline-edge-strong\"\n />\n <async-button\n type=\"button\"\n @click=\"copyMCPUrl\"\n class=\"rounded-md bg-primary px-4 py-2 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover\">\n Copy\n </async-button>\n </div>\n </div>\n\n <div class=\"mt-8 grid gap-6 text-sm text-content-secondary\">\n <section>\n <h2 class=\"text-base font-semibold text-content\">Authentication and network access</h2>\n <p class=\"mt-2\">\n Without a Mongoose Studio API key, the MCP endpoint uses the deployment's\n <code class=\"rounded bg-muted px-1 py-0.5\">bindIp</code> restrictions. By default, this means an MCP client can only connect from localhost.\n </p>\n <p class=\"mt-2\">\n With an API key, MCP clients such as Claude and ChatGPT connect through OAuth. You will be prompted to sign in to Mongoose Studio and approve the connection before the client receives access.\n </p>\n </section>\n\n <section>\n <h2 class=\"text-base font-semibold text-content\">Permissions</h2>\n <p class=\"mt-2\">\n When an API key is configured, MCP access is scoped to the signed-in user's workspace permissions. During authorization, the user can explicitly grant fewer permissions, such as read-only access or a lower execution time limit. An MCP connection can never receive more access than that user already has.\n </p>\n </section>\n\n <section>\n <h2 class=\"text-base font-semibold text-content\">Supported operations</h2>\n <p class=\"mt-2\">\n The MCP server supports database CRUD operations, dashboards, and script creation. It does not execute standalone scripts directly.\n </p>\n <p class=\"mt-2\">\n An MCP client can create a script and return a Mongoose Studio URL. A person can then open that URL, review or edit the code, and choose whether to dry run or execute it.\n </p>\n </section>\n </div>\n</div>\n";
|
|
54925
|
+
|
|
54926
|
+
/***/ },
|
|
54927
|
+
|
|
54320
54928
|
/***/ "./frontend/src/modal/modal.css"
|
|
54321
54929
|
/*!**************************************!*\
|
|
54322
54930
|
!*** ./frontend/src/modal/modal.css ***!
|
|
@@ -54390,7 +54998,7 @@ module.exports = ".models {\n position: relative;\n display: flex;\n flex-dir
|
|
|
54390
54998
|
(module) {
|
|
54391
54999
|
|
|
54392
55000
|
"use strict";
|
|
54393
|
-
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <aside class=\"bg-page border-r overflow-hidden transition-all duration-300 ease-in-out z-20 w-0 lg:w-64 fixed lg:relative shrink-0 flex flex-col top-[55px] bottom-0 lg:top-auto lg:bottom-auto lg:h-full\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-64' : ''\">\n <!-- Search -->\n <div class=\"p-3 shrink-0\">\n <div class=\"relative\">\n <svg class=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" />\n </svg>\n <input\n v-model=\"modelSearch\"\n type=\"text\"\n placeholder=\"Find model...\"\n @keydown.esc=\"modelSearch = ''\"\n class=\"w-full rounded-md border border-edge bg-surface py-1.5 pl-8 pr-3 text-sm text-content placeholder:text-gray-400 focus:border-edge-strong focus:outline-none focus:ring-1 focus:ring-gray-300\"\n />\n </div>\n </div>\n <!-- Model list (scrollable) -->\n <nav class=\"flex-1 overflow-y-auto px-2 pb-2\">\n <!-- Recently Viewed -->\n <div v-if=\"filteredRecentModels.length > 0 && !modelSearch.trim()\">\n <div class=\"px-2 py-1 text-xs font-semibold text-gray-400 uppercase tracking-wider\">Recently Viewed</div>\n <ul role=\"list\">\n <li v-for=\"model in filteredRecentModels\" :key=\"'recent-' + model\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"flex items-center rounded-md py-1.5 px-2 text-sm text-content-secondary\"\n :class=\"model === currentModel ? 'bg-gray-200 font-semibold text-content' : 'hover:bg-muted'\">\n <span class=\"truncate\" v-html=\"highlightMatch(model)\"></span>\n <span\n v-if=\"modelDocumentCounts && modelDocumentCounts[model] !== undefined && model !== currentModel\"\n class=\"ml-auto text-xs text-gray-400 bg-muted rounded px-1.5 py-[1px]\"\n >\n {{formatCompactCount(modelDocumentCounts[model])}}\n </span>\n </router-link>\n </li>\n </ul>\n <div class=\"border-b border-edge my-2\"></div>\n </div>\n <!-- All Models / Search Results -->\n <div class=\"px-2 py-1 text-xs font-semibold text-gray-400 uppercase tracking-wider\">{{ modelSearch.trim() ? 'Search Results' : 'All Models' }}</div>\n <ul role=\"list\">\n <li v-for=\"model in filteredModels\" :key=\"'all-' + model\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"flex items-center rounded-md py-1.5 px-2 text-sm text-content-secondary\"\n :class=\"model === currentModel ? 'bg-gray-200 font-semibold text-content' : 'hover:bg-muted'\">\n <span class=\"truncate\" v-html=\"highlightMatch(model)\"></span>\n <span\n v-if=\"modelDocumentCounts && modelDocumentCounts[model] !== undefined && model !== currentModel\"\n class=\"ml-auto text-xs text-gray-400 bg-muted rounded px-1.5 py-[1px]\"\n >\n {{formatCompactCount(modelDocumentCounts[model])}}\n </span>\n </router-link>\n </li>\n </ul>\n <div v-if=\"filteredModels.length === 0 && modelSearch.trim()\" class=\"px-2 py-2 text-sm text-content-tertiary\">\n No models match \"{{modelSearch}}\"\n </div>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100 rounded-md\">\n No models found\n </div>\n </nav>\n <!-- Bottom toolbar -->\n <div class=\"shrink-0 border-t border-edge bg-page px-2 py-1.5 flex items-center gap-1\">\n <button\n type=\"button\"\n @click=\"hideSidebar = true\"\n class=\"rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n title=\"Hide sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n @click=\"openModelSwitcher\"\n class=\"rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n title=\"Quick switch (Ctrl+P)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" />\n </svg>\n </button>\n </div>\n </aside>\n <div class=\"documents bg-slate-50 min-w-0\" ref=\"documentsList\">\n <div class=\"documents-menu bg-slate-50\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <button\n v-if=\"hideSidebar === true || hideSidebar === null\"\n type=\"button\"\n @click=\"hideSidebar = false\"\n class=\"shrink-0 rounded-md p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n :class=\"hideSidebar === null ? 'lg:hidden' : ''\"\n title=\"Show sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n <document-search\n ref=\"documentSearch\"\n :value=\"searchText\"\n :schema-paths=\"schemaPaths\"\n @search=\"search\"\n >\n </document-search>\n <div>\n <span v-if=\"numDocuments == null\">Loading ...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{documents.length}}/{{numDocuments === 1 ? numDocuments + ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{\n 'bg-gray-700 ring-inset ring-2 ring-gray-300 text-white hover:bg-gray-600': selectMultiple,\n 'bg-primary hover:bg-primary-hover text-primary-text': !selectMultiple\n }\"\n class=\"rounded px-2 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n 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\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n 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\"\n >\n Delete\n </button>\n <div class=\"relative\" v-show=\"!selectMultiple\" ref=\"actionsMenuContainer\" @keyup.esc.prevent=\"closeActionsMenu\">\n <button\n @click=\"toggleActionsMenu\"\n type=\"button\"\n aria-label=\"More actions\"\n class=\"rounded bg-surface px-2 py-2 text-sm font-semibold text-content-secondary shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-page focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z\" />\n </svg>\n </button>\n <div\n v-if=\"showActionsMenu\"\n class=\"absolute right-0 mt-2 w-48 origin-top-right rounded-md bg-surface shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-50\"\n >\n <div class=\"py-1\">\n <button\n @click=\"shouldShowExportModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Export\n </button>\n <button\n @click=\"shouldShowCreateModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Create\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Indexes\n </button>\n <button\n @click=\"openAnalyzeSchemaModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Analyze Schema\n </button>\n <button\n @click=\"openCollectionInfo\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Collection Info\n </button>\n <button\n @click=\"toggleRowNumbers()\"\n :disabled=\"outputType !== 'table'\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm\"\n :class=\"outputType === 'table' ? 'text-content-secondary hover:bg-muted' : 'text-content-tertiary cursor-not-allowed opacity-50'\"\n >\n {{ showRowNumbers ? 'Hide row numbers' : 'Show row numbers' }}\n </button>\n <button\n @click=\"resetFilter()\"\n :disabled=\"searchText.trim().length === 0\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm\"\n :class=\"searchText.trim().length > 0 ? 'text-content-secondary hover:bg-muted' : 'text-content-tertiary cursor-not-allowed opacity-50'\"\n >\n Reset Filter\n </button>\n <button\n @click=\"toggleProjectionMenu(); showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm hover:bg-muted\"\n :class=\"isProjectionMenuSelected ? 'text-primary font-semibold' : 'text-content-secondary'\"\n >\n {{ isProjectionMenuSelected ? 'Projection (On)' : 'Projection' }}\n </button>\n <button\n v-if=\"isProjectionMenuSelected\"\n @click=\"clearProjection()\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Reset Projection\n </button>\n <async-button\n v-if=\"isProjectionMenuSelected\"\n type=\"button\"\n @click=\"applyDefaultProjectionColumns()\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Default Projection\n </async-button>\n <button\n @click=\"openDropCollectionModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-red-700 hover:bg-red-50\"\n >\n Drop Collection\n </button>\n </div>\n </div>\n </div>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-page focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-surface'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-page focus:z-10\"\n :class=\"outputType === 'json' ? 'bg-gray-200' : 'bg-surface'\">\n <img class=\"h-5 w-5\" src=\"images/json.svg\">\n </button>\n <button\n @click=\"setOutputType('map')\"\n :disabled=\"geoJsonFields.length === 0\"\n type=\"button\"\n :title=\"geoJsonFields.length > 0 ? 'Map view' : 'No GeoJSON fields detected'\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 ring-1 ring-inset ring-gray-300 focus:z-10\"\n :class=\"[\n geoJsonFields.length === 0 ? 'text-gray-300 cursor-not-allowed bg-muted' : 'text-gray-400 hover:bg-page',\n outputType === 'map' ? 'bg-gray-200' : (geoJsonFields.length > 0 ? 'bg-surface' : '')\n ]\">\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.503 3.498 4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 0 0-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0Z\" />\n </svg>\n </button>\n </span>\n </div>\n <div v-if=\"isProjectionMenuSelected && (outputType === 'table' || outputType === 'json')\" class=\"flex items-center gap-2 w-full mt-2 flex-shrink-0\">\n <projection-search\n ref=\"projectionSearch\"\n :value=\"projectionText\"\n :schema-paths=\"schemaPaths\"\n @projection-input=\"projectionText = $event\"\n @apply=\"applyProjectionFromInput\"\n />\n </div>\n </div>\n <!-- In JSON view, this container is the scrollable element used for infinite scroll. -->\n <div class=\"documents-container relative\" ref=\"documentsContainerScroll\" @scroll=\"checkIfScrolledToBottom\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n <span class=\"block mt-2\">\n Need help?\n <a\n href=\"https://discord.gg/P3YCfKYxpy\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"underline font-medium text-red-800 hover:text-red-900\"\n >Ask in Discord</a>\n or\n <a\n href=\"https://github.com/mongoosejs/studio/issues\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"underline font-medium text-red-800 hover:text-red-900\"\n >\n open a GitHub issue.\n </a>\n </span>\n </div>\n </div>\n <div v-else-if=\"outputType === 'table'\" class=\"flex-1 min-h-0 flex flex-col overflow-hidden\">\n <div\n ref=\"documentsScrollContainer\"\n class=\"overflow-x-auto overflow-y-auto flex-1 min-h-0 border border-edge rounded-lg bg-surface\"\n @scroll=\"checkIfScrolledToBottom\"\n >\n <table class=\"min-w-full border-collapse text-sm\">\n <thead class=\"sticky top-0 z-10 bg-slate-100 dark:bg-shark-800 border-b border-edge\">\n <tr>\n <th v-if=\"showRowNumbers\" class=\"px-3 py-2.5 text-left font-medium text-content border-r border-edge whitespace-nowrap align-middle w-0\">\n #\n </th>\n <th\n v-for=\"path in tableDisplayPaths\"\n :key=\"path.path\"\n class=\"px-3 py-2.5 text-left font-medium text-content border-r border-edge last:border-r-0 whitespace-nowrap align-middle\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n @click=\"addPathFilter(path.path)\"\n class=\"cursor-pointer hover:text-primary truncate min-w-0\"\n :title=\"path.path\"\n >\n {{ path.path }}\n </span>\n <span class=\"text-xs text-content-tertiary shrink-0\">({{ path.instance || 'unknown' }})</span>\n <span class=\"inline-flex shrink-0 gap-0.5 items-center\">\n <button\n type=\"button\"\n @click.stop=\"sortDocs(1, path.path)\"\n class=\"p-0.5 rounded text-content-tertiary hover:text-content hover:bg-muted\"\n :class=\"{ 'text-primary font-semibold': sortBy[path.path] === 1 }\"\n :title=\"sortBy[path.path] === 1 ? 'Clear sort' : 'Sort ascending'\"\n >\n ↑\n </button>\n <button\n type=\"button\"\n @click.stop=\"sortDocs(-1, path.path)\"\n class=\"p-0.5 rounded text-content-tertiary hover:text-content hover:bg-muted\"\n :class=\"{ 'text-primary font-semibold': sortBy[path.path] === -1 }\"\n :title=\"sortBy[path.path] === -1 ? 'Clear sort' : 'Sort descending'\"\n >\n ↓\n </button>\n <button\n v-if=\"filteredPaths.length > 0\"\n type=\"button\"\n @click.stop=\"removeField(path)\"\n class=\"p-1.5 rounded-md border border-transparent text-content-tertiary hover:text-valencia-600 hover:bg-valencia-50 hover:border-valencia-200 focus:outline-none focus:ring-2 focus:ring-valencia-500/30\"\n title=\"Remove column\"\n aria-label=\"Remove column\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n </button>\n </span>\n </div>\n </th>\n <th v-if=\"filteredPaths.length > 0\" class=\"px-2 py-2.5 border-r border-edge last:border-r-0 align-middle w-0 bg-slate-50 dark:bg-shark-800/80\">\n <div class=\"relative\" ref=\"addFieldContainer\">\n <button\n type=\"button\"\n @click=\"toggleAddFieldDropdown()\"\n class=\"flex items-center justify-center w-8 h-8 rounded border border-dashed border-edge text-content-tertiary hover:border-primary hover:text-primary hover:bg-primary-subtle/30\"\n title=\"Add column\"\n aria-label=\"Add column\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\" class=\"w-5 h-5\"> <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" /> </svg>\n </button>\n <div\n v-if=\"showAddFieldDropdown\"\n class=\"absolute right-0 top-full mt-1 z-[100] min-w-[180px] max-w-[280px] rounded-md border border-edge bg-surface shadow-lg py-1 max-h-48 overflow-y-auto\"\n >\n <input\n v-if=\"availablePathsToAdd.length > 5\"\n ref=\"addFieldFilterInput\"\n v-model=\"addFieldFilterText\"\n type=\"text\"\n placeholder=\"Filter fields...\"\n class=\"mx-2 mb-1 w-[calc(100%-1rem)] rounded border border-edge px-2 py-1 text-sm\"\n @click.stop\n />\n <button\n v-for=\"p in filteredPathsToAdd\"\n :key=\"p.path\"\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left text-sm hover:bg-muted\"\n @click.stop=\"addField(p)\"\n >\n {{ p.path }}\n </button>\n <p v-if=\"filteredPathsToAdd.length === 0\" class=\"px-3 py-2 text-sm text-content-tertiary\">\n {{ addFieldFilterText.trim() ? 'No matching fields' : 'All fields added' }}\n </p>\n </div>\n </div>\n </th>\n </tr>\n </thead>\n <tbody class=\"bg-surface\">\n <tr\n v-for=\"(document, docIndex) in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentClick(document, $event)\"\n class=\"border-b border-edge cursor-pointer transition-colors\"\n :class=\"selectedDocuments.some(x => x._id.toString() === document._id.toString())\n ? 'bg-blue-200'\n : 'hover:bg-muted'\"\n >\n <td v-if=\"showRowNumbers\" class=\"px-3 py-2 border-r border-edge align-top text-content-tertiary whitespace-nowrap\">\n {{ docIndex + 1 }}\n </td>\n <td\n v-for=\"schemaPath in tableDisplayPaths\"\n :key=\"schemaPath.path\"\n class=\"px-3 py-2 border-r border-edge last:border-r-0 align-top max-w-[280px]\"\n >\n <div class=\"table-cell-content flex items-center gap-1.5 min-w-0 group\">\n <span class=\"min-w-0 overflow-hidden text-ellipsis flex-1\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\"\n />\n </span>\n <button\n type=\"button\"\n class=\"table-cell-copy shrink-0 p-1 rounded text-content-tertiary hover:text-content hover:bg-muted focus:outline-none focus:ring-1 focus:ring-edge\"\n aria-label=\"Copy cell value\"\n @click.stop=\"copyCellValue(getValueForPath(document, schemaPath.path))\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1M8 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M8 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m0 0h2a2 2 0 0 1 2 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n </div>\n </td>\n <td v-if=\"filteredPaths.length > 0\" class=\"w-0 px-0 py-0 border-r border-edge last:border-r-0 bg-slate-50/50 dark:bg-shark-800/30\"></td>\n </tr>\n </tbody>\n </table>\n </div>\n <div v-if=\"outputType === 'table' && (loadingMore || (status === 'loading' && documents.length > 0))\" class=\"flex items-center justify-center gap-2 py-3 text-sm text-content-tertiary border-t border-edge bg-surface\">\n <img src=\"images/loader.gif\" alt=\"\" class=\"h-5 w-5\">\n <span>Loading documents…</span>\n </div>\n <p v-if=\"outputType === 'table' && documents.length === 0 && status === 'loaded'\" class=\"mt-2 text-sm text-content-tertiary px-1\">\n No documents to show. Use Projection in the menu to choose columns.\n </p>\n </div>\n <div v-else-if=\"outputType === 'json'\" class=\"flex min-w-0 flex-col space-y-2 p-1 mt-1\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative min-w-0 max-w-full transition-colors rounded-md border border-slate-100',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:shadow-sm hover:border-slate-300 bg-surface'\n ]\"\n >\n <router-link\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-primary px-2 py-1 text-xs font-semibold text-primary-text shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n :to=\"{ path: '/model/' + currentModel + '/document/' + document._id, query: $route.query }\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n @click.stop\n >\n Open\n </router-link>\n <list-json :value=\"filterDocument(document)\" :references=\"referenceMap\">\n </list-json>\n </div>\n <div v-if=\"outputType === 'json' && (loadingMore || (status === 'loading' && documents.length > 0))\" class=\"flex items-center justify-center gap-2 py-3 text-sm text-content-tertiary\">\n <img src=\"images/loader.gif\" alt=\"\" class=\"h-5 w-5\">\n <span>Loading documents…</span>\n </div>\n </div>\n <div v-else-if=\"outputType === 'map'\" class=\"flex flex-col h-full\">\n <div class=\"p-2 bg-surface border-b flex items-center gap-2\">\n <label class=\"text-sm font-medium text-content-secondary\">GeoJSON Field:</label>\n <select\n :value=\"selectedGeoField\"\n @change=\"setSelectedGeoField($event.target.value)\"\n class=\"rounded-md border border-edge-strong py-1 px-2 text-sm focus:border-primary focus:ring-primary\"\n >\n <option v-for=\"field in geoJsonFields\" :key=\"field.path\" :value=\"field.path\">\n {{ field.label }}\n </option>\n </select>\n <async-button\n @click=\"loadMoreDocuments\"\n :disabled=\"loadedAllDocs\"\n type=\"button\"\n class=\"rounded px-2 py-1 text-xs font-semibold text-primary-text shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n :class=\"loadedAllDocs ? 'bg-gray-400 cursor-not-allowed' : 'bg-primary hover:bg-primary-hover'\"\n >\n Load more\n </async-button>\n </div>\n <div class=\"flex-1 min-h-[400px]\" ref=\"modelsMap\"></div>\n </div>\n <div v-if=\"status === 'loading' && !loadingMore && documents.length === 0\" class=\"loader loader-overlay\" aria-busy=\"true\">\n <img src=\"images/loader.gif\" alt=\"Loading\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold flex items-center gap-2\">\n <div>{{ index.name }}</div>\n <div v-if=\"isTTLIndex(index)\" class=\"rounded-full bg-primary-subtle px-2 py-0.5 text-xs font-semibold text-primary\">\n TTL: {{ formatTTL(index.expireAfterSeconds) }}\n </div>\n </div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowAnalyzeSchemaModal\" containerClass=\"md:!w-[70vw]\">\n <template v-slot:body>\n <analyze-schema-modal\n :current-model=\"currentModel\"\n @close=\"shouldShowAnalyzeSchemaModal = false\"\n ></analyze-schema-modal>\n </template>\n </modal>\n <modal v-if=\"shouldShowCollectionInfoModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCollectionInfoModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Collection Info</div>\n <div v-if=\"!collectionInfo\" class=\"text-gray-600\">Loading collection details...</div>\n <div v-else class=\"space-y-3\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Documents</div>\n <div class=\"text-content\">{{ formatNumber(collectionInfo.documentCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Indexes</div>\n <div class=\"text-content\">{{ formatNumber(collectionInfo.indexCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Total Index Size</div>\n <div class=\"text-content\">{{ formatCollectionSize(collectionInfo.totalIndexSize) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Total Storage Size</div>\n <div class=\"text-content\">{{ formatCollectionSize(collectionInfo.size) }}</div>\n </div>\n <div class=\"flex flex-col gap-1\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Collation</div>\n <div class=\"text-content\">{{ collectionInfo.hasCollation ? 'Yes' : 'No' }}</div>\n </div>\n <div v-if=\"collectionInfo.hasCollation\" class=\"rounded bg-muted p-3 text-sm text-gray-800 overflow-x-auto\">\n <pre class=\"whitespace-pre-wrap\">{{ JSON.stringify(collectionInfo.collation, null, 2) }}</pre>\n </div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Capped</div>\n <div class=\"text-content\">{{ collectionInfo.capped ? 'Yes' : 'No' }}</div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <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\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-page0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowDropCollectionModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDropCollectionModal = false\">×</div>\n <h2 class=\"text-xl font-bold mb-3\">Are you sure?</h2>\n <p class=\"text-content-secondary mb-3\">\n This will permanently drop the <span class=\"font-semibold\">{{ currentModel }}</span> collection and all its documents.\n </p>\n <div v-if=\"requiresDropCollectionNameConfirmation()\" class=\"rounded border border-red-300 bg-red-50 px-3 py-2 mb-4\">\n <p class=\"text-sm font-semibold text-red-700\">Danger zone</p>\n <p class=\"text-sm text-red-700 mb-2\">Type <span class=\"font-mono font-semibold\">{{ currentModel }}</span> to confirm.</p>\n <input\n v-model=\"dropCollectionConfirmName\"\n type=\"text\"\n :placeholder=\"currentModel\"\n class=\"w-full rounded border border-red-300 px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-red-200\"\n />\n </div>\n <div class=\"flex gap-4\">\n <async-button\n @click=\"dropCollection\"\n :disabled=\"requiresDropCollectionNameConfirmation() && dropCollectionConfirmName !== currentModel\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Drop Collection\n </async-button>\n <button @click=\"shouldShowDropCollectionModal = false\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-page0\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n <model-switcher\n :show=\"showModelSwitcher\"\n :models=\"models\"\n :recently-viewed-models=\"recentlyViewedModels\"\n :model-document-counts=\"modelDocumentCounts\"\n @close=\"showModelSwitcher = false\"\n @select=\"selectSwitcherModel\"\n ></model-switcher>\n</div>\n";
|
|
55001
|
+
module.exports = "<div class=\"models flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <aside class=\"bg-page border-r overflow-hidden transition-all duration-300 ease-in-out z-20 w-0 lg:w-64 fixed lg:relative shrink-0 flex flex-col top-[55px] bottom-0 lg:top-auto lg:bottom-auto lg:h-full\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-64' : ''\">\n <!-- Search -->\n <div class=\"p-3 shrink-0\">\n <div class=\"relative\">\n <svg class=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" />\n </svg>\n <input\n v-model=\"modelSearch\"\n type=\"text\"\n placeholder=\"Find model...\"\n @keydown.esc=\"modelSearch = ''\"\n class=\"w-full rounded-md border border-edge bg-surface py-1.5 pl-8 pr-3 text-sm text-content placeholder:text-gray-400 focus:border-edge-strong focus:outline-none focus:ring-1 focus:ring-gray-300\"\n />\n </div>\n </div>\n <!-- Model list (scrollable) -->\n <nav class=\"flex-1 overflow-y-auto px-2 pb-2\">\n <!-- Recently Viewed -->\n <div v-if=\"filteredRecentModels.length > 0 && !modelSearch.trim()\">\n <div class=\"px-2 py-1 text-xs font-semibold text-gray-400 uppercase tracking-wider\">Recently Viewed</div>\n <ul role=\"list\">\n <li v-for=\"model in filteredRecentModels\" :key=\"'recent-' + model\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"flex items-center rounded-md py-1.5 px-2 text-sm text-content-secondary\"\n :class=\"model === currentModel ? 'bg-gray-200 font-semibold text-content' : 'hover:bg-muted'\">\n <span class=\"truncate\" v-html=\"highlightMatch(model)\"></span>\n <span\n v-if=\"modelDocumentCounts && modelDocumentCounts[model] !== undefined && model !== currentModel\"\n class=\"ml-auto text-xs text-gray-400 bg-muted rounded px-1.5 py-[1px]\"\n >\n {{formatCompactCount(modelDocumentCounts[model])}}\n </span>\n </router-link>\n </li>\n </ul>\n <div class=\"border-b border-edge my-2\"></div>\n </div>\n <!-- All Models / Search Results -->\n <div class=\"px-2 py-1 text-xs font-semibold text-gray-400 uppercase tracking-wider\">{{ modelSearch.trim() ? 'Search Results' : 'All Models' }}</div>\n <ul role=\"list\">\n <li v-for=\"model in filteredModels\" :key=\"'all-' + model\">\n <router-link\n :to=\"'/model/' + model\"\n class=\"flex items-center rounded-md py-1.5 px-2 text-sm text-content-secondary\"\n :class=\"model === currentModel ? 'bg-gray-200 font-semibold text-content' : 'hover:bg-muted'\">\n <span class=\"truncate\" v-html=\"highlightMatch(model)\"></span>\n <span\n v-if=\"modelDocumentCounts && modelDocumentCounts[model] !== undefined && model !== currentModel\"\n class=\"ml-auto text-xs text-gray-400 bg-muted rounded px-1.5 py-[1px]\"\n >\n {{formatCompactCount(modelDocumentCounts[model])}}\n </span>\n </router-link>\n </li>\n </ul>\n <div v-if=\"filteredModels.length === 0 && modelSearch.trim()\" class=\"px-2 py-2 text-sm text-content-tertiary\">\n No models match \"{{modelSearch}}\"\n </div>\n <div v-if=\"models.length === 0 && status === 'loaded'\" class=\"p-2 bg-red-100 rounded-md\">\n No models found\n </div>\n </nav>\n <!-- Bottom toolbar -->\n <div class=\"shrink-0 border-t border-edge bg-page px-2 py-1.5 flex items-center gap-1\">\n <button\n type=\"button\"\n @click=\"hideSidebar = true\"\n class=\"rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n title=\"Hide sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n @click=\"openModelSwitcher\"\n class=\"rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n title=\"Quick switch (Ctrl+P)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" />\n </svg>\n </button>\n </div>\n </aside>\n <div class=\"documents bg-slate-50 min-w-0\" ref=\"documentsList\">\n <div class=\"documents-menu bg-slate-50\">\n <div class=\"flex flex-row items-center w-full gap-2\">\n <button\n v-if=\"hideSidebar === true || hideSidebar === null\"\n type=\"button\"\n @click=\"hideSidebar = false\"\n class=\"shrink-0 rounded-md p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted\"\n :class=\"hideSidebar === null ? 'lg:hidden' : ''\"\n title=\"Show sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n <document-search\n ref=\"documentSearch\"\n :value=\"searchText\"\n :schema-paths=\"schemaPaths\"\n @search=\"search\"\n >\n </document-search>\n <div>\n <tooltip\n v-if=\"numDocumentsError\"\n :text=\"'Error counting documents: ' + numDocumentsError\"\n >\n <span\n class=\"inline-flex rounded-md bg-red-50 px-2 py-2 text-sm text-red-700 ring-1 ring-inset ring-red-200\"\n role=\"alert\"\n >\n Count Error\n </span>\n </tooltip>\n <span v-else-if=\"numDocuments == null\">Loading...</span>\n <span v-else-if=\"typeof numDocuments === 'number'\">{{documents.length}}/{{numDocuments === 1 ? numDocuments + ' document' : numDocuments + ' documents'}}</span>\n </div>\n <button\n @click=\"stagingSelect\"\n type=\"button\"\n :class=\"{\n 'bg-gray-700 ring-inset ring-2 ring-gray-300 text-white hover:bg-gray-600': selectMultiple,\n 'bg-primary hover:bg-primary-hover text-primary-text': !selectMultiple\n }\"\n class=\"rounded px-2 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {{ selectMultiple ? 'Cancel' : 'Select' }}\n </button>\n <button\n v-show=\"selectMultiple\"\n @click=\"shouldShowUpdateMultipleModal=true;\"\n type=\"button\"\n 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\"\n >\n Update\n </button>\n <button\n @click=\"shouldShowDeleteMultipleModal=true;\"\n type=\"button\"\n v-show=\"selectMultiple\"\n 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\"\n >\n Delete\n </button>\n <div class=\"relative\" v-show=\"!selectMultiple\" ref=\"actionsMenuContainer\" @keyup.esc.prevent=\"closeActionsMenu\">\n <button\n @click=\"toggleActionsMenu\"\n type=\"button\"\n aria-label=\"More actions\"\n class=\"rounded bg-surface px-2 py-2 text-sm font-semibold text-content-secondary shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-page focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Zm0 6a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z\" />\n </svg>\n </button>\n <div\n v-if=\"showActionsMenu\"\n class=\"absolute right-0 mt-2 w-48 origin-top-right rounded-md bg-surface shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-50\"\n >\n <div class=\"py-1\">\n <button\n @click=\"shouldShowExportModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Export\n </button>\n <button\n @click=\"shouldShowCreateModal = true; showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Create\n </button>\n <button\n @click=\"openIndexModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Indexes\n </button>\n <button\n @click=\"openAnalyzeSchemaModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Analyze Schema\n </button>\n <button\n @click=\"openCollectionInfo\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Collection Info\n </button>\n <button\n @click=\"toggleRowNumbers()\"\n :disabled=\"outputType !== 'table'\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm\"\n :class=\"outputType === 'table' ? 'text-content-secondary hover:bg-muted' : 'text-content-tertiary cursor-not-allowed opacity-50'\"\n >\n {{ showRowNumbers ? 'Hide row numbers' : 'Show row numbers' }}\n </button>\n <button\n @click=\"resetFilter()\"\n :disabled=\"searchText.trim().length === 0\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm\"\n :class=\"searchText.trim().length > 0 ? 'text-content-secondary hover:bg-muted' : 'text-content-tertiary cursor-not-allowed opacity-50'\"\n >\n Reset Filter\n </button>\n <button\n @click=\"toggleProjectionMenu(); showActionsMenu = false\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm hover:bg-muted\"\n :class=\"isProjectionMenuSelected ? 'text-primary font-semibold' : 'text-content-secondary'\"\n >\n {{ isProjectionMenuSelected ? 'Projection (On)' : 'Projection' }}\n </button>\n <button\n v-if=\"isProjectionMenuSelected\"\n @click=\"clearProjection()\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Reset Projection\n </button>\n <async-button\n v-if=\"isProjectionMenuSelected\"\n type=\"button\"\n @click=\"applyDefaultProjectionColumns()\"\n class=\"block w-full px-4 py-2 text-left text-sm text-content-secondary hover:bg-muted\"\n >\n Default Projection\n </async-button>\n <button\n @click=\"openDropCollectionModal\"\n type=\"button\"\n class=\"block w-full px-4 py-2 text-left text-sm text-red-700 hover:bg-red-50\"\n >\n Drop Collection\n </button>\n </div>\n </div>\n </div>\n <span class=\"isolate inline-flex rounded-md shadow-sm\">\n <button\n @click=\"setOutputType('table')\"\n type=\"button\"\n class=\"relative inline-flex items-center rounded-none rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-page focus:z-10\"\n :class=\"outputType === 'table' ? 'bg-gray-200' : 'bg-surface'\">\n <img class=\"h-5 w-5\" src=\"images/table.svg\">\n </button>\n <button\n @click=\"setOutputType('json')\"\n type=\"button\"\n class=\"relative -ml-px inline-flex items-center px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-page focus:z-10\"\n :class=\"outputType === 'json' ? 'bg-gray-200' : 'bg-surface'\">\n <img class=\"h-5 w-5\" src=\"images/json.svg\">\n </button>\n <button\n @click=\"setOutputType('map')\"\n :disabled=\"geoJsonFields.length === 0\"\n type=\"button\"\n :title=\"geoJsonFields.length > 0 ? 'Map view' : 'No GeoJSON fields detected'\"\n class=\"relative -ml-px inline-flex items-center rounded-none rounded-r-md px-2 py-2 ring-1 ring-inset ring-gray-300 focus:z-10\"\n :class=\"[\n geoJsonFields.length === 0 ? 'text-gray-300 cursor-not-allowed bg-muted' : 'text-gray-400 hover:bg-page',\n outputType === 'map' ? 'bg-gray-200' : (geoJsonFields.length > 0 ? 'bg-surface' : '')\n ]\">\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.503 3.498 4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 0 0-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0Z\" />\n </svg>\n </button>\n </span>\n </div>\n <div v-if=\"isProjectionMenuSelected && (outputType === 'table' || outputType === 'json')\" class=\"flex items-center gap-2 w-full mt-2 flex-shrink-0\">\n <projection-search\n ref=\"projectionSearch\"\n :value=\"projectionText\"\n :schema-paths=\"schemaPaths\"\n @projection-input=\"projectionText = $event\"\n @apply=\"applyProjectionFromInput\"\n />\n </div>\n </div>\n <!-- In JSON view, this container is the scrollable element used for infinite scroll. -->\n <div class=\"documents-container relative\" ref=\"documentsContainerScroll\" @scroll=\"checkIfScrolledToBottom\">\n <div v-if=\"error\">\n <div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 relative m-4 rounded-md\" role=\"alert\">\n <span class=\"block font-bold\">Error</span>\n <span class=\"block\">{{ error }}</span>\n <span class=\"block mt-2\">\n Need help?\n <a\n href=\"https://discord.gg/P3YCfKYxpy\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"underline font-medium text-red-800 hover:text-red-900\"\n >Ask in Discord</a>\n or\n <a\n href=\"https://github.com/mongoosejs/studio/issues\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"underline font-medium text-red-800 hover:text-red-900\"\n >\n open a GitHub issue.\n </a>\n </span>\n </div>\n </div>\n <div v-else-if=\"outputType === 'table'\" class=\"flex-1 min-h-0 flex flex-col overflow-hidden\">\n <div\n ref=\"documentsScrollContainer\"\n class=\"overflow-x-auto overflow-y-auto flex-1 min-h-0 border border-edge rounded-lg bg-surface\"\n @scroll=\"checkIfScrolledToBottom\"\n >\n <table class=\"min-w-full border-collapse text-sm\">\n <thead class=\"sticky top-0 z-10 bg-slate-100 dark:bg-shark-800 border-b border-edge\">\n <tr>\n <th v-if=\"showRowNumbers\" class=\"px-3 py-2.5 text-left font-medium text-content border-r border-edge whitespace-nowrap align-middle w-0\">\n #\n </th>\n <th\n v-for=\"path in tableDisplayPaths\"\n :key=\"path.path\"\n class=\"px-3 py-2.5 text-left font-medium text-content border-r border-edge last:border-r-0 whitespace-nowrap align-middle\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n @click=\"addPathFilter(path.path)\"\n class=\"cursor-pointer hover:text-primary truncate min-w-0\"\n :title=\"path.path\"\n >\n {{ path.path }}\n </span>\n <span class=\"text-xs text-content-tertiary shrink-0\">({{ path.instance || 'unknown' }})</span>\n <span class=\"inline-flex shrink-0 gap-0.5 items-center\">\n <button\n type=\"button\"\n @click.stop=\"sortDocs(1, path.path)\"\n class=\"p-0.5 rounded text-content-tertiary hover:text-content hover:bg-muted\"\n :class=\"{ 'text-primary font-semibold': sortBy[path.path] === 1 }\"\n :title=\"sortBy[path.path] === 1 ? 'Clear sort' : 'Sort ascending'\"\n >\n ↑\n </button>\n <button\n type=\"button\"\n @click.stop=\"sortDocs(-1, path.path)\"\n class=\"p-0.5 rounded text-content-tertiary hover:text-content hover:bg-muted\"\n :class=\"{ 'text-primary font-semibold': sortBy[path.path] === -1 }\"\n :title=\"sortBy[path.path] === -1 ? 'Clear sort' : 'Sort descending'\"\n >\n ↓\n </button>\n <button\n v-if=\"filteredPaths.length > 0\"\n type=\"button\"\n @click.stop=\"removeField(path)\"\n class=\"p-1.5 rounded-md border border-transparent text-content-tertiary hover:text-valencia-600 hover:bg-valencia-50 hover:border-valencia-200 focus:outline-none focus:ring-2 focus:ring-valencia-500/30\"\n title=\"Remove column\"\n aria-label=\"Remove column\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n </button>\n </span>\n </div>\n </th>\n <th v-if=\"filteredPaths.length > 0\" class=\"px-2 py-2.5 border-r border-edge last:border-r-0 align-middle w-0 bg-slate-50 dark:bg-shark-800/80\">\n <div class=\"relative\" ref=\"addFieldContainer\">\n <button\n type=\"button\"\n @click=\"toggleAddFieldDropdown()\"\n class=\"flex items-center justify-center w-8 h-8 rounded border border-dashed border-edge text-content-tertiary hover:border-primary hover:text-primary hover:bg-primary-subtle/30\"\n title=\"Add column\"\n aria-label=\"Add column\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\" class=\"w-5 h-5\"> <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" /> </svg>\n </button>\n <div\n v-if=\"showAddFieldDropdown\"\n class=\"absolute right-0 top-full mt-1 z-[100] min-w-[180px] max-w-[280px] rounded-md border border-edge bg-surface shadow-lg py-1 max-h-48 overflow-y-auto\"\n >\n <input\n v-if=\"availablePathsToAdd.length > 5\"\n ref=\"addFieldFilterInput\"\n v-model=\"addFieldFilterText\"\n type=\"text\"\n placeholder=\"Filter fields...\"\n class=\"mx-2 mb-1 w-[calc(100%-1rem)] rounded border border-edge px-2 py-1 text-sm\"\n @click.stop\n />\n <button\n v-for=\"p in filteredPathsToAdd\"\n :key=\"p.path\"\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left text-sm hover:bg-muted\"\n @click.stop=\"addField(p)\"\n >\n {{ p.path }}\n </button>\n <p v-if=\"filteredPathsToAdd.length === 0\" class=\"px-3 py-2 text-sm text-content-tertiary\">\n {{ addFieldFilterText.trim() ? 'No matching fields' : 'All fields added' }}\n </p>\n </div>\n </div>\n </th>\n </tr>\n </thead>\n <tbody class=\"bg-surface\">\n <tr\n v-for=\"(document, docIndex) in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentClick(document, $event)\"\n class=\"border-b border-edge cursor-pointer transition-colors\"\n :class=\"selectedDocuments.some(x => x._id.toString() === document._id.toString())\n ? 'bg-blue-200'\n : 'hover:bg-muted'\"\n >\n <td v-if=\"showRowNumbers\" class=\"px-3 py-2 border-r border-edge align-top text-content-tertiary whitespace-nowrap\">\n {{ docIndex + 1 }}\n </td>\n <td\n v-for=\"schemaPath in tableDisplayPaths\"\n :key=\"schemaPath.path\"\n class=\"px-3 py-2 border-r border-edge last:border-r-0 align-top max-w-[280px]\"\n >\n <div class=\"table-cell-content flex items-center gap-1.5 min-w-0 group\">\n <span class=\"min-w-0 overflow-hidden text-ellipsis flex-1\">\n <component\n :is=\"getComponentForPath(schemaPath)\"\n :value=\"getValueForPath(document, schemaPath.path)\"\n :allude=\"getReferenceModel(schemaPath)\"\n />\n </span>\n <button\n type=\"button\"\n class=\"table-cell-copy shrink-0 p-1 rounded text-content-tertiary hover:text-content hover:bg-muted focus:outline-none focus:ring-1 focus:ring-edge\"\n aria-label=\"Copy cell value\"\n @click.stop=\"copyCellValue(getValueForPath(document, schemaPath.path))\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1M8 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M8 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m0 0h2a2 2 0 0 1 2 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n </div>\n </td>\n <td v-if=\"filteredPaths.length > 0\" class=\"w-0 px-0 py-0 border-r border-edge last:border-r-0 bg-slate-50/50 dark:bg-shark-800/30\"></td>\n </tr>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"outputType === 'table' && (documentsError || loadingMore || (status === 'loading' && documents.length > 0))\"\n class=\"flex items-center justify-center gap-2 py-3 text-sm border-t\"\n :class=\"documentsError ? 'border-red-200 bg-red-50 text-red-700' : 'border-edge bg-surface text-content-tertiary'\"\n :role=\"documentsError ? 'alert' : null\"\n >\n <img v-if=\"!documentsError\" src=\"images/loader.gif\" alt=\"\" class=\"h-5 w-5\">\n <span>{{documentsError || 'Loading documents…'}}</span>\n </div>\n <p v-if=\"outputType === 'table' && documents.length === 0 && status === 'loaded' && !documentsError\" class=\"mt-2 text-sm text-content-tertiary px-1\">\n No documents to show. Use Projection in the menu to choose columns.\n </p>\n </div>\n <div v-else-if=\"outputType === 'json'\" class=\"flex min-w-0 flex-col space-y-2 p-1 mt-1\">\n <div\n v-for=\"document in documents\"\n :key=\"document._id\"\n @click=\"handleDocumentContainerClick(document, $event)\"\n :class=\"[\n 'group relative min-w-0 max-w-full transition-colors rounded-md border border-slate-100',\n selectedDocuments.some(x => x._id.toString() === document._id.toString()) ? 'bg-blue-200' : 'hover:shadow-sm hover:border-slate-300 bg-surface'\n ]\"\n >\n <router-link\n class=\"absolute top-2 right-2 z-10 inline-flex items-center rounded bg-primary px-2 py-1 text-xs font-semibold text-primary-text shadow-sm transition-opacity duration-150 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n :to=\"{ path: '/model/' + currentModel + '/document/' + document._id, query: $route.query }\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n @click.stop\n >\n Open\n </router-link>\n <list-json :value=\"filterDocument(document)\" :references=\"referenceMap\">\n </list-json>\n </div>\n <div\n v-if=\"outputType === 'json' && (documentsError || loadingMore || (status === 'loading' && documents.length > 0))\"\n class=\"flex items-center justify-center gap-2 py-3 text-sm\"\n :class=\"documentsError ? 'rounded-md border border-red-200 bg-red-50 text-red-700' : 'text-content-tertiary'\"\n :role=\"documentsError ? 'alert' : null\"\n >\n <img v-if=\"!documentsError\" src=\"images/loader.gif\" alt=\"\" class=\"h-5 w-5\">\n <span>{{documentsError || 'Loading documents…'}}</span>\n </div>\n </div>\n <div v-else-if=\"outputType === 'map'\" class=\"flex flex-col h-full\">\n <div class=\"p-2 bg-surface border-b flex items-center gap-2\">\n <label class=\"text-sm font-medium text-content-secondary\">GeoJSON Field:</label>\n <select\n :value=\"selectedGeoField\"\n @change=\"setSelectedGeoField($event.target.value)\"\n class=\"rounded-md border border-edge-strong py-1 px-2 text-sm focus:border-primary focus:ring-primary\"\n >\n <option v-for=\"field in geoJsonFields\" :key=\"field.path\" :value=\"field.path\">\n {{ field.label }}\n </option>\n </select>\n <async-button\n @click=\"loadMoreDocuments\"\n :disabled=\"loadedAllDocs\"\n type=\"button\"\n class=\"rounded px-2 py-1 text-xs font-semibold text-primary-text shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n :class=\"loadedAllDocs ? 'bg-gray-400 cursor-not-allowed' : 'bg-primary hover:bg-primary-hover'\"\n >\n Load more\n </async-button>\n </div>\n <div class=\"flex-1 min-h-[400px]\" ref=\"modelsMap\"></div>\n </div>\n <div v-if=\"status === 'loading' && !loadingMore && documents.length === 0\" class=\"loader loader-overlay\" aria-busy=\"true\">\n <img src=\"images/loader.gif\" alt=\"Loading\">\n </div>\n </div>\n </div>\n <modal v-if=\"shouldShowExportModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowExportModal = false\">×</div>\n <export-query-results\n :schemaPaths=\"schemaPaths\"\n :search-text=\"searchText\"\n :currentModel=\"currentModel\"\n @done=\"shouldShowExportModal = false\">\n </export-query-results>\n </template>\n </modal>\n <modal v-if=\"shouldShowIndexModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowIndexModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Indexes</div>\n <div v-for=\"index in mongoDBIndexes\" class=\"w-full flex items-center\">\n <div class=\"grow shrink text-left flex justify-between items-center\" v-if=\"index.name != '_id_'\">\n <div>\n <div class=\"font-bold flex items-center gap-2\">\n <div>{{ index.name }}</div>\n <div v-if=\"isTTLIndex(index)\" class=\"rounded-full bg-primary-subtle px-2 py-0.5 text-xs font-semibold text-primary\">\n TTL: {{ formatTTL(index.expireAfterSeconds) }}\n </div>\n </div>\n <div class=\"text-sm font-mono\">{{ JSON.stringify(index.key) }}</div>\n </div>\n <div>\n <async-button\n type=\"button\"\n @click=\"dropIndex(index.name)\"\n class=\"rounded-md bg-valencia-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-valencia-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed\">\n Drop\n </async-button>\n </div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowAnalyzeSchemaModal\" containerClass=\"md:!w-[70vw]\">\n <template v-slot:body>\n <analyze-schema-modal\n :current-model=\"currentModel\"\n @close=\"shouldShowAnalyzeSchemaModal = false\"\n ></analyze-schema-modal>\n </template>\n </modal>\n <modal v-if=\"shouldShowCollectionInfoModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCollectionInfoModal = false\">×</div>\n <div class=\"text-xl font-bold mb-2\">Collection Info</div>\n <div v-if=\"!collectionInfo\" class=\"text-gray-600\">Loading collection details...</div>\n <div v-else class=\"space-y-3\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Documents</div>\n <div class=\"text-content\">{{ formatNumber(collectionInfo.documentCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Indexes</div>\n <div class=\"text-content\">{{ formatNumber(collectionInfo.indexCount) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Total Index Size</div>\n <div class=\"text-content\">{{ formatCollectionSize(collectionInfo.totalIndexSize) }}</div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Total Storage Size</div>\n <div class=\"text-content\">{{ formatCollectionSize(collectionInfo.size) }}</div>\n </div>\n <div class=\"flex flex-col gap-1\">\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Collation</div>\n <div class=\"text-content\">{{ collectionInfo.hasCollation ? 'Yes' : 'No' }}</div>\n </div>\n <div v-if=\"collectionInfo.hasCollation\" class=\"rounded bg-muted p-3 text-sm text-gray-800 overflow-x-auto\">\n <pre class=\"whitespace-pre-wrap\">{{ JSON.stringify(collectionInfo.collation, null, 2) }}</pre>\n </div>\n </div>\n <div class=\"flex justify-between gap-4\">\n <div class=\"font-semibold text-content-secondary\">Capped</div>\n <div class=\"text-content\">{{ collectionInfo.capped ? 'Yes' : 'No' }}</div>\n </div>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowCreateModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowCreateModal = false;\">×</div>\n <create-document :currentModel=\"currentModel\" :paths=\"schemaPaths\" @close=\"closeCreationModal\"></create-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowUpdateMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowUpdateMultipleModal = false;\">×</div>\n <update-document :currentModel=\"currentModel\" :document=\"selectedDocuments\" :multiple=\"true\" @update=\"updateDocuments\" @close=\"shouldShowUpdateMultipleModal=false;\"></update-document>\n </template>\n </modal>\n <modal v-if=\"shouldShowDeleteMultipleModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDeleteMultipleModal = false;\">×</div>\n <h2>Are you sure you want to delete {{selectedDocuments.length}} documents?</h2>\n <div>\n <list-json :value=\"selectedDocuments\"></list-json>\n </div>\n <div class=\"flex gap-4\">\n <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\">\n Confirm\n </async-button>\n <button @click=\"shouldShowDeleteMultipleModal = false;\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-page0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n <modal v-if=\"shouldShowDropCollectionModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"shouldShowDropCollectionModal = false\">×</div>\n <h2 class=\"text-xl font-bold mb-3\">Are you sure?</h2>\n <p class=\"text-content-secondary mb-3\">\n This will permanently drop the <span class=\"font-semibold\">{{ currentModel }}</span> collection and all its documents.\n </p>\n <div v-if=\"requiresDropCollectionNameConfirmation()\" class=\"rounded border border-red-300 bg-red-50 px-3 py-2 mb-4\">\n <p class=\"text-sm font-semibold text-red-700\">Danger zone</p>\n <p class=\"text-sm text-red-700 mb-2\">Type <span class=\"font-mono font-semibold\">{{ currentModel }}</span> to confirm.</p>\n <input\n v-model=\"dropCollectionConfirmName\"\n type=\"text\"\n :placeholder=\"currentModel\"\n class=\"w-full rounded border border-red-300 px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-red-200\"\n />\n </div>\n <div class=\"flex gap-4\">\n <async-button\n @click=\"dropCollection\"\n :disabled=\"requiresDropCollectionNameConfirmation() && dropCollectionConfirmName !== currentModel\"\n class=\"rounded bg-red-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Drop Collection\n </async-button>\n <button @click=\"shouldShowDropCollectionModal = false\" class=\"rounded bg-gray-400 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-page0\">\n Cancel\n </button>\n </div>\n </template>\n </modal>\n <model-switcher\n :show=\"showModelSwitcher\"\n :models=\"models\"\n :recently-viewed-models=\"recentlyViewedModels\"\n :model-document-counts=\"modelDocumentCounts\"\n @close=\"showModelSwitcher = false\"\n @select=\"selectSwitcherModel\"\n ></model-switcher>\n</div>\n";
|
|
54394
55002
|
|
|
54395
55003
|
/***/ },
|
|
54396
55004
|
|
|
@@ -54423,7 +55031,7 @@ module.exports = ".active {\n text-decoration: underline;\n}\n\n.navbar .nav-le
|
|
|
54423
55031
|
(module) {
|
|
54424
55032
|
|
|
54425
55033
|
"use strict";
|
|
54426
|
-
module.exports = "<div>\n<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\">\n <!-- Left: Logo + Brand -->\n <div class=\"flex items-center gap-2 self-center\">\n <router-link class=\"flex items-center gap-2\" :to=\"{ name: defaultRoute }\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-10 text-primary\" viewBox=\"0 0 250 250\" fill=\"currentColor\" aria-label=\"Mongoose Studio Logo\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n <span class=\"text-base font-semibold text-content whitespace-nowrap\">Mongoose Studio</span>\n </router-link>\n </div>\n <!-- Center: Nav Links -->\n <nav class=\"flex items-stretch gap-6\">\n <a v-if=\"hasAccess(roles, 'root')\"\n href=\"#/\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"documentView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Documents</a>\n <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\" aria-disabled=\"true\">\n Documents\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'dashboards')\"\n href=\"#/dashboards\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"dashboardView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Dashboards</a>\n <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\">\n Dashboards\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'chat') && supportsAI\"\n href=\"#/chat\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"chatView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Chat</a>\n <span v-else-if=\"hasAccess(roles, 'chat') && !supportsAI\"\n class=\"inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-gray-300 cursor-not-allowed\"\n :title=\"chatDisabledReason\">\n Chat\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <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\">\n Chat\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a\n v-if=\"hasTaskVisualizer\"\n href=\"#/tasks\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"taskView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">\n Tasks\n </a>\n <a\n href=\"https://studio.mongoosejs.io/docs\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-content-tertiary hover:text-content\"\n >\n Docs\n </a>\n </nav>\n <!-- Right: Env Badge + User -->\n <div class=\"flex items-center justify-end gap-3 self-center\">\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary\"\n title=\"Recent pages\"\n aria-label=\"Recent pages\"\n aria-haspopup=\"dialog\"\n :aria-expanded=\"showRecentPagesModal ? 'true' : 'false'\"\n @click=\"openRecentPagesModal\"\n >\n <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\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </button>\n <div\n v-if=\"!!state.nodeEnv\"\n title=\"NODE_ENV\"\n class=\"inline-flex items-center rounded px-2 py-1 text-xs text-content-tertiary bg-surface border border-edge gap-2\"\n >\n <span\n :class=\"warnEnv ? 'bg-red-400' : 'bg-yellow-400'\"\n class=\"inline-block rounded-full\"\n style=\"width: 0.5em; height: 0.5em;\"\n ></span>\n <span>{{state.nodeEnv}}</span>\n </div>\n <button\n v-if=\"!user || !hasAPIKey\"\n type=\"button\"\n @click=\"toggleDarkMode\"\n :title=\"darkMode ? 'Switch to light mode' : 'Switch to dark mode'\"\n class=\"inline-flex items-center justify-center rounded-md p-2 text-content-tertiary hover:text-content-secondary hover:bg-muted\"\n aria-label=\"Toggle dark mode\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/>\n </svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/>\n </svg>\n </button>\n <div class=\"flex items-center\" v-if=\"!user && hasAPIKey\">\n <button\n type=\"button\"\n @click=\"loginWithGithub\"\n class=\"rounded bg-primary px-2 py-2 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-primary\">\n Login\n </button>\n </div>\n <div v-if=\"user && hasAPIKey\" class=\"flex items-center relative\" v-clickOutside=\"hideFlyout\">\n <button type=\"button\" @click=\"showFlyout = !showFlyout\" class=\"relative flex rounded-full text-sm focus:outline-none focus:ring-2 focus:ring-gray-300\" id=\"user-menu-button\" aria-expanded=\"false\" aria-haspopup=\"true\">\n <span class=\"absolute -inset-1.5\"></span>\n <span class=\"sr-only\">Open user menu</span>\n <img class=\"size-8 rounded-full\" :src=\"user.picture\" alt=\"\">\n </button>\n\n <div\n v-if=\"showFlyout\"\n class=\"absolute right-0 top-[90%] w-48 origin-top-right rounded-md bg-surface py-1 shadow-lg ring-1 ring-black/5 focus:outline-none\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-labelledby=\"user-menu-button\"\n style=\"z-index: 10000\"\n tabindex=\"-1\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode(); showFlyout = false\"\n class=\"w-full cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle text-left flex items-center gap-2\"\n role=\"menuitem\"\n tabindex=\"-1\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n {{ darkMode ? 'Light mode' : 'Dark mode' }}\n </button>\n <router-link to=\"/team\" v-if=\"hasAccess(roles, 'team')\" @click=\"showFlyout = false\" class=\"cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Team</router-link>\n <span v-else class=\"block px-4 py-2 text-sm text-gray-300 cursor-not-allowed\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">\n Team\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <span @click=\"logout\" class=\"cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Sign out</span>\n </div>\n </div>\n </div>\n</div>\n<!-- Mobile navbar -->\n<div class=\"navbar w-full bg-page flex justify-between border-b border-edge !h-[55px] md:hidden\">\n <div class=\"flex items-center gap-2 pl-4\">\n <router-link class=\"flex items-center gap-2\" :to=\"{ name: defaultRoute }\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-8 text-primary\" viewBox=\"0 0 250 250\" fill=\"currentColor\" aria-label=\"Mongoose Studio Logo\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n <span class=\"text-base font-semibold text-content\">Mongoose Studio</span>\n </router-link>\n </div>\n <div class=\"flex items-center gap-1 pr-2\">\n <button\n type=\"button\"\n class=\"rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary md:hidden\"\n title=\"Recent pages\"\n aria-label=\"Recent pages\"\n aria-haspopup=\"dialog\"\n :aria-expanded=\"showRecentPagesModal ? 'true' : 'false'\"\n @click=\"openRecentPagesModal\"\n >\n <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\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </button>\n <!-- Mobile menu toggle, controls the 'mobileMenuOpen' state. -->\n <button type=\"button\" id=\"open-mobile-menu\" class=\"-ml-2 rounded-md p-2 text-gray-400\">\n <span class=\"sr-only\">Open menu</span>\n <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5\" />\n </svg>\n </button>\n </div>\n\n <!-- Mobile menu mask -->\n <div id=\"mobile-menu-mask\" class=\"fixed inset-0 bg-black bg-opacity-40 z-40 hidden\"></div>\n <!-- Mobile menu drawer -->\n <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\">\n <div class=\"flex items-center justify-between px-4 !h-[55px] border-b border-edge\">\n <router-link :to=\"{ name: defaultRoute }\">\n <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\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n </router-link>\n <button type=\"button\" id=\"close-mobile-menu\" class=\"text-gray-400 p-2 rounded-md\">\n <span class=\"sr-only\">Close menu</span>\n <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <nav class=\"flex-1 px-4 py-4 space-y-2\">\n <div class=\"flex items-center gap-2 px-3 py-2\" v-if=\"!user || !hasAPIKey\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode\"\n class=\"inline-flex items-center gap-2 rounded-md px-3 py-2 text-base font-medium text-content-secondary hover:bg-muted\"\n aria-label=\"Toggle dark mode\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n <span>{{ darkMode ? 'Light mode' : 'Dark mode' }}</span>\n </button>\n </div>\n <a v-if=\"hasAccess(roles, 'root')\"\n href=\"#/\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"documentView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Documents</a>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Documents\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'dashboards')\"\n href=\"#/dashboards\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"dashboardView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Dashboards</a>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Dashboards\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'chat') && supportsAI\"\n href=\"#/chat\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"chatView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Chat</a>\n <span v-else-if=\"hasAccess(roles, 'chat') && !supportsAI\"\n class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\"\n :title=\"chatDisabledReason\">\n Chat\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Chat\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasTaskVisualizer\"\n href=\"#/tasks\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"taskView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Tasks</a>\n <div v-if=\"!user && hasAPIKey\" class=\"mt-4\">\n <button\n type=\"button\"\n @click=\"loginWithGithub\"\n class=\"w-full rounded bg-muted text-content px-3 py-2 text-base font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\">\n Login\n </button>\n </div>\n <div v-if=\"user && hasAPIKey\" class=\"mt-4\">\n <div class=\"flex items-center gap-3 px-3 py-2 bg-page rounded-md\">\n <img class=\"size-8 rounded-full\" :src=\"user.picture\" alt=\"\">\n <span class=\"text-content font-medium\">{{ user.name }}</span>\n </div>\n <div class=\"mt-2 space-y-1\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode\"\n class=\"w-full inline-flex items-center gap-2 px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle text-left\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n {{ darkMode ? 'Light mode' : 'Dark mode' }}\n </button>\n <router-link to=\"/team\" v-if=\"hasAccess(roles, 'team')\" class=\"block px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle\">Team</router-link>\n <span v-else class=\"block px-3 py-2 rounded-md text-base text-gray-300 cursor-not-allowed\">\n Team\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <span @click=\"logout\" class=\"block px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle cursor-pointer\">Sign out</span>\n </div>\n </div>\n </nav>\n </div>\n</div>\n\n<modal\n v-if=\"showRecentPagesModal\"\n flush-container\n 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\"\n bodyClass=\"modal-recent-pages-body !p-0\"\n>\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"closeRecentPagesModal\" role=\"button\" aria-label=\"Close recent pages\">×</div>\n <div\n class=\"shrink-0 flex items-center gap-3 border-b border-edge bg-surface px-4 py-4 pr-12 dark:bg-shark-900\"\n >\n <h2 class=\"m-0 text-lg font-semibold text-content\">Recent pages</h2>\n <button\n type=\"button\"\n class=\"rounded px-2 py-1 text-sm font-medium text-content-secondary hover:bg-muted disabled:opacity-50\"\n @click=\"clearRecentPagesHistory\"\n :disabled=\"recentPagesList.length === 0\"\n >\n Clear\n </button>\n </div>\n <div class=\"modal-recent-pages-scroll\">\n <div\n v-if=\"recentPagesList.length === 0\"\n class=\"m-4 rounded border border-dashed border-edge px-3 py-6 text-center text-sm text-content-tertiary\"\n >\n No recent pages yet.\n </div>\n <button\n v-for=\"entry in recentPagesList\"\n :key=\"entry.path + '-' + entry.visitedAt\"\n type=\"button\"\n class=\"w-full px-4 py-2.5 text-left hover:bg-muted\"\n :class=\"entry.path === $route.fullPath ? 'bg-primary-subtle' : ''\"\n @click=\"goToRecentPage(entry)\"\n >\n <div class=\"truncate text-sm font-medium text-content\">{{ entry.label }}</div>\n <div class=\"truncate font-mono text-xs text-content-tertiary\">{{ entry.path }}</div>\n </button>\n </div>\n </template>\n</modal>\n</div>\n";
|
|
55034
|
+
module.exports = "<div>\n<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\">\n <!-- Left: Logo + Brand -->\n <div class=\"flex items-center gap-2 self-center\">\n <router-link class=\"flex items-center gap-2\" :to=\"{ name: defaultRoute }\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-10 text-primary\" viewBox=\"0 0 250 250\" fill=\"currentColor\" aria-label=\"Mongoose Studio Logo\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n <span class=\"text-base font-semibold text-content whitespace-nowrap\">Mongoose Studio</span>\n </router-link>\n </div>\n <!-- Center: Nav Links -->\n <nav class=\"flex items-stretch gap-6\">\n <a v-if=\"hasAccess(roles, 'root')\"\n href=\"#/\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"documentView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Documents</a>\n <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\" aria-disabled=\"true\">\n Documents\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'dashboards')\"\n href=\"#/dashboards\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"dashboardView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Dashboards</a>\n <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\">\n Dashboards\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'chat') && supportsAI\"\n href=\"#/chat\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"chatView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">Chat</a>\n <span v-else-if=\"hasAccess(roles, 'chat') && !supportsAI\"\n class=\"inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-gray-300 cursor-not-allowed\"\n :title=\"chatDisabledReason\">\n Chat\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <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\">\n Chat\n <svg class=\"h-4 w-4 ml-1\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a\n v-if=\"hasTaskVisualizer\"\n href=\"#/tasks\"\n class=\"inline-flex items-center px-1 border-b-2 text-sm font-medium\"\n :class=\"taskView ? 'text-content border-primary' : 'border-transparent text-content-tertiary hover:text-content'\">\n Tasks\n </a>\n <a\n href=\"https://studio.mongoosejs.io/docs\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"inline-flex items-center px-1 border-b-2 border-transparent text-sm font-medium text-content-tertiary hover:text-content\"\n >\n Docs\n </a>\n </nav>\n <!-- Right: Env Badge + User -->\n <div class=\"flex items-center justify-end gap-3 self-center\">\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary\"\n title=\"Recent pages\"\n aria-label=\"Recent pages\"\n aria-haspopup=\"dialog\"\n :aria-expanded=\"showRecentPagesModal ? 'true' : 'false'\"\n @click=\"openRecentPagesModal\"\n >\n <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\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </button>\n <div\n v-if=\"!!state.nodeEnv\"\n title=\"NODE_ENV\"\n class=\"inline-flex items-center rounded px-2 py-1 text-xs text-content-tertiary bg-surface border border-edge gap-2\"\n >\n <span\n :class=\"warnEnv ? 'bg-red-400' : 'bg-yellow-400'\"\n class=\"inline-block rounded-full\"\n style=\"width: 0.5em; height: 0.5em;\"\n ></span>\n <span>{{state.nodeEnv}}</span>\n </div>\n <button\n v-if=\"!user || !hasAPIKey\"\n type=\"button\"\n @click=\"toggleDarkMode\"\n :title=\"darkMode ? 'Switch to light mode' : 'Switch to dark mode'\"\n class=\"inline-flex items-center justify-center rounded-md p-2 text-content-tertiary hover:text-content-secondary hover:bg-muted\"\n aria-label=\"Toggle dark mode\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/>\n </svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/>\n </svg>\n </button>\n <div class=\"flex items-center\" v-if=\"!user && hasAPIKey\">\n <button\n type=\"button\"\n @click=\"loginWithGithub\"\n class=\"rounded bg-primary px-2 py-2 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-primary\">\n Login\n </button>\n </div>\n <div v-if=\"user && hasAPIKey\" class=\"flex items-center relative\" v-clickOutside=\"hideFlyout\">\n <button type=\"button\" @click=\"showFlyout = !showFlyout\" class=\"relative flex rounded-full text-sm focus:outline-none focus:ring-2 focus:ring-gray-300\" id=\"user-menu-button\" aria-expanded=\"false\" aria-haspopup=\"true\">\n <span class=\"absolute -inset-1.5\"></span>\n <span class=\"sr-only\">Open user menu</span>\n <img class=\"size-8 rounded-full\" :src=\"user.picture\" alt=\"\">\n </button>\n\n <div\n v-if=\"showFlyout\"\n class=\"absolute right-0 top-[90%] w-48 origin-top-right rounded-md bg-surface py-1 shadow-lg ring-1 ring-black/5 focus:outline-none\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-labelledby=\"user-menu-button\"\n style=\"z-index: 10000\"\n tabindex=\"-1\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode(); showFlyout = false\"\n class=\"w-full cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle text-left flex items-center gap-2\"\n role=\"menuitem\"\n tabindex=\"-1\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n {{ darkMode ? 'Light mode' : 'Dark mode' }}\n </button>\n <router-link to=\"/team\" v-if=\"hasAccess(roles, 'team')\" @click=\"showFlyout = false\" class=\"cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Team</router-link>\n <span v-else class=\"block px-4 py-2 text-sm text-gray-300 cursor-not-allowed\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">\n Team\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <router-link v-if=\"mcpEnabled\" to=\"/mcp\" @click=\"showFlyout = false\" class=\"cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle\" role=\"menuitem\" tabindex=\"-1\">MCP</router-link>\n <span v-else class=\"block px-4 py-2 text-sm text-gray-300 cursor-not-allowed\" role=\"menuitem\" title=\"MCP is disabled for this deployment\">\n MCP\n </span>\n <span @click=\"logout\" class=\"cursor-pointer block px-4 py-2 text-sm text-content-secondary hover:bg-primary-subtle\" role=\"menuitem\" tabindex=\"-1\" id=\"user-menu-item-2\">Sign out</span>\n </div>\n </div>\n </div>\n</div>\n<!-- Mobile navbar -->\n<div class=\"navbar w-full bg-page flex justify-between border-b border-edge !h-[55px] md:hidden\">\n <div class=\"flex items-center gap-2 pl-4\">\n <router-link class=\"flex items-center gap-2\" :to=\"{ name: defaultRoute }\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-8 text-primary\" viewBox=\"0 0 250 250\" fill=\"currentColor\" aria-label=\"Mongoose Studio Logo\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n <span class=\"text-base font-semibold text-content\">Mongoose Studio</span>\n </router-link>\n </div>\n <div class=\"flex items-center gap-1 pr-2\">\n <button\n type=\"button\"\n class=\"rounded-md p-2 text-content-tertiary hover:bg-muted hover:text-content-secondary md:hidden\"\n title=\"Recent pages\"\n aria-label=\"Recent pages\"\n aria-haspopup=\"dialog\"\n :aria-expanded=\"showRecentPagesModal ? 'true' : 'false'\"\n @click=\"openRecentPagesModal\"\n >\n <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\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </button>\n <!-- Mobile menu toggle, controls the 'mobileMenuOpen' state. -->\n <button type=\"button\" id=\"open-mobile-menu\" class=\"-ml-2 rounded-md p-2 text-gray-400\">\n <span class=\"sr-only\">Open menu</span>\n <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5\" />\n </svg>\n </button>\n </div>\n\n <!-- Mobile menu mask -->\n <div id=\"mobile-menu-mask\" class=\"fixed inset-0 bg-black bg-opacity-40 z-40 hidden\"></div>\n <!-- Mobile menu drawer -->\n <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\">\n <div class=\"flex items-center justify-between px-4 !h-[55px] border-b border-edge\">\n <router-link :to=\"{ name: defaultRoute }\">\n <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\">\n <path d=\"M 241.66,125.01 C 237.81,112.98 227.41,111.95 216.76,110.36 C 215.12,95.83 210.99,83.09 202.29,70.33 C 202.99,68.37 201.92,66.65 200.74,65.11 C 183.14,41.46 157.52,27 124.66,27 C 92.62,27 66.09,40.77 48.28,63.38 C 46.21,65.85 46.26,67.71 47.12,69.36 C 37.81,81.15 33.21,93.78 30.99,109.86 C 20.19,110.58 11.71,115.92 9.04,124.94 C 3.28,145.66 5.62,157.95 10.01,169.16 C 16.14,184.65 29.12,186.31 36.04,185.81 C 42.48,185.68 44.94,184.31 44.72,182.11 C 44.26,177.79 41.01,165.31 41.01,149.12 C 41.01,138.22 43.19,127.74 46.21,117.7 C 47.51,113.33 44.66,112.05 39.16,110.28 C 41.01,96.88 45.88,84.85 52.61,73.79 C 55.17,75.56 58.07,74.88 59.61,72.71 C 75.86,54.31 97.89,45.16 124.61,45.16 C 149.71,45.16 171.91,55.91 189.29,73.47 C 191.95,76.59 193.91,76.67 197.6,74.42 C 204.93,86.26 208.28,98.24 208.98,110.39 C 203.84,111.81 201.28,113.19 202.92,118.61 C 206.51,128.99 207.92,137.93 207.92,148.73 C 207.92,162.11 204.8,174.71 202.84,182.71 C 201.92,186.23 204.31,186.91 210.79,186.99 H 213.91 C 225.87,186.61 235.39,180.64 239.49,169.05 C 244.83,155.26 245.08,138.01 241.66,125.01 Z\"/>\n <path d=\"M 124.71,70.81 C 79.63,70.81 47.49,107.12 47.49,148.72 C 47.49,169.16 56.41,188.19 73.71,200.61 L 73.96,200.77 C 77.43,177.81 84.16,162.21 95.29,145.42 C 92.04,137.09 91.71,130.87 92.62,120.83 C 93.81,111.23 96.08,107.12 102.19,107.68 C 110.04,108.87 117.98,116.18 126.22,124.96 C 139.89,124.05 157.81,131.25 178.33,139.09 C 183.11,140.86 183.72,142.63 182.97,148.33 C 179.45,160.93 170.86,166.63 158.11,174.05 C 143.09,183.07 141.13,199.42 153.88,220.09 L 153.96,221.01 L 154.71,221.17 C 181.31,208.43 201.34,181.01 201.34,148.72 C 201.34,108.15 169.29,70.81 124.71,70.81 Z\"/>\n </svg>\n </router-link>\n <button type=\"button\" id=\"close-mobile-menu\" class=\"text-gray-400 p-2 rounded-md\">\n <span class=\"sr-only\">Close menu</span>\n <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <nav class=\"flex-1 px-4 py-4 space-y-2\">\n <div class=\"flex items-center gap-2 px-3 py-2\" v-if=\"!user || !hasAPIKey\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode\"\n class=\"inline-flex items-center gap-2 rounded-md px-3 py-2 text-base font-medium text-content-secondary hover:bg-muted\"\n aria-label=\"Toggle dark mode\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n <span>{{ darkMode ? 'Light mode' : 'Dark mode' }}</span>\n </button>\n </div>\n <a v-if=\"hasAccess(roles, 'root')\"\n href=\"#/\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"documentView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Documents</a>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Documents\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'dashboards')\"\n href=\"#/dashboards\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"dashboardView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Dashboards</a>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Dashboards\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasAccess(roles, 'chat') && supportsAI\"\n href=\"#/chat\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"chatView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Chat</a>\n <span v-else-if=\"hasAccess(roles, 'chat') && !supportsAI\"\n class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\"\n :title=\"chatDisabledReason\">\n Chat\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <span v-else class=\"block px-3 py-2 rounded-md text-base font-medium text-gray-300 cursor-not-allowed\">\n Chat\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <a v-if=\"hasTaskVisualizer\"\n href=\"#/tasks\"\n class=\"block px-3 py-2 rounded-md text-base font-medium\"\n :class=\"taskView ? 'text-content bg-primary-subtle' : 'text-content-secondary hover:bg-muted'\">Tasks</a>\n <div v-if=\"!user && hasAPIKey\" class=\"mt-4\">\n <button\n type=\"button\"\n @click=\"loginWithGithub\"\n class=\"w-full rounded bg-muted text-content px-3 py-2 text-base font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\">\n Login\n </button>\n </div>\n <div v-if=\"user && hasAPIKey\" class=\"mt-4\">\n <div class=\"flex items-center gap-3 px-3 py-2 bg-page rounded-md\">\n <img class=\"size-8 rounded-full\" :src=\"user.picture\" alt=\"\">\n <span class=\"text-content font-medium\">{{ user.name }}</span>\n </div>\n <div class=\"mt-2 space-y-1\">\n <button\n type=\"button\"\n @click=\"toggleDarkMode\"\n class=\"w-full inline-flex items-center gap-2 px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle text-left\">\n <svg v-if=\"darkMode\" xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z\"/></svg>\n {{ darkMode ? 'Light mode' : 'Dark mode' }}\n </button>\n <router-link to=\"/team\" v-if=\"hasAccess(roles, 'team')\" class=\"block px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle\">Team</router-link>\n <span v-else class=\"block px-3 py-2 rounded-md text-base text-gray-300 cursor-not-allowed\">\n Team\n <svg class=\"h-4 w-4 ml-1 inline\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <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\" />\n </svg>\n </span>\n <router-link v-if=\"mcpEnabled\" to=\"/mcp\" class=\"block px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle\">MCP</router-link>\n <span v-else class=\"block px-3 py-2 rounded-md text-base text-gray-300 cursor-not-allowed\" title=\"MCP is disabled for this deployment\">\n MCP\n </span>\n <span @click=\"logout\" class=\"block px-3 py-2 rounded-md text-base text-content-secondary hover:bg-primary-subtle cursor-pointer\">Sign out</span>\n </div>\n </div>\n </nav>\n </div>\n</div>\n\n<modal\n v-if=\"showRecentPagesModal\"\n flush-container\n 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\"\n bodyClass=\"modal-recent-pages-body !p-0\"\n>\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"closeRecentPagesModal\" role=\"button\" aria-label=\"Close recent pages\">×</div>\n <div\n class=\"shrink-0 flex items-center gap-3 border-b border-edge bg-surface px-4 py-4 pr-12 dark:bg-shark-900\"\n >\n <h2 class=\"m-0 text-lg font-semibold text-content\">Recent pages</h2>\n <button\n type=\"button\"\n class=\"rounded px-2 py-1 text-sm font-medium text-content-secondary hover:bg-muted disabled:opacity-50\"\n @click=\"clearRecentPagesHistory\"\n :disabled=\"recentPagesList.length === 0\"\n >\n Clear\n </button>\n </div>\n <div class=\"modal-recent-pages-scroll\">\n <div\n v-if=\"recentPagesList.length === 0\"\n class=\"m-4 rounded border border-dashed border-edge px-3 py-6 text-center text-sm text-content-tertiary\"\n >\n No recent pages yet.\n </div>\n <button\n v-for=\"entry in recentPagesList\"\n :key=\"entry.path + '-' + entry.visitedAt\"\n type=\"button\"\n class=\"w-full px-4 py-2.5 text-left hover:bg-muted\"\n :class=\"entry.path === $route.fullPath ? 'bg-primary-subtle' : ''\"\n @click=\"goToRecentPage(entry)\"\n >\n <div class=\"truncate text-sm font-medium text-content\">{{ entry.label }}</div>\n <div class=\"truncate font-mono text-xs text-content-tertiary\">{{ entry.path }}</div>\n </button>\n </div>\n </template>\n</modal>\n</div>\n";
|
|
54427
55035
|
|
|
54428
55036
|
/***/ },
|
|
54429
55037
|
|
|
@@ -54438,6 +55046,17 @@ module.exports = "<modal v-if=\"show\" containerClass=\"!max-w-md\">\n <templat
|
|
|
54438
55046
|
|
|
54439
55047
|
/***/ },
|
|
54440
55048
|
|
|
55049
|
+
/***/ "./frontend/src/script/script.html"
|
|
55050
|
+
/*!*****************************************!*\
|
|
55051
|
+
!*** ./frontend/src/script/script.html ***!
|
|
55052
|
+
\*****************************************/
|
|
55053
|
+
(module) {
|
|
55054
|
+
|
|
55055
|
+
"use strict";
|
|
55056
|
+
module.exports = "<div class=\"px-4 py-6\">\n <div v-if=\"status === 'loading'\" class=\"max-w-5xl mx-auto text-center\">\n <img src=\"images/loader.gif\" class=\"inline mt-10\" alt=\"Loading script\">\n </div>\n\n <div v-else-if=\"script\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center justify-between mb-4\">\n <div>\n <h1 class=\"text-xl font-semibold text-content\">Script</h1>\n <p class=\"text-xs text-content-tertiary font-mono\">{{ script._id }}</p>\n </div>\n <div class=\"flex items-center\">\n <button\n v-if=\"!isEditing\"\n class=\"px-3 py-1.5 mr-2 text-sm bg-gray-700 text-white rounded hover:bg-gray-600\"\n @click=\"startEditing\">\n Edit\n </button>\n <div class=\"relative flex items-center\">\n <async-button\n class=\"px-3 py-1.5 text-sm bg-primary hover:bg-primary-hover text-primary-text rounded-l-md\"\n @click=\"executeScript\">\n {{ selectedRunLabel }}\n </async-button>\n <button\n class=\"px-1.5 py-1.5 text-sm bg-primary hover:bg-primary-hover text-primary-text border-l border-black/10 rounded-r-md\"\n @click.stop=\"showRunDropdown = !showRunDropdown\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n <div\n v-if=\"showRunDropdown\"\n class=\"absolute right-0 top-full z-10 mt-1 w-40 rounded-md bg-surface py-1 shadow-lg ring-1 ring-black/5\">\n <button class=\"block w-full px-4 py-2 text-left text-xs text-content-secondary hover:bg-muted\" @click=\"selectRunMode('run')\">\n Run\n </button>\n <button\n class=\"block w-full px-4 py-2 text-left text-xs\"\n :class=\"canUseDryRun ? 'text-content-secondary hover:bg-muted' : 'cursor-not-allowed text-gray-400'\"\n :disabled=\"!canUseDryRun\"\n :title=\"canUseDryRun ? null : 'Dry run mode requires MongoDB transaction support'\"\n @click=\"selectRunMode('dryRun')\">\n Dry Run\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"relative border rounded bg-surface text-content text-sm overflow-hidden\">\n <div class=\"flex border-b py-1 pl-1 text-xs font-medium bg-surface\">\n <button\n class=\"px-4 py-1 rounded-l-md border-r border-edge-strong font-semibold\"\n :class=\"activeTab === 'code' ? 'bg-gray-700 text-white shadow' : 'bg-muted text-gray-600'\"\n @click=\"activeTab = 'code'\">\n Code\n </button>\n <button\n class=\"px-4 py-1 rounded-r-md font-semibold\"\n :class=\"activeTab === 'output' ? 'bg-gray-700 text-white shadow' : 'bg-muted text-gray-600'\"\n @click=\"activeTab = 'output'\">\n Output<span v-if=\"isDryRunResult\" class=\"ml-1\">[Dry Run]</span>\n </button>\n </div>\n\n <div v-show=\"activeTab === 'code'\" class=\"max-h-[65vh] overflow-y-auto\">\n <div v-if=\"isEditing\" class=\"flex flex-col\">\n <ace-editor\n v-model=\"editedScript\"\n mode=\"javascript\"\n :line-numbers=\"true\"\n class=\"w-full h-[55vh] min-h-[300px]\"\n />\n <div class=\"flex justify-end p-2 border-t border-edge\">\n <button class=\"px-3 py-1.5 text-xs bg-gray-300 text-gray-800 rounded hover:bg-gray-400\" @click=\"cancelEditing\">\n Cancel\n </button>\n </div>\n </div>\n <pre v-else class=\"whitespace-pre-wrap !my-0 bg-muted\"><code ref=\"code\" class=\"language-javascript\" v-text=\"script.script\"></code></pre>\n </div>\n\n <div v-show=\"activeTab === 'output'\" class=\"p-3 max-h-[65vh] overflow-y-auto border-t\">\n <div v-if=\"script.executionResult?.error\" class=\"rounded-md bg-red-50 p-4 mb-3 text-sm text-red-800\">\n {{ script.executionResult.error }}\n </div>\n <dashboard-result\n v-if=\"script.executionResult?.output != null\"\n :result=\"script.executionResult.output\">\n </dashboard-result>\n <pre v-else-if=\"!script.executionResult?.error\">No output</pre>\n\n <div v-if=\"script.executionResult?.logs\" class=\"mt-3 pt-3 border-t border-edge\">\n <div class=\"text-xs font-semibold text-gray-600 uppercase tracking-wide\">Console</div>\n <pre class=\"mt-1 bg-muted text-content p-3 rounded whitespace-pre-wrap overflow-x-auto max-h-[280px]\">{{ script.executionResult.logs }}</pre>\n </div>\n </div>\n </div>\n </div>\n\n <div v-else class=\"max-w-5xl mx-auto text-content-secondary\">\n No script with the given id could be found.\n </div>\n</div>\n";
|
|
55057
|
+
|
|
55058
|
+
/***/ },
|
|
55059
|
+
|
|
54441
55060
|
/***/ "./frontend/src/splash/splash.html"
|
|
54442
55061
|
/*!*****************************************!*\
|
|
54443
55062
|
!*** ./frontend/src/splash/splash.html ***!
|
|
@@ -54526,6 +55145,17 @@ module.exports = "<div class=\"mx-auto max-w-5xl py-6 px-2 flex flex-col gap-8\"
|
|
|
54526
55145
|
|
|
54527
55146
|
/***/ },
|
|
54528
55147
|
|
|
55148
|
+
/***/ "./frontend/src/tooltip/tooltip.html"
|
|
55149
|
+
/*!*******************************************!*\
|
|
55150
|
+
!*** ./frontend/src/tooltip/tooltip.html ***!
|
|
55151
|
+
\*******************************************/
|
|
55152
|
+
(module) {
|
|
55153
|
+
|
|
55154
|
+
"use strict";
|
|
55155
|
+
module.exports = "<span\n ref=\"trigger\"\n class=\"inline-flex outline-none focus-visible:rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600\"\n tabindex=\"0\"\n :aria-describedby=\"isOpen ? tooltipId : null\"\n @mouseenter=\"show\"\n @mouseleave=\"hideUnlessPinned\"\n @focusin=\"show\"\n @focusout=\"handleFocusOut\"\n @click=\"toggle\"\n @keydown.esc.stop=\"hide\"\n>\n <slot></slot>\n <span\n v-show=\"isOpen\"\n ref=\"tooltip\"\n :id=\"tooltipId\"\n class=\"pointer-events-none fixed z-[1000] w-max max-w-[min(20rem,calc(100vw-1rem))] whitespace-normal rounded-md bg-gray-900 px-2.5 py-1.5 text-xs font-normal leading-4 text-white shadow-lg\"\n :style=\"tooltipStyle\"\n role=\"tooltip\"\n >\n {{ text }}\n <span\n class=\"absolute left-1/2 h-2 w-2 -translate-x-1/2 rotate-45 bg-gray-900\"\n :class=\"placement === 'bottom' ? '-top-1' : '-bottom-1'\"\n ></span>\n </span>\n</span>\n";
|
|
55156
|
+
|
|
55157
|
+
/***/ },
|
|
55158
|
+
|
|
54529
55159
|
/***/ "./frontend/src/update-document/update-document.css"
|
|
54530
55160
|
/*!**********************************************************!*\
|
|
54531
55161
|
!*** ./frontend/src/update-document/update-document.css ***!
|
|
@@ -59997,7 +60627,7 @@ exports.validatorErrorSymbol = Symbol('mongoose#validatorError');
|
|
|
59997
60627
|
|
|
59998
60628
|
|
|
59999
60629
|
|
|
60000
|
-
const ObjectId = (__webpack_require__(/*! mongodb/lib/bson */ "./node_modules/mongodb/lib/bson.js").ObjectId);
|
|
60630
|
+
const ObjectId = (__webpack_require__(/*! mongodb/lib/bson */ "./node_modules/mongoose/node_modules/mongodb/lib/bson.js").ObjectId);
|
|
60001
60631
|
const objectIdSymbol = (__webpack_require__(/*! ../helpers/symbols */ "./node_modules/mongoose/lib/helpers/symbols.js").objectIdSymbol);
|
|
60002
60632
|
|
|
60003
60633
|
/**
|
|
@@ -62994,11 +63624,20 @@ class ObjectId extends BSONValue {
|
|
|
62994
63624
|
|
|
62995
63625
|
function internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined) {
|
|
62996
63626
|
const objectStack = [
|
|
62997
|
-
{
|
|
63627
|
+
{ object, ignoreUndefined: ignoreUndefined ?? false, exit: false }
|
|
62998
63628
|
];
|
|
63629
|
+
const path = new Set();
|
|
62999
63630
|
let total = 0;
|
|
63000
63631
|
while (objectStack.length > 0) {
|
|
63001
|
-
const
|
|
63632
|
+
const frame = objectStack.pop();
|
|
63633
|
+
if (frame.exit) {
|
|
63634
|
+
path.delete(frame.object);
|
|
63635
|
+
continue;
|
|
63636
|
+
}
|
|
63637
|
+
const { object: obj, ignoreUndefined: frameIgnoreUndefined } = frame;
|
|
63638
|
+
path.add(obj);
|
|
63639
|
+
frame.exit = true;
|
|
63640
|
+
objectStack.push(frame);
|
|
63002
63641
|
total += 5;
|
|
63003
63642
|
const isObjArray = Array.isArray(obj);
|
|
63004
63643
|
const isObjMap = !isObjArray && (obj instanceof Map || isMap(obj));
|
|
@@ -63009,23 +63648,23 @@ function internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined
|
|
|
63009
63648
|
if (isObjArray) {
|
|
63010
63649
|
const array = target;
|
|
63011
63650
|
for (let i = 0; i < array.length; i++) {
|
|
63012
|
-
total += calculateElementSize(i.toString(), array[i], serializeFunctions, true, frameIgnoreUndefined, objectStack);
|
|
63651
|
+
total += calculateElementSize(i.toString(), array[i], serializeFunctions, true, frameIgnoreUndefined, objectStack, path);
|
|
63013
63652
|
}
|
|
63014
63653
|
}
|
|
63015
63654
|
else if (isObjMap) {
|
|
63016
63655
|
for (const [key, value] of target) {
|
|
63017
|
-
total += calculateElementSize(key, value, serializeFunctions, false, frameIgnoreUndefined, objectStack);
|
|
63656
|
+
total += calculateElementSize(key, value, serializeFunctions, false, frameIgnoreUndefined, objectStack, path);
|
|
63018
63657
|
}
|
|
63019
63658
|
}
|
|
63020
63659
|
else {
|
|
63021
63660
|
for (const key of Object.keys(target)) {
|
|
63022
|
-
total += calculateElementSize(key, target[key], serializeFunctions, false, frameIgnoreUndefined, objectStack);
|
|
63661
|
+
total += calculateElementSize(key, target[key], serializeFunctions, false, frameIgnoreUndefined, objectStack, path);
|
|
63023
63662
|
}
|
|
63024
63663
|
}
|
|
63025
63664
|
}
|
|
63026
63665
|
return total;
|
|
63027
63666
|
}
|
|
63028
|
-
function calculateElementSize(name, value, serializeFunctions = false, isArray = false, ignoreUndefined = false, objectStack) {
|
|
63667
|
+
function calculateElementSize(name, value, serializeFunctions = false, isArray = false, ignoreUndefined = false, objectStack, path) {
|
|
63029
63668
|
if (typeof value?.toBSON === 'function') {
|
|
63030
63669
|
value = value.toBSON();
|
|
63031
63670
|
}
|
|
@@ -63085,7 +63724,10 @@ function calculateElementSize(name, value, serializeFunctions = false, isArray =
|
|
|
63085
63724
|
}
|
|
63086
63725
|
else if (value._bsontype === 'Code') {
|
|
63087
63726
|
if (value.scope != null && Object.keys(value.scope).length > 0) {
|
|
63088
|
-
|
|
63727
|
+
if (path.has(value.scope)) {
|
|
63728
|
+
throw new BSONError('Cannot convert circular structure to BSON');
|
|
63729
|
+
}
|
|
63730
|
+
objectStack.push({ object: value.scope, ignoreUndefined, exit: false });
|
|
63089
63731
|
return (ByteUtils.utf8ByteLength(name) +
|
|
63090
63732
|
1 +
|
|
63091
63733
|
1 +
|
|
@@ -63123,7 +63765,7 @@ function calculateElementSize(name, value, serializeFunctions = false, isArray =
|
|
|
63123
63765
|
if (value.db != null) {
|
|
63124
63766
|
ordered_values['$db'] = value.db;
|
|
63125
63767
|
}
|
|
63126
|
-
objectStack.push({
|
|
63768
|
+
objectStack.push({ object: ordered_values, ignoreUndefined: true, exit: false });
|
|
63127
63769
|
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
63128
63770
|
}
|
|
63129
63771
|
else if (value instanceof RegExp || isRegExp(value)) {
|
|
@@ -63147,7 +63789,10 @@ function calculateElementSize(name, value, serializeFunctions = false, isArray =
|
|
|
63147
63789
|
1);
|
|
63148
63790
|
}
|
|
63149
63791
|
else {
|
|
63150
|
-
|
|
63792
|
+
if (path.has(value)) {
|
|
63793
|
+
throw new BSONError('Cannot convert circular structure to BSON');
|
|
63794
|
+
}
|
|
63795
|
+
objectStack.push({ object: value, ignoreUndefined, exit: false });
|
|
63151
63796
|
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
63152
63797
|
}
|
|
63153
63798
|
case 'function':
|
|
@@ -66010,7 +66655,7 @@ var src_default = VueToastificationPlugin;
|
|
|
66010
66655
|
(module) {
|
|
66011
66656
|
|
|
66012
66657
|
"use strict";
|
|
66013
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.
|
|
66658
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.6.0","description":"AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.","homepage":"https://mongoosestudio.app/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","@modelcontextprotocol/sdk":"^1.30.1","ace-builds":"^1.43.6","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.1","marked":"15.0.12","mpath":"^0.9.0","node-inspect-extracted":"3.x","regexp.escape":"^2.0.1","tailwindcss":"3.4.0","time-commando":"1.0.1","typescript":"^6.0.2","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x","xss":"^1.0.15","zod":"^4.6.5"},"peerDependencies":{"@nestjs/common":"10.x || 11.x","mongoose":"7.x || 8.x || ^9.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"optionalPeerDependencies":{"@mongoosejs/task":"0.5.x || 0.6.x"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","@nestjs/common":"^11.1.9","express":"4.x","mocha":"10.2.0","mongodb-memory-server":"^11.0.1","mongoose":"9.x","sinon":"^21.0.1"},"scripts":{"lint":"eslint .","seed":"node seed/index.js","start":"node ./local.js","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js","test:frontend":"mocha test/frontend/*.test.js","eval:agent":"node eval/agent/run.js"}}');
|
|
66014
66659
|
|
|
66015
66660
|
/***/ }
|
|
66016
66661
|
|
|
@@ -66051,75 +66696,46 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version"
|
|
|
66051
66696
|
/******/
|
|
66052
66697
|
/************************************************************************/
|
|
66053
66698
|
/******/ /* webpack/runtime/amd define */
|
|
66054
|
-
/******/ (
|
|
66055
|
-
/******/
|
|
66056
|
-
/******/
|
|
66057
|
-
/******/ };
|
|
66058
|
-
/******/ })();
|
|
66699
|
+
/******/ __webpack_require__.amdD = function () {
|
|
66700
|
+
/******/ throw new Error('define cannot be used indirect');
|
|
66701
|
+
/******/ };
|
|
66059
66702
|
/******/
|
|
66060
66703
|
/******/ /* webpack/runtime/define property getters */
|
|
66061
|
-
/******/
|
|
66062
|
-
/******/
|
|
66063
|
-
/******/
|
|
66064
|
-
/******/ if(
|
|
66065
|
-
/******/
|
|
66066
|
-
/******/ while(i < definition.length) {
|
|
66067
|
-
/******/ var key = definition[i++];
|
|
66068
|
-
/******/ var binding = definition[i++];
|
|
66069
|
-
/******/ if(!__webpack_require__.o(exports, key)) {
|
|
66070
|
-
/******/ if(binding === 0) {
|
|
66071
|
-
/******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
|
|
66072
|
-
/******/ } else {
|
|
66073
|
-
/******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
|
|
66074
|
-
/******/ }
|
|
66075
|
-
/******/ } else if(binding === 0) { i++; }
|
|
66076
|
-
/******/ }
|
|
66077
|
-
/******/ } else {
|
|
66078
|
-
/******/ for(var key in definition) {
|
|
66079
|
-
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
66080
|
-
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
66081
|
-
/******/ }
|
|
66082
|
-
/******/ }
|
|
66704
|
+
/******/ // define getter/value functions for harmony exports
|
|
66705
|
+
/******/ __webpack_require__.d = (exports, definition) => {
|
|
66706
|
+
/******/ for(var key in definition) {
|
|
66707
|
+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
66708
|
+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
66083
66709
|
/******/ }
|
|
66084
|
-
/******/ }
|
|
66085
|
-
/******/ }
|
|
66710
|
+
/******/ }
|
|
66711
|
+
/******/ };
|
|
66086
66712
|
/******/
|
|
66087
66713
|
/******/ /* webpack/runtime/global */
|
|
66088
|
-
/******/ (()
|
|
66089
|
-
/******/
|
|
66090
|
-
/******/
|
|
66091
|
-
/******/
|
|
66092
|
-
/******/
|
|
66093
|
-
/******/
|
|
66094
|
-
/******/
|
|
66095
|
-
/******/ }
|
|
66096
|
-
/******/ })();
|
|
66714
|
+
/******/ __webpack_require__.g = (function() {
|
|
66715
|
+
/******/ if (typeof globalThis === 'object') return globalThis;
|
|
66716
|
+
/******/ try {
|
|
66717
|
+
/******/ return this || new Function('return this')();
|
|
66718
|
+
/******/ } catch (e) {
|
|
66719
|
+
/******/ if (typeof window === 'object') return window;
|
|
66720
|
+
/******/ }
|
|
66097
66721
|
/******/ })();
|
|
66098
66722
|
/******/
|
|
66099
66723
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
66100
|
-
/******/ (
|
|
66101
|
-
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
66102
|
-
/******/ })();
|
|
66724
|
+
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop));
|
|
66103
66725
|
/******/
|
|
66104
66726
|
/******/ /* webpack/runtime/make namespace object */
|
|
66105
|
-
/******/
|
|
66106
|
-
/******/
|
|
66107
|
-
/******/
|
|
66108
|
-
/******/
|
|
66109
|
-
/******/
|
|
66110
|
-
/******/ }
|
|
66111
|
-
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
66112
|
-
/******/ };
|
|
66113
|
-
/******/ })();
|
|
66727
|
+
/******/ // define __esModule on exports
|
|
66728
|
+
/******/ __webpack_require__.r = (exports) => {
|
|
66729
|
+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
66730
|
+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
66731
|
+
/******/ };
|
|
66114
66732
|
/******/
|
|
66115
66733
|
/******/ /* webpack/runtime/node module decorator */
|
|
66116
|
-
/******/ (
|
|
66117
|
-
/******/
|
|
66118
|
-
/******/
|
|
66119
|
-
/******/
|
|
66120
|
-
/******/
|
|
66121
|
-
/******/ };
|
|
66122
|
-
/******/ })();
|
|
66734
|
+
/******/ __webpack_require__.nmd = (module) => {
|
|
66735
|
+
/******/ module.paths = [];
|
|
66736
|
+
/******/ if (!module.children) module.children = [];
|
|
66737
|
+
/******/ return module;
|
|
66738
|
+
/******/ };
|
|
66123
66739
|
/******/
|
|
66124
66740
|
/************************************************************************/
|
|
66125
66741
|
/******/
|