@mongoosejs/studio 0.0.115 → 0.0.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/actions/Dashboard/getDashboard.js +16 -7
- package/backend/db/dashboardSchema.js +1 -1
- package/frontend/public/app.js +69 -25
- package/frontend/public/tw.css +44 -4
- package/frontend/src/chat/chat-message/chat-message.html +3 -3
- package/frontend/src/chat/chat-message/chat-message.js +33 -1
- package/frontend/src/chat/chat-message-script/chat-message-script.html +5 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.js +7 -2
- package/frontend/src/chat/chat.html +2 -1
- package/frontend/src/chat/chat.js +4 -2
- package/frontend/src/dashboard/dashboard.html +9 -11
- package/frontend/src/dashboard/dashboard.js +7 -7
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +2 -0
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +21 -5
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +4 -2
- package/frontend/src/dashboard-result/dashboard-result.html +4 -2
- package/frontend/src/dashboard-result/dashboard-result.js +2 -1
- package/frontend/src/dashboards/dashboards.html +108 -86
- package/frontend/src/models/models.js +2 -2
- package/package.json +1 -1
|
@@ -41,14 +41,23 @@ module.exports = ({ db }) => async function getDashboard(params) {
|
|
|
41
41
|
return { dashboard, error: { message: error.message } };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
try {
|
|
45
|
+
const { dashboardResult } = await startExec.then(({ dashboardResult }) => {
|
|
46
|
+
if (!dashboardResult) {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
return completeDashboardEvaluate(
|
|
50
|
+
dashboardResult._id,
|
|
51
|
+
$workspaceId,
|
|
52
|
+
authorization,
|
|
53
|
+
result
|
|
54
|
+
);
|
|
55
|
+
});
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
return { dashboard, dashboardResult };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return { dashboard, error: { message: error.message } };
|
|
60
|
+
}
|
|
52
61
|
} else {
|
|
53
62
|
const { dashboardResults } = await getDashboardResults(dashboardId, $workspaceId, authorization);
|
|
54
63
|
return { dashboard, dashboardResults };
|
|
@@ -18,7 +18,7 @@ const dashboardSchema = new mongoose.Schema({
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
dashboardSchema.methods.evaluate = async function evaluate() {
|
|
21
|
-
const context = vm.createContext({ db: this.constructor.db, setTimeout });
|
|
21
|
+
const context = vm.createContext({ db: this.constructor.db, setTimeout, ObjectId: mongoose.Types.ObjectId });
|
|
22
22
|
let result = null;
|
|
23
23
|
result = await vm.runInContext(formatFunction(this.code), context);
|
|
24
24
|
if (result.$document?.constructor?.modelName) {
|
package/frontend/public/app.js
CHANGED
|
@@ -336,6 +336,7 @@ const vanillatoasts = __webpack_require__(/*! vanillatoasts */ "./node_modules/v
|
|
|
336
336
|
module.exports = app => app.component('chat-message-script', {
|
|
337
337
|
template,
|
|
338
338
|
props: ['message', 'script', 'language'],
|
|
339
|
+
emits: ['copyMessage'],
|
|
339
340
|
data() {
|
|
340
341
|
return {
|
|
341
342
|
activeTab: 'code',
|
|
@@ -411,9 +412,13 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
411
412
|
this.$router.push('/dashboard/' + dashboard._id);
|
|
412
413
|
},
|
|
413
414
|
async copyOutput() {
|
|
414
|
-
|
|
415
|
+
let output = this.message.executionResult.output;
|
|
416
|
+
if (output != null && typeof output === 'object') {
|
|
417
|
+
output = JSON.stringify(output, null, 2);
|
|
418
|
+
}
|
|
419
|
+
await navigator.clipboard.writeText(output);
|
|
415
420
|
vanillatoasts.create({
|
|
416
|
-
title: '
|
|
421
|
+
title: 'Code output copied!',
|
|
417
422
|
type: 'success',
|
|
418
423
|
timeout: 3000,
|
|
419
424
|
icon: 'images/success.png',
|
|
@@ -457,6 +462,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
457
462
|
|
|
458
463
|
const api = __webpack_require__(/*! ../../api */ "./frontend/src/api.js");
|
|
459
464
|
const marked = (__webpack_require__(/*! marked */ "./node_modules/marked/lib/marked.cjs").marked);
|
|
465
|
+
const vanillatoasts = __webpack_require__(/*! vanillatoasts */ "./node_modules/vanillatoasts/vanillatoasts.js");
|
|
460
466
|
const template = __webpack_require__(/*! ./chat-message.html */ "./frontend/src/chat/chat-message/chat-message.html");
|
|
461
467
|
|
|
462
468
|
module.exports = app => app.component('chat-message', {
|
|
@@ -464,7 +470,7 @@ module.exports = app => app.component('chat-message', {
|
|
|
464
470
|
props: ['message'],
|
|
465
471
|
computed: {
|
|
466
472
|
styleForMessage() {
|
|
467
|
-
return this.message.role === 'user' ? 'bg-gray-100' : '';
|
|
473
|
+
return this.message.role === 'user' ? 'p-3 bg-gray-100' : 'py-3 pr-3';
|
|
468
474
|
},
|
|
469
475
|
contentSplitByScripts() {
|
|
470
476
|
const content = this.message.content;
|
|
@@ -516,6 +522,37 @@ module.exports = app => app.component('chat-message', {
|
|
|
516
522
|
});
|
|
517
523
|
message.executionResult = chatMessage.executionResult;
|
|
518
524
|
console.log(message);
|
|
525
|
+
},
|
|
526
|
+
async copyMessage() {
|
|
527
|
+
const parts = this.contentSplitByScripts;
|
|
528
|
+
let output = '';
|
|
529
|
+
for (const part of parts) {
|
|
530
|
+
if (part.type === 'text') {
|
|
531
|
+
output += part.content + '\n';
|
|
532
|
+
} else if (part.type === 'code') {
|
|
533
|
+
let result = this.message.executionResult?.output;
|
|
534
|
+
if (result != null && typeof result === 'object') {
|
|
535
|
+
result = JSON.stringify(result, null, 2);
|
|
536
|
+
}
|
|
537
|
+
if (result) {
|
|
538
|
+
let executionOutput = this.message.executionResult?.output;
|
|
539
|
+
if (executionOutput != null && typeof executionOutput === 'object') {
|
|
540
|
+
executionOutput = JSON.stringify(executionOutput, null, 2);
|
|
541
|
+
}
|
|
542
|
+
if (executionOutput) {
|
|
543
|
+
output += '```\n' + executionOutput + '\n```\n';
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
await navigator.clipboard.writeText(output.trim());
|
|
549
|
+
vanillatoasts.create({
|
|
550
|
+
title: 'Message output copied!',
|
|
551
|
+
type: 'success',
|
|
552
|
+
timeout: 3000,
|
|
553
|
+
icon: 'images/success.png',
|
|
554
|
+
positionClass: 'bottomRight'
|
|
555
|
+
});
|
|
519
556
|
}
|
|
520
557
|
}
|
|
521
558
|
});
|
|
@@ -553,6 +590,8 @@ module.exports = app => app.component('chat', {
|
|
|
553
590
|
async sendMessage() {
|
|
554
591
|
this.sendingMessage = true;
|
|
555
592
|
try {
|
|
593
|
+
const content = this.newMessage;
|
|
594
|
+
this.newMessage = '';
|
|
556
595
|
if (!this.chatThreadId) {
|
|
557
596
|
const { chatThread } = await api.ChatThread.createChatThread();
|
|
558
597
|
this.chatThreads.unshift(chatThread);
|
|
@@ -561,7 +600,7 @@ module.exports = app => app.component('chat', {
|
|
|
561
600
|
}
|
|
562
601
|
|
|
563
602
|
this.chatMessages.push({
|
|
564
|
-
content
|
|
603
|
+
content,
|
|
565
604
|
role: 'user'
|
|
566
605
|
});
|
|
567
606
|
|
|
@@ -573,7 +612,7 @@ module.exports = app => app.component('chat', {
|
|
|
573
612
|
|
|
574
613
|
const { chatMessages, chatThread } = await api.ChatThread.createChatMessage({
|
|
575
614
|
chatThreadId: this.chatThreadId,
|
|
576
|
-
content
|
|
615
|
+
content
|
|
577
616
|
});
|
|
578
617
|
this.chatMessages.push(chatMessages[1]);
|
|
579
618
|
for (const thread of this.chatThreads) {
|
|
@@ -904,9 +943,11 @@ const template = __webpack_require__(/*! ./dashboard-chart.html */ "./frontend/s
|
|
|
904
943
|
|
|
905
944
|
module.exports = app => app.component('dashboard-chart', {
|
|
906
945
|
template: template,
|
|
907
|
-
props: ['value', '
|
|
946
|
+
props: ['value', 'fullscreen'],
|
|
947
|
+
emits: ['fullscreen'],
|
|
908
948
|
data: () => ({
|
|
909
|
-
chart: null
|
|
949
|
+
chart: null,
|
|
950
|
+
showDetailModal: false
|
|
910
951
|
}),
|
|
911
952
|
mounted() {
|
|
912
953
|
const ctx = this.$refs.chart.getContext('2d');
|
|
@@ -1074,7 +1115,8 @@ const template = __webpack_require__(/*! ./dashboard-result.html */ "./frontend/
|
|
|
1074
1115
|
|
|
1075
1116
|
module.exports = app => app.component('dashboard-result', {
|
|
1076
1117
|
template: template,
|
|
1077
|
-
props: ['result', 'finishedEvaluatingAt'],
|
|
1118
|
+
props: ['result', 'finishedEvaluatingAt', 'fullscreen'],
|
|
1119
|
+
emits: ['fullscreen'],
|
|
1078
1120
|
mounted: async function() {
|
|
1079
1121
|
},
|
|
1080
1122
|
methods: {
|
|
@@ -1167,22 +1209,22 @@ module.exports = app => app.component('dashboard', {
|
|
|
1167
1209
|
},
|
|
1168
1210
|
async evaluateDashboard() {
|
|
1169
1211
|
this.status = 'evaluating';
|
|
1212
|
+
this.errorMessage = null;
|
|
1170
1213
|
try {
|
|
1171
1214
|
const { dashboard, dashboardResult, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
|
|
1172
1215
|
this.dashboard = dashboard;
|
|
1173
|
-
if (error) {
|
|
1174
|
-
this.errorMessage = error.message;
|
|
1175
|
-
}
|
|
1176
1216
|
this.code = this.dashboard.code;
|
|
1177
1217
|
this.title = this.dashboard.title;
|
|
1178
1218
|
this.description = this.dashboard.description ?? '';
|
|
1179
|
-
|
|
1219
|
+
if (dashboardResult) {
|
|
1220
|
+
this.dashboardResults.unshift(dashboardResult);
|
|
1221
|
+
}
|
|
1222
|
+
if (error) {
|
|
1223
|
+
this.errorMessage = error.message;
|
|
1224
|
+
}
|
|
1180
1225
|
} finally {
|
|
1181
1226
|
this.status = 'loaded';
|
|
1182
1227
|
}
|
|
1183
|
-
},
|
|
1184
|
-
openDetailModal() {
|
|
1185
|
-
this.showDetailModal = true;
|
|
1186
1228
|
}
|
|
1187
1229
|
},
|
|
1188
1230
|
computed: {
|
|
@@ -1226,6 +1268,7 @@ const template = __webpack_require__(/*! ./edit-dashboard.html */ "./frontend/sr
|
|
|
1226
1268
|
module.exports = app => app.component('edit-dashboard', {
|
|
1227
1269
|
template: template,
|
|
1228
1270
|
props: ['dashboardId', 'code', 'currentDescription', 'currentTitle'],
|
|
1271
|
+
emits: ['close', 'clearError'],
|
|
1229
1272
|
data: function() {
|
|
1230
1273
|
return {
|
|
1231
1274
|
status: 'loaded',
|
|
@@ -1239,6 +1282,7 @@ module.exports = app => app.component('edit-dashboard', {
|
|
|
1239
1282
|
this.$emit('close');
|
|
1240
1283
|
},
|
|
1241
1284
|
async updateCode() {
|
|
1285
|
+
this.$emit('clearError');
|
|
1242
1286
|
this.status = 'loading';
|
|
1243
1287
|
try {
|
|
1244
1288
|
const { doc, result, error } = await api.Dashboard.updateDashboard({
|
|
@@ -2671,13 +2715,13 @@ module.exports = app => app.component('models', {
|
|
|
2671
2715
|
this.query.search = this.searchText;
|
|
2672
2716
|
const query = this.query;
|
|
2673
2717
|
const newUrl = this.$router.resolve({ query }).href;
|
|
2674
|
-
|
|
2718
|
+
this.$router.push({ query });
|
|
2675
2719
|
} else {
|
|
2676
2720
|
this.filter = {};
|
|
2677
2721
|
delete this.query.search;
|
|
2678
2722
|
const query = this.query;
|
|
2679
2723
|
const newUrl = this.$router.resolve({ query }).href;
|
|
2680
|
-
|
|
2724
|
+
this.$router.push({ query });
|
|
2681
2725
|
}
|
|
2682
2726
|
this.documents = [];
|
|
2683
2727
|
this.status = 'loading';
|
|
@@ -4169,7 +4213,7 @@ module.exports = "<button v-bind=\"attrsToBind\" :disabled=\"isDisabled\" @click
|
|
|
4169
4213
|
/***/ ((module) => {
|
|
4170
4214
|
|
|
4171
4215
|
"use strict";
|
|
4172
|
-
module.exports = "<div class=\"relative border rounded bg-gray-100 text-black text-sm overflow-hidden\">\n <div class=\"flex border-b pt-[1px] text-xs font-medium bg-gray-200\">\n <button\n class=\"px-3 py-1 border-r border-gray-300 hover:bg-green-300\"\n :class=\"{'bg-gray-300': activeTab === 'code', 'bg-green-300': activeTab === 'code'}\"\n @click=\"activeTab = 'code'\">\n Code\n </button>\n <button\n class=\"px-3 py-1 hover:bg-green-300\"\n :class=\"{'bg-green-300': activeTab === 'output'}\"\n @click=\"activeTab = 'output'\">\n Output\n </button>\n <div class=\"ml-auto mr-1 flex\">\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-gray-500 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center\"\n @click=\"copyOutput\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center\"\n @click=\"openDetailModal\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n <async-button\n class=\"px-2 py-1 text-xs bg-green-500 text-white border-none rounded cursor-pointer hover:bg-green-600 transition-colors disabled:bg-gray-400\"\n @click=\"executeScript(message, script)\">\n Execute\n </async-button>\n <div class=\"relative ml-1\" ref=\"dropdown\">\n <button\n @click.stop=\"toggleDropdown\"\n class=\"px-1 py-1 text-xs hover:bg-gray-300 rounded flex items-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M10 6a2 2 0 110-4 2 2 0 010 4zm0 6a2 2 0 110-4 2 2 0 010 4zm0 6a2 2 0 110-4 2 2 0 010 4z\" />\n </svg>\n </button>\n <div\n v-if=\"showDropdown\"\n class=\"absolute right-0 z-10 mt-1 w-64 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5\">\n <button\n class=\"block w-full text-left px-4 py-2 text-xs text-gray-700 hover:bg-gray-100\"\n @click=\"openCreateDashboardModal(); showDropdown = false\">\n Create Dashboard\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <pre class=\"p-3 whitespace-pre-wrap max-h-[50vh] max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] overflow-y-auto\" v-show=\"activeTab === 'code'\"><code v-text=\"script\" ref=\"code\" :class=\"'language-' + language\"></code></pre>\n\n <div class=\"p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-white border-t max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] relative\" v-show=\"activeTab === 'output'\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" />\n <dashboard-map v-else-if=\"message.executionResult?.output?.$featureCollection\" :value=\"message.executionResult?.output\" />\n <pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n\n <modal ref=\"outputModal\" v-if=\"showDetailModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showDetailModal = false;\">×</div>\n <div class=\"h-full overflow-auto\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" :responsive=\"true\" />\n <pre v-else class=\"whitespace-pre-wrap\">{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n </template>\n </modal>\n <modal v-if=\"showCreateDashboardModal\">\n <template #body>\n <div class=\"modal-exit\" @click=\"showCreateDashboardModal = false\">×</div>\n <div>\n <div class=\"mt-4 text-gray-900 font-semibold\">Create Dashboard</div>\n <div class=\"mt-4\">\n <label class=\"block text-sm font-medium leading-6 text-gray-900\">Title</label>\n <div class=\"mt-2\">\n <div class=\"w-full flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-teal-600\">\n <input type=\"text\" v-model=\"newDashboardTitle\" class=\"outline-none block flex-1 border-0 bg-transparent py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6\" placeholder=\"My Dashboard\">\n </div>\n </div>\n </div>\n <div class=\"my-4\">\n <label class=\"block text-sm font-medium leading-6 text-gray-900\">Code</label>\n <div class=\"border border-gray-200\">\n <textarea class=\"p-2 h-[300px] w-full\" ref=\"dashboardCodeEditor\"></textarea>\n </div>\n </div>\n <async-button\n @click=\"createDashboardFromScript\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">\n Submit\n </async-button>\n <div v-if=\"createErrors.length > 0\" class=\"rounded-md bg-red-50 p-4 mt-1\">\n <div class=\"flex\">\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-sm font-medium text-red-800\">Error</h3>\n <div class=\"mt-2 text-sm text-red-700\">\n {{createError}}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
4216
|
+
module.exports = "<div class=\"relative border rounded bg-gray-100 text-black text-sm overflow-hidden\">\n <div class=\"flex border-b pt-[1px] text-xs font-medium bg-gray-200\">\n <button\n class=\"px-3 py-1 border-r border-gray-300 hover:bg-green-300\"\n :class=\"{'bg-gray-300': activeTab === 'code', 'bg-green-300': activeTab === 'code'}\"\n @click=\"activeTab = 'code'\">\n Code\n </button>\n <button\n class=\"px-3 py-1 hover:bg-green-300\"\n :class=\"{'bg-green-300': activeTab === 'output'}\"\n @click=\"activeTab = 'output'\">\n Output\n </button>\n <div class=\"ml-auto mr-1 flex\">\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-gray-500 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center\"\n @click=\"copyOutput\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\" />\n </svg>\n </button>\n <button\n v-if=\"activeTab === 'output'\"\n class=\"px-2 py-1 mr-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center\"\n @click=\"openDetailModal\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n <async-button\n class=\"px-2 py-1 text-xs bg-green-500 text-white border-none rounded cursor-pointer hover:bg-green-600 transition-colors disabled:bg-gray-400\"\n @click=\"executeScript(message, script)\">\n Execute\n </async-button>\n <div class=\"relative ml-1\" ref=\"dropdown\">\n <button\n @click.stop=\"toggleDropdown\"\n class=\"px-1 py-1 text-xs hover:bg-gray-300 rounded flex items-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M10 6a2 2 0 110-4 2 2 0 010 4zm0 6a2 2 0 110-4 2 2 0 010 4zm0 6a2 2 0 110-4 2 2 0 010 4z\" />\n </svg>\n </button>\n <div\n v-if=\"showDropdown\"\n class=\"absolute right-0 z-10 mt-1 w-64 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5\">\n <button\n class=\"block w-full text-left px-4 py-2 text-xs text-gray-700 hover:bg-gray-100\"\n @click=\"openCreateDashboardModal(); showDropdown = false\">\n Create Dashboard\n </button>\n <button\n class=\"block w-full text-left px-4 py-2 text-xs text-gray-700 hover:bg-gray-100\"\n @click=\"$emit('copyMessage'); showDropdown = false\">\n Copy Full Message\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <pre class=\"p-3 whitespace-pre-wrap max-h-[50vh] max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] overflow-y-auto\" v-show=\"activeTab === 'code'\"><code v-text=\"script\" ref=\"code\" :class=\"'language-' + language\"></code></pre>\n\n <div class=\"p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-white border-t max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] relative\" v-show=\"activeTab === 'output'\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" />\n <dashboard-map v-else-if=\"message.executionResult?.output?.$featureCollection\" :value=\"message.executionResult?.output\" />\n <pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n\n <modal ref=\"outputModal\" v-if=\"showDetailModal\" containerClass=\"!h-[90vh] !w-[90vw]\">\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showDetailModal = false;\">×</div>\n <div class=\"h-full overflow-auto\">\n <dashboard-chart v-if=\"message.executionResult?.output?.$chart\" :value=\"message.executionResult?.output\" :responsive=\"true\" />\n <pre v-else class=\"whitespace-pre-wrap\">{{ message.executionResult?.output || 'No output' }}</pre>\n </div>\n </template>\n </modal>\n <modal v-if=\"showCreateDashboardModal\">\n <template #body>\n <div class=\"modal-exit\" @click=\"showCreateDashboardModal = false\">×</div>\n <div>\n <div class=\"mt-4 text-gray-900 font-semibold\">Create Dashboard</div>\n <div class=\"mt-4\">\n <label class=\"block text-sm font-medium leading-6 text-gray-900\">Title</label>\n <div class=\"mt-2\">\n <div class=\"w-full flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-teal-600\">\n <input type=\"text\" v-model=\"newDashboardTitle\" class=\"outline-none block flex-1 border-0 bg-transparent py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6\" placeholder=\"My Dashboard\">\n </div>\n </div>\n </div>\n <div class=\"my-4\">\n <label class=\"block text-sm font-medium leading-6 text-gray-900\">Code</label>\n <div class=\"border border-gray-200\">\n <textarea class=\"p-2 h-[300px] w-full\" ref=\"dashboardCodeEditor\"></textarea>\n </div>\n </div>\n <async-button\n @click=\"createDashboardFromScript\"\n class=\"rounded-md bg-teal-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-teal-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600\">\n Submit\n </async-button>\n <div v-if=\"createErrors.length > 0\" class=\"rounded-md bg-red-50 p-4 mt-1\">\n <div class=\"flex\">\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-sm font-medium text-red-800\">Error</h3>\n <div class=\"mt-2 text-sm text-red-700\">\n {{createError}}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </modal>\n</div>\n";
|
|
4173
4217
|
|
|
4174
4218
|
/***/ }),
|
|
4175
4219
|
|
|
@@ -4180,7 +4224,7 @@ module.exports = "<div class=\"relative border rounded bg-gray-100 text-black te
|
|
|
4180
4224
|
/***/ ((module) => {
|
|
4181
4225
|
|
|
4182
4226
|
"use strict";
|
|
4183
|
-
module.exports = "<div class=\"relative flex items-start\" :class=\"{'justify-end': message.role === 'user'}\">\n <div\n class=\"min-w-0 max-w-[calc(100vw-
|
|
4227
|
+
module.exports = "<div class=\"relative flex items-start\" :class=\"{'justify-end': message.role === 'user'}\">\n <div\n class=\"min-w-0 max-w-[calc(100vw-3rem)] lg:max-w-[calc(100vw-15rem)]\"\n :class=\"{'text-right': message.role === 'user'}\">\n\n <div class=\"text-sm text-gray-900 rounded-md inline-block relative\" :class=\"styleForMessage\">\n <div v-for=\"part in contentSplitByScripts\">\n <div v-if=\"part.type === 'text'\" v-html=\"marked(part.content)\">\n </div>\n <div v-else-if=\"part.type === 'code'\">\n <chat-message-script :message=\"message\" :script=\"part.content\" :language=\"part.language\" @copyMessage=\"copyMessage\"></chat-message-script>\n </div>\n </div>\n </div>\n </div>\n</div>\n";
|
|
4184
4228
|
|
|
4185
4229
|
/***/ }),
|
|
4186
4230
|
|
|
@@ -4191,7 +4235,7 @@ module.exports = "<div class=\"relative flex items-start\" :class=\"{'justify-en
|
|
|
4191
4235
|
/***/ ((module) => {
|
|
4192
4236
|
|
|
4193
4237
|
"use strict";
|
|
4194
|
-
module.exports = "<div class=\"flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <button\n class=\"fixed top-[65px] right-4 z-10 p-2 rounded-md shadow bg-white\"\n :class=\"hasWorkspace ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 cursor-not-allowed bg-gray-50'\"\n @click=\"toggleShareThread\"\n :disabled=\"!hasWorkspace || !chatThreadId || sharingThread\"\n aria-label=\"Share thread with workspace\"\n title=\"Share thread with workspace\"\n >\n <svg v-if=\"hasWorkspace\" xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.48 2.48 0 0 0 0-1.39l7.02-4.11a2.5 2.5 0 1 0-.87-1.37L8.04 9.94a2.5 2.5 0 1 0 0 4.12l7.12 4.16a2.5 2.5 0 1 0 .84-1.34l-7.05-4.12c-.04-.02-.08-.05-.11-.07a2.48 2.48 0 0 0 0-1.39c.03-.02.07-.04.11-.07l7.11-4.16c.52.47 1.2.76 1.94.76a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0-1.94.94L7.97 8.43a2.5 2.5 0 1 0 0 7.14l9.09 5.3c.52-.47 1.2-.76 1.94-.76a2.5 2.5 0 1 0 0-5z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M12 1a5 5 0 00-5 5v3H6a2 2 0 00-2 2v9a2 2 0 002 2h12a2 2 0 002-2v-9a2 2 0 00-2-2h-1V6a5 5 0 00-5-5zm-3 8V6a3 3 0 016 0v3H9zm9 2v9H6v-9h12z\"/></svg>\n </button>\n <!-- Sidebar: Chat Threads -->\n <aside class=\"bg-gray-50 border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-64 fixed lg:relative\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-64' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-64 overflow-x-hidden\">\n <div class=\"p-4 font-bold text-lg\">Chat Threads</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <div class=\"p-4 w-64\">\n <async-button\n @click=\"createNewThread\"\n class=\"w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700\"\n >\n Create New Thread\n </async-button>\n </div>\n <div v-if=\"status === 'loaded' && chatThreads.length === 0\" class=\"p-4 text-sm text-gray-700\">\n No threads yet\n </div>\n <ul v-if=\"status === 'loaded'\" class=\"w-64\">\n <li\n v-for=\"thread in chatThreads\"\n :key=\"thread._id\"\n @click=\"selectThread(thread._id)\"\n class=\"p-4 hover:bg-gray-200 cursor-pointer w-64\"\n :class=\"{ 'bg-gray-300': thread._id === chatThreadId }\"\n >\n {{ thread.title || 'Untitled Thread' }}\n </li>\n </ul>\n </aside>\n\n <!-- Main Chat Area -->\n <main class=\"flex-1 flex flex-col\">\n <div class=\"flex-1 overflow-y-auto p-6 space-y-4\" ref=\"messagesContainer\">\n <ul role=\"list\" class=\"space-y-4\">\n <div v-if=\"true\">\n <div class=\"flex items-center justify-center py-3 mb-4\">\n <div class=\"bg-gray-300 h-px flex-grow max-w-xs\"></div>\n <p class=\"mx-4 text-sm font-medium text-gray-500\">This is the beginning of the message thread</p>\n <div class=\"bg-gray-300 h-px flex-grow max-w-xs\"></div>\n </div>\n </div>\n <li v-for=\"message in chatMessages\" :key=\"message._id\">\n <chat-message :message=\"message\"></chat-message>\n </li>\n </ul>\n </div>\n\n\n <!-- Input Area -->\n <div class=\"border-t p-4\">\n <form @submit.prevent=\"sendMessage\" :disabled=\"sendingMessage\" class=\"flex gap-2 items-end justify-end\">\n <textarea\n v-model=\"newMessage\"\n placeholder=\"Ask something
|
|
4238
|
+
module.exports = "<div class=\"flex\" style=\"height: calc(100vh - 55px); height: calc(100dvh - 55px)\">\n <div class=\"fixed top-[65px] cursor-pointer bg-gray-100 rounded-r-md z-10\" @click=\"hideSidebar = false\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"#5f6368\"><path d=\"M360-120v-720h80v720h-80Zm160-160v-400l200 200-200 200Z\"/></svg>\n </div>\n <button\n class=\"fixed top-[65px] right-4 z-10 p-2 rounded-md shadow bg-white\"\n :class=\"hasWorkspace ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 cursor-not-allowed bg-gray-50'\"\n @click=\"toggleShareThread\"\n :disabled=\"!hasWorkspace || !chatThreadId || sharingThread\"\n aria-label=\"Share thread with workspace\"\n title=\"Share thread with workspace\"\n >\n <svg v-if=\"hasWorkspace\" xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.48 2.48 0 0 0 0-1.39l7.02-4.11a2.5 2.5 0 1 0-.87-1.37L8.04 9.94a2.5 2.5 0 1 0 0 4.12l7.12 4.16a2.5 2.5 0 1 0 .84-1.34l-7.05-4.12c-.04-.02-.08-.05-.11-.07a2.48 2.48 0 0 0 0-1.39c.03-.02.07-.04.11-.07l7.11-4.16c.52.47 1.2.76 1.94.76a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0-1.94.94L7.97 8.43a2.5 2.5 0 1 0 0 7.14l9.09 5.3c.52-.47 1.2-.76 1.94-.76a2.5 2.5 0 1 0 0-5z\"/></svg>\n <svg v-else xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M12 1a5 5 0 00-5 5v3H6a2 2 0 00-2 2v9a2 2 0 002 2h12a2 2 0 002-2v-9a2 2 0 00-2-2h-1V6a5 5 0 00-5-5zm-3 8V6a3 3 0 016 0v3H9zm9 2v9H6v-9h12z\"/></svg>\n </button>\n <!-- Sidebar: Chat Threads -->\n <aside class=\"bg-gray-50 border-r overflow-y-auto overflow-x-hidden h-full transition-all duration-300 ease-in-out z-20 w-0 lg:w-64 fixed lg:relative\" :class=\"hideSidebar === true ? '!w-0' : hideSidebar === false ? '!w-64' : ''\">\n <div class=\"flex items-center border-b border-gray-100 w-64 overflow-x-hidden\">\n <div class=\"p-4 font-bold text-lg\">Chat Threads</div>\n <button\n @click=\"hideSidebar = true\"\n class=\"ml-auto mr-2 p-2 rounded hover:bg-gray-200 focus:outline-none\"\n aria-label=\"Close sidebar\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"h-5 w-5\" viewBox=\"0 -960 960 960\" class=\"w-5\" fill=\"currentColor\"><path d=\"M660-320v-320L500-480l160 160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm120-80v-560H200v560h120Zm80 0h360v-560H400v560Zm-80 0H200h120Z\"/></svg>\n </button>\n </div>\n <div class=\"p-4 w-64\">\n <async-button\n @click=\"createNewThread\"\n class=\"w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700\"\n >\n Create New Thread\n </async-button>\n </div>\n <div v-if=\"status === 'loaded' && chatThreads.length === 0\" class=\"p-4 text-sm text-gray-700\">\n No threads yet\n </div>\n <ul v-if=\"status === 'loaded'\" class=\"w-64\">\n <li\n v-for=\"thread in chatThreads\"\n :key=\"thread._id\"\n @click=\"selectThread(thread._id)\"\n class=\"p-4 hover:bg-gray-200 cursor-pointer w-64\"\n :class=\"{ 'bg-gray-300': thread._id === chatThreadId }\"\n >\n {{ thread.title || 'Untitled Thread' }}\n </li>\n </ul>\n </aside>\n\n <!-- Main Chat Area -->\n <main class=\"flex-1 flex flex-col\">\n <div class=\"flex-1 overflow-y-auto p-6 space-y-4\" ref=\"messagesContainer\">\n <ul role=\"list\" class=\"space-y-4\">\n <div v-if=\"true\">\n <div class=\"flex items-center justify-center py-3 mb-4\">\n <div class=\"bg-gray-300 h-px flex-grow max-w-xs\"></div>\n <p class=\"mx-4 text-sm font-medium text-gray-500\">This is the beginning of the message thread</p>\n <div class=\"bg-gray-300 h-px flex-grow max-w-xs\"></div>\n </div>\n </div>\n <li v-for=\"message in chatMessages\" :key=\"message._id\">\n <chat-message :message=\"message\"></chat-message>\n </li>\n </ul>\n </div>\n\n\n <!-- Input Area -->\n <div class=\"border-t p-4\">\n <form @submit.prevent=\"sendMessage\" :disabled=\"sendingMessage\" class=\"flex gap-2 items-end justify-end\">\n <textarea\n v-model=\"newMessage\"\n :placeholder=\"sendingMessage ? 'Sending...' : 'Ask something...'\"\n class=\"flex-1 border rounded px-4 py-2 resize-none overflow-y-auto\"\n :disabled=\"sendingMessage\"\n rows=\"1\"\n ref=\"messageInput\"\n @input=\"adjustTextareaHeight\"\n @keydown.enter.exact.prevent=\"handleEnter\"\n ></textarea>\n <button class=\"bg-blue-600 text-white px-4 h-[42px] rounded disabled:bg-gray-600\" :disabled=\"sendingMessage\">\n <svg v-if=\"sendingMessage\" style=\"height: 1em\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" opacity=\"0.3\" />\n <path d=\"M12 2a10 10 0 0 1 10 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 12 12\" to=\"360 12 12\" dur=\"1s\" repeatCount=\"indefinite\" />\n </path>\n </g>\n </svg>\n <span v-else>Send</span>\n </button>\n </form>\n </div>\n </main>\n</div>\n";
|
|
4195
4239
|
|
|
4196
4240
|
/***/ }),
|
|
4197
4241
|
|
|
@@ -4257,7 +4301,7 @@ module.exports = "<div>\n <div class=\"mb-2\">\n <textarea class=\"border bo
|
|
|
4257
4301
|
/***/ ((module) => {
|
|
4258
4302
|
|
|
4259
4303
|
"use strict";
|
|
4260
|
-
module.exports = "<div :class=\"responsive ? 'h-full' : ''\">\n <div v-if=\"header\" class=\"border-b border-gray-100 px-2 pb-2 flex items-center\">\n <div class=\"text-xl font-bold\">{{header}}</div>\n <button\n class=\"ml-auto px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors\"\n @click=\"exportPNG\"\n title=\"Export PNG\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 1.5em;\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M280-280h400v-80H280v80Zm200-120 160-160-56-56-64 62v-166h-80v166l-64-62-56 56 160 160Zm0 320q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z\"/></svg>\n </button>\n </div>\n <div v-else class=\"border-b border-gray-100 px-2 pb-2 text-right\">\n <button\n class=\"
|
|
4304
|
+
module.exports = "<div :class=\"responsive ? 'h-full' : ''\">\n <div v-if=\"header && !fullscreen\" class=\"border-b border-gray-100 px-2 pb-2 flex items-center gap-1\">\n <div class=\"text-xl font-bold\">{{header}}</div>\n <button\n class=\"ml-auto px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors\"\n @click=\"exportPNG\"\n title=\"Export PNG\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 1.5em;\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M280-280h400v-80H280v80Zm200-120 160-160-56-56-64 62v-166h-80v166l-64-62-56 56 160 160Zm0 320q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z\"/></svg>\n </button>\n <button\n class=\"px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors flex items-center\"\n @click=\"$emit('fullscreen')\"\n aria-label=\"Expand dashboard result\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 1.5em\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n </div>\n <div v-else-if=\"!fullscreen\" class=\"pt-1 border-b border-gray-100 px-2 pb-2 text-right flex items-center justify-end gap-1 w-full\">\n <button\n class=\"px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors\"\n @click=\"exportPNG\"\n title=\"Export PNG\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 1.5em;\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M280-280h400v-80H280v80Zm200-120 160-160-56-56-64 62v-166h-80v166l-64-62-56 56 160 160Zm0 320q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z\"/></svg>\n </button>\n <button\n class=\"px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors flex items-center\"\n @click=\"$emit('fullscreen')\"\n aria-label=\"Expand dashboard result\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 1.5em\" class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5\" />\n </svg>\n </button>\n </div>\n <div :class=\"responsive ? 'relative h-full min-h-0' : ''\">\n <canvas ref=\"chart\" class=\"block w-full h-full\"></canvas>\n </div>\n</div>\n";
|
|
4261
4305
|
|
|
4262
4306
|
/***/ }),
|
|
4263
4307
|
|
|
@@ -4301,7 +4345,7 @@ module.exports = "<div class=\"py-2\">\n <div v-if=\"header\" class=\"border-b
|
|
|
4301
4345
|
/***/ ((module) => {
|
|
4302
4346
|
|
|
4303
4347
|
"use strict";
|
|
4304
|
-
module.exports = "<div>\n <div v-if=\"Array.isArray(result)\">\n <div v-for=\"el in result\" :key=\"el._id || el.finishedEvaluatingAt\">\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(el)\"\n :value=\"el\">\n </component>\n </div>\n </div>\n <div v-else>\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(result)\"\n :value=\"result\">\n </component>\n </div>\n <div class=\"text-right text-sm text-gray-700 mt-1\" v-if=\"finishedEvaluatingAt\">\n Last Evaluated: {{ format.isoToLongDateTime(finishedEvaluatingAt) }}\n </div>\n</div>\n";
|
|
4348
|
+
module.exports = "<div>\n <div v-if=\"Array.isArray(result)\">\n <div v-for=\"el in result\" :key=\"el._id || el.finishedEvaluatingAt\">\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(el)\"\n :value=\"el\">\n </component>\n </div>\n </div>\n <div v-else>\n <component\n class=\"bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl\"\n :is=\"getComponentForValue(result)\"\n :value=\"result\"\n :fullscreen=\"fullscreen\"\n @fullscreen=\"$emit('fullscreen')\">\n </component>\n </div>\n <div class=\"text-right text-sm text-gray-700 mt-1\" v-if=\"finishedEvaluatingAt && !fullscreen\">\n Last Evaluated: {{ format.isoToLongDateTime(finishedEvaluatingAt) }}\n </div>\n</div>\n";
|
|
4305
4349
|
|
|
4306
4350
|
/***/ }),
|
|
4307
4351
|
|
|
@@ -4323,7 +4367,7 @@ module.exports = "<div class=\"py-2\">\n <div v-if=\"header\" class=\"border-b
|
|
|
4323
4367
|
/***/ ((module) => {
|
|
4324
4368
|
|
|
4325
4369
|
"use strict";
|
|
4326
|
-
module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"status === 'loading'\" class=\"max-w-5xl mx-auto text-center\">\n <img src=\"images/loader.gif\" class=\"inline mt-10\">\n </div>\n <div v-if=\"dashboard && status !== 'loading'\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center w-full\" v-if=\"!showEditor\">\n <h2 class=\"mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink\">{{title}}</h2>\n <div class=\"flex gap-2\">\n <button\n @click=\"showEditor = true\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\">\n <img src=\"images/edit.svg\" class=\"inline h-[1.25em] mr-1\" /> Edit\n </button>\n\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center rounded-md bg-ultramarine-600 px-4 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n <svg class=\"inline h-[1.25em] mr-1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"m670-140 160-100-160-100v200ZM240-600h480v-80H240v80ZM720-40q-83 0-141.5-58.5T520-240q0-83 58.5-141.5T720-440q83 0 141.5 58.5T920-240q0 83-58.5 141.5T720-40ZM120-80v-680q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v267q-19-9-39-15t-41-9v-243H200v562h243q5 31 15.5 59T486-86l-6 6-60-60-60 60-60-60-60 60-60-60-60 60Zm120-200h203q3-21 9-41t15-39H240v80Zm0-160h284q38-37 88.5-58.5T720-520H240v80Zm-40 242v-562 562Z\"/></svg>\n Evaluate\n </async-button>\n </div>\n </div>\n <div v-if=\"!showEditor\" class=\"mt-4 mb-4\">\n <div v-if=\"dashboardResults.length === 0\">\n <div class=\"flex flex-col items-center justify-center py-8\">\n <p class=\"text-gray-700 text-base mb-4\">This dashboard hasn't been evaluated yet.</p>\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"rounded-md bg-ultramarine-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n Evaluate Dashboard\n </async-button>\n </div>\n </div>\n <div v-else>\n <div class=\"relative\">\n <
|
|
4370
|
+
module.exports = "<div class=\"dashboard px-1\">\n <div v-if=\"status === 'loading'\" class=\"max-w-5xl mx-auto text-center\">\n <img src=\"images/loader.gif\" class=\"inline mt-10\">\n </div>\n <div v-if=\"dashboard && status !== 'loading'\" class=\"max-w-5xl mx-auto\">\n <div class=\"flex items-center w-full\" v-if=\"!showEditor\">\n <h2 class=\"mt-4 mb-4 text-gray-900 font-semibold text-xl grow shrink\">{{title}}</h2>\n <div class=\"flex gap-2\">\n <button\n @click=\"showEditor = true\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center rounded-md bg-ultramarine-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\">\n <img src=\"images/edit.svg\" class=\"inline h-[1.25em] mr-1\" /> Edit\n </button>\n\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"flex items-center rounded-md bg-ultramarine-600 px-4 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n <svg class=\"inline h-[1.25em] mr-1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"m670-140 160-100-160-100v200ZM240-600h480v-80H240v80ZM720-40q-83 0-141.5-58.5T520-240q0-83 58.5-141.5T720-440q83 0 141.5 58.5T920-240q0 83-58.5 141.5T720-40ZM120-80v-680q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v267q-19-9-39-15t-41-9v-243H200v562h243q5 31 15.5 59T486-86l-6 6-60-60-60 60-60-60-60 60-60-60-60 60Zm120-200h203q3-21 9-41t15-39H240v80Zm0-160h284q38-37 88.5-58.5T720-520H240v80Zm-40 242v-562 562Z\"/></svg>\n Evaluate\n </async-button>\n </div>\n </div>\n <div v-if=\"!showEditor\" class=\"mt-4 mb-4\">\n <div v-if=\"dashboardResults.length === 0\">\n <div class=\"flex flex-col items-center justify-center py-8\">\n <p class=\"text-gray-700 text-base mb-4\">This dashboard hasn't been evaluated yet.</p>\n <async-button\n @click=\"evaluateDashboard\"\n type=\"button\"\n :disabled=\"status === 'evaluating'\"\n class=\"rounded-md bg-ultramarine-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:cursor-not-allowed disabled:bg-gray-600\"\n >\n Evaluate Dashboard\n </async-button>\n </div>\n </div>\n <div v-else>\n <div class=\"relative\">\n <dashboard-result\n :key=\"dashboardResult.finishedEvaluatingAt\"\n :result=\"dashboardResult.result\"\n :finishedEvaluatingAt=\"dashboardResult.finishedEvaluatingAt\"\n @fullscreen=\"showDetailModal = true\"\n class=\"h-[40vh]\"\n >\n </dashboard-result>\n </div>\n </div>\n </div>\n <div v-if=\"showEditor\" class=\"mt-4\">\n <edit-dashboard\n :dashboardId=\"dashboard._id\"\n :code=\"code\"\n :currentDescription=\"description\"\n :currentTitle=\"title\"\n @close=\"showEditor=false;\"\n @update=\"updateCode\"\n @clearError=\"errorMessage = null\"></edit-dashboard>\n </div>\n <div v-if=\"errorMessage\" class=\"rounded-md bg-red-50 p-4 mt-4\">\n <div class=\"flex\">\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n <div class=\"ml-3\">\n <h3 class=\"text-sm font-medium text-red-800\">{{errorMessage}}</h3>\n </div>\n </div>\n </div>\n\n </div>\n <div v-if=\"!dashboard && status !== 'loading'\">\n No dashboard with the given id could be found.\n </div>\n</div>\n\n<modal\n v-if=\"showDetailModal\"\n containerClass=\"!h-[90vh] !w-[90vw]\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Dashboard Details\"\n>\n <template #body>\n <div class=\"absolute font-mono right-1 top-1 cursor-pointer text-xl\" @click=\"showDetailModal = false;\" role=\"button\" aria-label=\"Close modal\">×</div>\n <div class=\"h-full overflow-auto\">\n <dashboard-result\n v-if=\"dashboardResult\"\n :result=\"dashboardResult.result\"\n :finishedEvaluatingAt=\"dashboardResult.finishedEvaluatingAt\"\n :fullscreen=\"true\"\n :responsive=\"true\">\n </dashboard-result>\n </div>\n </template>\n</modal>\n";
|
|
4327
4371
|
|
|
4328
4372
|
/***/ }),
|
|
4329
4373
|
|
|
@@ -4345,7 +4389,7 @@ module.exports = "<div class=\"p-4 bg-gray-100 rounded-lg shadow-lg\">\n <div
|
|
|
4345
4389
|
/***/ ((module) => {
|
|
4346
4390
|
|
|
4347
4391
|
"use strict";
|
|
4348
|
-
module.exports = "<div class=\"dashboards max-w-5xl mx-auto mt-8\">\n <div v-if=\"status === 'loaded' && dashboards.length === 0\">\n
|
|
4392
|
+
module.exports = "<div class=\"dashboards max-w-5xl mx-auto mt-8\">\n <div v-if=\"status === 'loading'\" class=\"text-center mt-4\">\n <svg\n class=\"inline w-8 h-8 animate-spin text-ultramarine-600\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\"\n ></path>\n </svg>\n </div>\n <div v-if=\"status === 'loaded' && dashboards.length === 0\">\n <div class=\"text-center\">\n <h3 class=\"mt-2 text-sm font-semibold text-gray-900\">No dashboards yet</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Get started by creating a new dashboard.</p>\n <div class=\"mt-6\">\n <button type=\"button\" class=\"inline-flex items-center rounded-md bg-ultramarine-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">\n <svg class=\"-ml-0.5 mr-1.5 h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z\" />\n </svg>\n New Dashboard\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"px-4 sm:px-6 lg:px-8\">\n <div class=\"sm:flex sm:items-center\">\n <div class=\"sm:flex-auto\">\n <h1 class=\"text-base font-semibold leading-6 text-gray-900\">Dashboards</h1>\n </div>\n <div class=\"mt-4 sm:ml-16 sm:mt-0 sm:flex-none\">\n <button\n type=\"button\"\n @click=\"showCreateDashboardModal = true\"\n class=\"block rounded-md bg-ultramarine-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600\">Create New Dashboard</button>\n </div>\n </div>\n <div class=\"mt-8 flow-root\">\n <div class=\"-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n <div class=\"inline-block min-w-full py-2 align-middle\">\n <table class=\"min-w-full divide-y divide-gray-300\">\n <thead>\n <tr>\n <th scope=\"col\" class=\"py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8\">Title</th>\n <th scope=\"col\" class=\"px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-[50%]\">Description</th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8\">\n </th>\n </tr>\n </thead>\n <tbody class=\"divide-y divide-gray-200 bg-white\">\n <tr v-for=\"dashboard in dashboards\">\n <td class=\"whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8\">{{dashboard.title}}</td>\n <td class=\"whitespace-nowrap px-3 py-4 text-sm text-gray-500 truncate w-[50%]\">{{dashboard.description}}</td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'/dashboard/' + dashboard._id + '?edit=true'\"\n class=\"text-ultramarine-600 hover:text-ultramarine-900\">\n Edit\n </router-link>\n </td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <router-link\n :to=\"'/dashboard/' + dashboard._id\"\n class=\"text-ultramarine-600 hover:text-ultramarine-900\">\n View\n </router-link>\n </td>\n <td class=\"relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8\">\n <button\n @click=\"showDeleteDashboardModal=dashboard\"\n class=\"text-ultramarine-600 hover:text-ultramarine-900\">\n Delete\n </button>\n </td>\n </tr>\n\n <!-- More people... -->\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n\n <modal v-if=\"showCreateDashboardModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"showCreateDashboardModal = false;\">×</div>\n\n <create-dashboard @close=\"insertNewDashboard\"></create-dashboard>\n </template>\n </modal>\n\n <modal v-if=\"showDeleteDashboardModal\">\n <template v-slot:body>\n <div class=\"modal-exit\" @click=\"showDeleteDashboardModal = null;\">×</div>\n <h2>Are you sure you want to delete this dashboard titled {{showDeleteDashboardModal.title}}?</h2>\n <div class=\"flex space-x-2\">\n <button class=\"px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500\" @click=\"deleteDashboard(showDeleteDashboardModal)\">Yes, delete</button>\n <button class=\"px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-600\" @click=\"showDeleteDashboardModal=null;\">Cancel</button>\n </div>\n </template>\n </modal>\n </div>\n</div>";
|
|
4349
4393
|
|
|
4350
4394
|
/***/ }),
|
|
4351
4395
|
|
|
@@ -14837,7 +14881,7 @@ var bson = /*#__PURE__*/Object.freeze({
|
|
|
14837
14881
|
/***/ ((module) => {
|
|
14838
14882
|
|
|
14839
14883
|
"use strict";
|
|
14840
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.
|
|
14884
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.0.117","description":"A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.","homepage":"https://studio.mongoosejs.io/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"dependencies":{"archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"0.0.26","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vanillatoasts":"^1.6.0","vue":"3.x","webpack":"5.x"},"peerDependencies":{"bson":"^5.5.1 || 6.x","express":"4.x","mongoose":"7.x || 8.x"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongoose":"8.x"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js"}}');
|
|
14841
14885
|
|
|
14842
14886
|
/***/ })
|
|
14843
14887
|
|
package/frontend/public/tw.css
CHANGED
|
@@ -882,6 +882,10 @@ video {
|
|
|
882
882
|
height: 32px;
|
|
883
883
|
}
|
|
884
884
|
|
|
885
|
+
.h-\[40vh\] {
|
|
886
|
+
height: 40vh;
|
|
887
|
+
}
|
|
888
|
+
|
|
885
889
|
.h-\[42px\] {
|
|
886
890
|
height: 42px;
|
|
887
891
|
}
|
|
@@ -898,6 +902,10 @@ video {
|
|
|
898
902
|
max-height: 50vh;
|
|
899
903
|
}
|
|
900
904
|
|
|
905
|
+
.min-h-0 {
|
|
906
|
+
min-height: 0px;
|
|
907
|
+
}
|
|
908
|
+
|
|
901
909
|
.\!w-0 {
|
|
902
910
|
width: 0px !important;
|
|
903
911
|
}
|
|
@@ -970,6 +978,10 @@ video {
|
|
|
970
978
|
max-width: 64rem;
|
|
971
979
|
}
|
|
972
980
|
|
|
981
|
+
.max-w-\[calc\(100vw-3rem\)\] {
|
|
982
|
+
max-width: calc(100vw - 3rem);
|
|
983
|
+
}
|
|
984
|
+
|
|
973
985
|
.max-w-\[calc\(100vw-4rem\)\] {
|
|
974
986
|
max-width: calc(100vw - 4rem);
|
|
975
987
|
}
|
|
@@ -1028,6 +1040,16 @@ video {
|
|
|
1028
1040
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1029
1041
|
}
|
|
1030
1042
|
|
|
1043
|
+
@keyframes spin {
|
|
1044
|
+
to {
|
|
1045
|
+
transform: rotate(360deg);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.animate-spin {
|
|
1050
|
+
animation: spin 1s linear infinite;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1031
1053
|
.cursor-not-allowed {
|
|
1032
1054
|
cursor: not-allowed;
|
|
1033
1055
|
}
|
|
@@ -1784,6 +1806,11 @@ video {
|
|
|
1784
1806
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
|
1785
1807
|
}
|
|
1786
1808
|
|
|
1809
|
+
.text-ultramarine-600 {
|
|
1810
|
+
--tw-text-opacity: 1;
|
|
1811
|
+
color: rgb(24 35 255 / var(--tw-text-opacity));
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1787
1814
|
.accent-sky-600 {
|
|
1788
1815
|
accent-color: #0284c7;
|
|
1789
1816
|
}
|
|
@@ -1792,6 +1819,14 @@ video {
|
|
|
1792
1819
|
opacity: 0.5;
|
|
1793
1820
|
}
|
|
1794
1821
|
|
|
1822
|
+
.opacity-25 {
|
|
1823
|
+
opacity: 0.25;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
.opacity-75 {
|
|
1827
|
+
opacity: 0.75;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1795
1830
|
.shadow {
|
|
1796
1831
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
1797
1832
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
@@ -2069,6 +2104,11 @@ video {
|
|
|
2069
2104
|
color: rgb(10 87 87 / var(--tw-text-opacity));
|
|
2070
2105
|
}
|
|
2071
2106
|
|
|
2107
|
+
.hover\:text-ultramarine-900:hover {
|
|
2108
|
+
--tw-text-opacity: 1;
|
|
2109
|
+
color: rgb(6 14 172 / var(--tw-text-opacity));
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2072
2112
|
.focus\:z-10:focus {
|
|
2073
2113
|
z-index: 10;
|
|
2074
2114
|
}
|
|
@@ -2346,10 +2386,6 @@ video {
|
|
|
2346
2386
|
.md\:hidden {
|
|
2347
2387
|
display: none;
|
|
2348
2388
|
}
|
|
2349
|
-
|
|
2350
|
-
.md\:p-3 {
|
|
2351
|
-
padding: 0.75rem;
|
|
2352
|
-
}
|
|
2353
2389
|
}
|
|
2354
2390
|
|
|
2355
2391
|
@media (min-width: 1024px) {
|
|
@@ -2370,6 +2406,10 @@ video {
|
|
|
2370
2406
|
width: 16rem;
|
|
2371
2407
|
}
|
|
2372
2408
|
|
|
2409
|
+
.lg\:max-w-\[calc\(100vw-15rem\)\] {
|
|
2410
|
+
max-width: calc(100vw - 15rem);
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2373
2413
|
.lg\:max-w-\[calc\(100vw-20rem\)\] {
|
|
2374
2414
|
max-width: calc(100vw - 20rem);
|
|
2375
2415
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<div class="relative flex items-start" :class="{'justify-end': message.role === 'user'}">
|
|
2
2
|
<div
|
|
3
|
-
class="min-w-0 max-w-[calc(100vw-
|
|
3
|
+
class="min-w-0 max-w-[calc(100vw-3rem)] lg:max-w-[calc(100vw-15rem)]"
|
|
4
4
|
:class="{'text-right': message.role === 'user'}">
|
|
5
5
|
|
|
6
|
-
<div class="text-sm text-gray-900
|
|
6
|
+
<div class="text-sm text-gray-900 rounded-md inline-block relative" :class="styleForMessage">
|
|
7
7
|
<div v-for="part in contentSplitByScripts">
|
|
8
8
|
<div v-if="part.type === 'text'" v-html="marked(part.content)">
|
|
9
9
|
</div>
|
|
10
10
|
<div v-else-if="part.type === 'code'">
|
|
11
|
-
<chat-message-script :message="message" :script="part.content" :language="part.language"></chat-message-script>
|
|
11
|
+
<chat-message-script :message="message" :script="part.content" :language="part.language" @copyMessage="copyMessage"></chat-message-script>
|
|
12
12
|
</div>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const api = require('../../api');
|
|
4
4
|
const marked = require('marked').marked;
|
|
5
|
+
const vanillatoasts = require('vanillatoasts');
|
|
5
6
|
const template = require('./chat-message.html');
|
|
6
7
|
|
|
7
8
|
module.exports = app => app.component('chat-message', {
|
|
@@ -9,7 +10,7 @@ module.exports = app => app.component('chat-message', {
|
|
|
9
10
|
props: ['message'],
|
|
10
11
|
computed: {
|
|
11
12
|
styleForMessage() {
|
|
12
|
-
return this.message.role === 'user' ? 'bg-gray-100' : '';
|
|
13
|
+
return this.message.role === 'user' ? 'p-3 bg-gray-100' : 'py-3 pr-3';
|
|
13
14
|
},
|
|
14
15
|
contentSplitByScripts() {
|
|
15
16
|
const content = this.message.content;
|
|
@@ -61,6 +62,37 @@ module.exports = app => app.component('chat-message', {
|
|
|
61
62
|
});
|
|
62
63
|
message.executionResult = chatMessage.executionResult;
|
|
63
64
|
console.log(message);
|
|
65
|
+
},
|
|
66
|
+
async copyMessage() {
|
|
67
|
+
const parts = this.contentSplitByScripts;
|
|
68
|
+
let output = '';
|
|
69
|
+
for (const part of parts) {
|
|
70
|
+
if (part.type === 'text') {
|
|
71
|
+
output += part.content + '\n';
|
|
72
|
+
} else if (part.type === 'code') {
|
|
73
|
+
let result = this.message.executionResult?.output;
|
|
74
|
+
if (result != null && typeof result === 'object') {
|
|
75
|
+
result = JSON.stringify(result, null, 2);
|
|
76
|
+
}
|
|
77
|
+
if (result) {
|
|
78
|
+
let executionOutput = this.message.executionResult?.output;
|
|
79
|
+
if (executionOutput != null && typeof executionOutput === 'object') {
|
|
80
|
+
executionOutput = JSON.stringify(executionOutput, null, 2);
|
|
81
|
+
}
|
|
82
|
+
if (executionOutput) {
|
|
83
|
+
output += '```\n' + executionOutput + '\n```\n';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await navigator.clipboard.writeText(output.trim());
|
|
89
|
+
vanillatoasts.create({
|
|
90
|
+
title: 'Message output copied!',
|
|
91
|
+
type: 'success',
|
|
92
|
+
timeout: 3000,
|
|
93
|
+
icon: 'images/success.png',
|
|
94
|
+
positionClass: 'bottomRight'
|
|
95
|
+
});
|
|
64
96
|
}
|
|
65
97
|
}
|
|
66
98
|
});
|
|
@@ -50,6 +50,11 @@
|
|
|
50
50
|
@click="openCreateDashboardModal(); showDropdown = false">
|
|
51
51
|
Create Dashboard
|
|
52
52
|
</button>
|
|
53
|
+
<button
|
|
54
|
+
class="block w-full text-left px-4 py-2 text-xs text-gray-700 hover:bg-gray-100"
|
|
55
|
+
@click="$emit('copyMessage'); showDropdown = false">
|
|
56
|
+
Copy Full Message
|
|
57
|
+
</button>
|
|
53
58
|
</div>
|
|
54
59
|
</div>
|
|
55
60
|
</div>
|
|
@@ -7,6 +7,7 @@ const vanillatoasts = require('vanillatoasts');
|
|
|
7
7
|
module.exports = app => app.component('chat-message-script', {
|
|
8
8
|
template,
|
|
9
9
|
props: ['message', 'script', 'language'],
|
|
10
|
+
emits: ['copyMessage'],
|
|
10
11
|
data() {
|
|
11
12
|
return {
|
|
12
13
|
activeTab: 'code',
|
|
@@ -82,9 +83,13 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
82
83
|
this.$router.push('/dashboard/' + dashboard._id);
|
|
83
84
|
},
|
|
84
85
|
async copyOutput() {
|
|
85
|
-
|
|
86
|
+
let output = this.message.executionResult.output;
|
|
87
|
+
if (output != null && typeof output === 'object') {
|
|
88
|
+
output = JSON.stringify(output, null, 2);
|
|
89
|
+
}
|
|
90
|
+
await navigator.clipboard.writeText(output);
|
|
86
91
|
vanillatoasts.create({
|
|
87
|
-
title: '
|
|
92
|
+
title: 'Code output copied!',
|
|
88
93
|
type: 'success',
|
|
89
94
|
timeout: 3000,
|
|
90
95
|
icon: 'images/success.png',
|
|
@@ -72,8 +72,9 @@
|
|
|
72
72
|
<form @submit.prevent="sendMessage" :disabled="sendingMessage" class="flex gap-2 items-end justify-end">
|
|
73
73
|
<textarea
|
|
74
74
|
v-model="newMessage"
|
|
75
|
-
placeholder="Ask something..."
|
|
75
|
+
:placeholder="sendingMessage ? 'Sending...' : 'Ask something...'"
|
|
76
76
|
class="flex-1 border rounded px-4 py-2 resize-none overflow-y-auto"
|
|
77
|
+
:disabled="sendingMessage"
|
|
77
78
|
rows="1"
|
|
78
79
|
ref="messageInput"
|
|
79
80
|
@input="adjustTextareaHeight"
|
|
@@ -21,6 +21,8 @@ module.exports = app => app.component('chat', {
|
|
|
21
21
|
async sendMessage() {
|
|
22
22
|
this.sendingMessage = true;
|
|
23
23
|
try {
|
|
24
|
+
const content = this.newMessage;
|
|
25
|
+
this.newMessage = '';
|
|
24
26
|
if (!this.chatThreadId) {
|
|
25
27
|
const { chatThread } = await api.ChatThread.createChatThread();
|
|
26
28
|
this.chatThreads.unshift(chatThread);
|
|
@@ -29,7 +31,7 @@ module.exports = app => app.component('chat', {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
this.chatMessages.push({
|
|
32
|
-
content
|
|
34
|
+
content,
|
|
33
35
|
role: 'user'
|
|
34
36
|
});
|
|
35
37
|
|
|
@@ -41,7 +43,7 @@ module.exports = app => app.component('chat', {
|
|
|
41
43
|
|
|
42
44
|
const { chatMessages, chatThread } = await api.ChatThread.createChatMessage({
|
|
43
45
|
chatThreadId: this.chatThreadId,
|
|
44
|
-
content
|
|
46
|
+
content
|
|
45
47
|
});
|
|
46
48
|
this.chatMessages.push(chatMessages[1]);
|
|
47
49
|
for (const thread of this.chatThreads) {
|
|
@@ -41,18 +41,13 @@
|
|
|
41
41
|
</div>
|
|
42
42
|
<div v-else>
|
|
43
43
|
<div class="relative">
|
|
44
|
-
<button
|
|
45
|
-
class="absolute top-2 right-2 px-2 py-1 text-xs bg-blue-500 text-white border-none rounded cursor-pointer hover:bg-blue-600 transition-colors flex items-center"
|
|
46
|
-
@click="openDetailModal"
|
|
47
|
-
aria-label="Expand dashboard result">
|
|
48
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
49
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5" />
|
|
50
|
-
</svg>
|
|
51
|
-
</button>
|
|
52
44
|
<dashboard-result
|
|
53
45
|
:key="dashboardResult.finishedEvaluatingAt"
|
|
54
46
|
:result="dashboardResult.result"
|
|
55
|
-
:finishedEvaluatingAt="dashboardResult.finishedEvaluatingAt"
|
|
47
|
+
:finishedEvaluatingAt="dashboardResult.finishedEvaluatingAt"
|
|
48
|
+
@fullscreen="showDetailModal = true"
|
|
49
|
+
class="h-[40vh]"
|
|
50
|
+
>
|
|
56
51
|
</dashboard-result>
|
|
57
52
|
</div>
|
|
58
53
|
</div>
|
|
@@ -64,7 +59,8 @@
|
|
|
64
59
|
:currentDescription="description"
|
|
65
60
|
:currentTitle="title"
|
|
66
61
|
@close="showEditor=false;"
|
|
67
|
-
@update="updateCode"
|
|
62
|
+
@update="updateCode"
|
|
63
|
+
@clearError="errorMessage = null"></edit-dashboard>
|
|
68
64
|
</div>
|
|
69
65
|
<div v-if="errorMessage" class="rounded-md bg-red-50 p-4 mt-4">
|
|
70
66
|
<div class="flex">
|
|
@@ -98,7 +94,9 @@
|
|
|
98
94
|
<dashboard-result
|
|
99
95
|
v-if="dashboardResult"
|
|
100
96
|
:result="dashboardResult.result"
|
|
101
|
-
:finishedEvaluatingAt="dashboardResult.finishedEvaluatingAt"
|
|
97
|
+
:finishedEvaluatingAt="dashboardResult.finishedEvaluatingAt"
|
|
98
|
+
:fullscreen="true"
|
|
99
|
+
:responsive="true">
|
|
102
100
|
</dashboard-result>
|
|
103
101
|
</div>
|
|
104
102
|
</template>
|
|
@@ -35,22 +35,22 @@ module.exports = app => app.component('dashboard', {
|
|
|
35
35
|
},
|
|
36
36
|
async evaluateDashboard() {
|
|
37
37
|
this.status = 'evaluating';
|
|
38
|
+
this.errorMessage = null;
|
|
38
39
|
try {
|
|
39
40
|
const { dashboard, dashboardResult, error } = await api.Dashboard.getDashboard({ dashboardId: this.dashboardId, evaluate: true });
|
|
40
41
|
this.dashboard = dashboard;
|
|
41
|
-
if (error) {
|
|
42
|
-
this.errorMessage = error.message;
|
|
43
|
-
}
|
|
44
42
|
this.code = this.dashboard.code;
|
|
45
43
|
this.title = this.dashboard.title;
|
|
46
44
|
this.description = this.dashboard.description ?? '';
|
|
47
|
-
|
|
45
|
+
if (dashboardResult) {
|
|
46
|
+
this.dashboardResults.unshift(dashboardResult);
|
|
47
|
+
}
|
|
48
|
+
if (error) {
|
|
49
|
+
this.errorMessage = error.message;
|
|
50
|
+
}
|
|
48
51
|
} finally {
|
|
49
52
|
this.status = 'loaded';
|
|
50
53
|
}
|
|
51
|
-
},
|
|
52
|
-
openDetailModal() {
|
|
53
|
-
this.showDetailModal = true;
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
computed: {
|
|
@@ -6,6 +6,7 @@ const template = require('./edit-dashboard.html');
|
|
|
6
6
|
module.exports = app => app.component('edit-dashboard', {
|
|
7
7
|
template: template,
|
|
8
8
|
props: ['dashboardId', 'code', 'currentDescription', 'currentTitle'],
|
|
9
|
+
emits: ['close', 'clearError'],
|
|
9
10
|
data: function() {
|
|
10
11
|
return {
|
|
11
12
|
status: 'loaded',
|
|
@@ -19,6 +20,7 @@ module.exports = app => app.component('edit-dashboard', {
|
|
|
19
20
|
this.$emit('close');
|
|
20
21
|
},
|
|
21
22
|
async updateCode() {
|
|
23
|
+
this.$emit('clearError');
|
|
22
24
|
this.status = 'loading';
|
|
23
25
|
try {
|
|
24
26
|
const { doc, result, error } = await api.Dashboard.updateDashboard({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div :class="responsive ? 'h-full' : ''">
|
|
2
|
-
<div v-if="header" class="border-b border-gray-100 px-2 pb-2 flex items-center">
|
|
2
|
+
<div v-if="header && !fullscreen" class="border-b border-gray-100 px-2 pb-2 flex items-center gap-1">
|
|
3
3
|
<div class="text-xl font-bold">{{header}}</div>
|
|
4
4
|
<button
|
|
5
5
|
class="ml-auto px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors"
|
|
@@ -7,16 +7,32 @@
|
|
|
7
7
|
title="Export PNG">
|
|
8
8
|
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.5em;" viewBox="0 -960 960 960" fill="currentColor"><path d="M280-280h400v-80H280v80Zm200-120 160-160-56-56-64 62v-166h-80v166l-64-62-56 56 160 160Zm0 320q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
|
9
9
|
</button>
|
|
10
|
+
<button
|
|
11
|
+
class="px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors flex items-center"
|
|
12
|
+
@click="$emit('fullscreen')"
|
|
13
|
+
aria-label="Expand dashboard result">
|
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.5em" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
15
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5" />
|
|
16
|
+
</svg>
|
|
17
|
+
</button>
|
|
10
18
|
</div>
|
|
11
|
-
<div v-else class="border-b border-gray-100 px-2 pb-2 text-right">
|
|
19
|
+
<div v-else-if="!fullscreen" class="pt-1 border-b border-gray-100 px-2 pb-2 text-right flex items-center justify-end gap-1 w-full">
|
|
12
20
|
<button
|
|
13
|
-
class="
|
|
21
|
+
class="px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors"
|
|
14
22
|
@click="exportPNG"
|
|
15
23
|
title="Export PNG">
|
|
16
24
|
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.5em;" viewBox="0 -960 960 960" fill="currentColor"><path d="M280-280h400v-80H280v80Zm200-120 160-160-56-56-64 62v-166h-80v166l-64-62-56 56 160 160Zm0 320q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
|
17
25
|
</button>
|
|
26
|
+
<button
|
|
27
|
+
class="px-2 py-1 text-xs bg-ultramarine-600 text-white border-none rounded cursor-pointer hover:bg-ultramarine-500 transition-colors flex items-center"
|
|
28
|
+
@click="$emit('fullscreen')"
|
|
29
|
+
aria-label="Expand dashboard result">
|
|
30
|
+
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.5em" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
31
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 1v4m0 0h-4m4 0l-5-5" />
|
|
32
|
+
</svg>
|
|
33
|
+
</button>
|
|
18
34
|
</div>
|
|
19
|
-
<div
|
|
20
|
-
<canvas ref="chart"></canvas>
|
|
35
|
+
<div :class="responsive ? 'relative h-full min-h-0' : ''">
|
|
36
|
+
<canvas ref="chart" class="block w-full h-full"></canvas>
|
|
21
37
|
</div>
|
|
22
38
|
</div>
|
|
@@ -4,9 +4,11 @@ const template = require('./dashboard-chart.html');
|
|
|
4
4
|
|
|
5
5
|
module.exports = app => app.component('dashboard-chart', {
|
|
6
6
|
template: template,
|
|
7
|
-
props: ['value', '
|
|
7
|
+
props: ['value', 'fullscreen'],
|
|
8
|
+
emits: ['fullscreen'],
|
|
8
9
|
data: () => ({
|
|
9
|
-
chart: null
|
|
10
|
+
chart: null,
|
|
11
|
+
showDetailModal: false
|
|
10
12
|
}),
|
|
11
13
|
mounted() {
|
|
12
14
|
const ctx = this.$refs.chart.getContext('2d');
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
<component
|
|
13
13
|
class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl"
|
|
14
14
|
:is="getComponentForValue(result)"
|
|
15
|
-
:value="result"
|
|
15
|
+
:value="result"
|
|
16
|
+
:fullscreen="fullscreen"
|
|
17
|
+
@fullscreen="$emit('fullscreen')">
|
|
16
18
|
</component>
|
|
17
19
|
</div>
|
|
18
|
-
<div class="text-right text-sm text-gray-700 mt-1" v-if="finishedEvaluatingAt">
|
|
20
|
+
<div class="text-right text-sm text-gray-700 mt-1" v-if="finishedEvaluatingAt && !fullscreen">
|
|
19
21
|
Last Evaluated: {{ format.isoToLongDateTime(finishedEvaluatingAt) }}
|
|
20
22
|
</div>
|
|
21
23
|
</div>
|
|
@@ -7,7 +7,8 @@ const template = require('./dashboard-result.html');
|
|
|
7
7
|
|
|
8
8
|
module.exports = app => app.component('dashboard-result', {
|
|
9
9
|
template: template,
|
|
10
|
-
props: ['result', 'finishedEvaluatingAt'],
|
|
10
|
+
props: ['result', 'finishedEvaluatingAt', 'fullscreen'],
|
|
11
|
+
emits: ['fullscreen'],
|
|
11
12
|
mounted: async function() {
|
|
12
13
|
},
|
|
13
14
|
methods: {
|
|
@@ -1,97 +1,119 @@
|
|
|
1
1
|
<div class="dashboards max-w-5xl mx-auto mt-8">
|
|
2
|
-
<div v-if="status === '
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<div v-if="status === 'loading'" class="text-center mt-4">
|
|
3
|
+
<svg
|
|
4
|
+
class="inline w-8 h-8 animate-spin text-ultramarine-600"
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
fill="none"
|
|
7
|
+
viewBox="0 0 24 24"
|
|
8
|
+
>
|
|
9
|
+
<circle
|
|
10
|
+
class="opacity-25"
|
|
11
|
+
cx="12"
|
|
12
|
+
cy="12"
|
|
13
|
+
r="10"
|
|
14
|
+
stroke="currentColor"
|
|
15
|
+
stroke-width="4"
|
|
16
|
+
></circle>
|
|
17
|
+
<path
|
|
18
|
+
class="opacity-75"
|
|
19
|
+
fill="currentColor"
|
|
20
|
+
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
|
|
21
|
+
></path>
|
|
22
|
+
</svg>
|
|
23
|
+
</div>
|
|
24
|
+
<div v-if="status === 'loaded' && dashboards.length === 0">
|
|
25
|
+
<div class="text-center">
|
|
26
|
+
<h3 class="mt-2 text-sm font-semibold text-gray-900">No dashboards yet</h3>
|
|
27
|
+
<p class="mt-1 text-sm text-gray-500">Get started by creating a new dashboard.</p>
|
|
28
|
+
<div class="mt-6">
|
|
29
|
+
<button type="button" class="inline-flex items-center rounded-md bg-ultramarine-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
30
|
+
<svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
31
|
+
<path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z" />
|
|
32
|
+
</svg>
|
|
33
|
+
New Dashboard
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
13
36
|
</div>
|
|
14
37
|
</div>
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
38
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
<div class="px-4 sm:px-6 lg:px-8">
|
|
40
|
+
<div class="sm:flex sm:items-center">
|
|
41
|
+
<div class="sm:flex-auto">
|
|
42
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Dashboards</h1>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
@click="showCreateDashboardModal = true"
|
|
48
|
+
class="block rounded-md bg-ultramarine-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">Create New Dashboard</button>
|
|
49
|
+
</div>
|
|
28
50
|
</div>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
</
|
|
42
|
-
</
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
</
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
</
|
|
68
|
-
</
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
</
|
|
73
|
-
</
|
|
51
|
+
<div class="mt-8 flow-root">
|
|
52
|
+
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
|
53
|
+
<div class="inline-block min-w-full py-2 align-middle">
|
|
54
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
55
|
+
<thead>
|
|
56
|
+
<tr>
|
|
57
|
+
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8">Title</th>
|
|
58
|
+
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-[50%]">Description</th>
|
|
59
|
+
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8">
|
|
60
|
+
</th>
|
|
61
|
+
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8">
|
|
62
|
+
</th>
|
|
63
|
+
</tr>
|
|
64
|
+
</thead>
|
|
65
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
66
|
+
<tr v-for="dashboard in dashboards">
|
|
67
|
+
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{dashboard.title}}</td>
|
|
68
|
+
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500 truncate w-[50%]">{{dashboard.description}}</td>
|
|
69
|
+
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
|
|
70
|
+
<router-link
|
|
71
|
+
:to="'/dashboard/' + dashboard._id + '?edit=true'"
|
|
72
|
+
class="text-ultramarine-600 hover:text-ultramarine-900">
|
|
73
|
+
Edit
|
|
74
|
+
</router-link>
|
|
75
|
+
</td>
|
|
76
|
+
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
|
|
77
|
+
<router-link
|
|
78
|
+
:to="'/dashboard/' + dashboard._id"
|
|
79
|
+
class="text-ultramarine-600 hover:text-ultramarine-900">
|
|
80
|
+
View
|
|
81
|
+
</router-link>
|
|
82
|
+
</td>
|
|
83
|
+
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
|
|
84
|
+
<button
|
|
85
|
+
@click="showDeleteDashboardModal=dashboard"
|
|
86
|
+
class="text-ultramarine-600 hover:text-ultramarine-900">
|
|
87
|
+
Delete
|
|
88
|
+
</button>
|
|
89
|
+
</td>
|
|
90
|
+
</tr>
|
|
91
|
+
|
|
92
|
+
<!-- More people... -->
|
|
93
|
+
</tbody>
|
|
94
|
+
</table>
|
|
95
|
+
</div>
|
|
74
96
|
</div>
|
|
75
97
|
</div>
|
|
76
98
|
</div>
|
|
77
|
-
</div>
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<create-dashboard @close="insertNewDashboard"></create-dashboard>
|
|
84
|
-
</template>
|
|
85
|
-
</modal>
|
|
100
|
+
<modal v-if="showCreateDashboardModal">
|
|
101
|
+
<template v-slot:body>
|
|
102
|
+
<div class="modal-exit" @click="showCreateDashboardModal = false;">×</div>
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
<create-dashboard @close="insertNewDashboard"></create-dashboard>
|
|
105
|
+
</template>
|
|
106
|
+
</modal>
|
|
107
|
+
|
|
108
|
+
<modal v-if="showDeleteDashboardModal">
|
|
109
|
+
<template v-slot:body>
|
|
110
|
+
<div class="modal-exit" @click="showDeleteDashboardModal = null;">×</div>
|
|
111
|
+
<h2>Are you sure you want to delete this dashboard titled {{showDeleteDashboardModal.title}}?</h2>
|
|
112
|
+
<div class="flex space-x-2">
|
|
113
|
+
<button class="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500" @click="deleteDashboard(showDeleteDashboardModal)">Yes, delete</button>
|
|
114
|
+
<button class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-600" @click="showDeleteDashboardModal=null;">Cancel</button>
|
|
115
|
+
</div>
|
|
116
|
+
</template>
|
|
117
|
+
</modal>
|
|
118
|
+
</div>
|
|
97
119
|
</div>
|
|
@@ -194,13 +194,13 @@ module.exports = app => app.component('models', {
|
|
|
194
194
|
this.query.search = this.searchText;
|
|
195
195
|
const query = this.query;
|
|
196
196
|
const newUrl = this.$router.resolve({ query }).href;
|
|
197
|
-
|
|
197
|
+
this.$router.push({ query });
|
|
198
198
|
} else {
|
|
199
199
|
this.filter = {};
|
|
200
200
|
delete this.query.search;
|
|
201
201
|
const query = this.query;
|
|
202
202
|
const newUrl = this.$router.resolve({ query }).href;
|
|
203
|
-
|
|
203
|
+
this.$router.push({ query });
|
|
204
204
|
}
|
|
205
205
|
this.documents = [];
|
|
206
206
|
this.status = 'loading';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.117",
|
|
4
4
|
"description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
|
|
5
5
|
"homepage": "https://studio.mongoosejs.io/",
|
|
6
6
|
"repository": {
|