@mongoosejs/studio 0.2.13 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/actions/ChatMessage/executeScript.js +5 -1
- package/backend/actions/ChatThread/createChatMessage.js +2 -1
- package/backend/actions/ChatThread/streamChatMessage.js +2 -2
- package/eslint.config.js +4 -1
- package/frontend/public/app.js +24642 -543
- package/frontend/public/dark-theme.css +365 -0
- package/frontend/public/images/mongoose-studio.svg +4 -0
- package/frontend/public/index.html +21 -1
- package/frontend/public/style.css +5 -7
- package/frontend/public/theme-variables.css +294 -0
- package/frontend/public/tw.css +305 -252
- package/frontend/src/ace-editor/ace-editor.html +4 -0
- package/frontend/src/ace-editor/ace-editor.js +89 -0
- package/frontend/src/aceEditor.js +69 -0
- package/frontend/src/chat/chat-message/chat-message.html +1 -1
- package/frontend/src/chat/chat-message/chat-message.js +1 -1
- package/frontend/src/chat/chat-message-script/chat-message-script.html +51 -34
- package/frontend/src/chat/chat-message-script/chat-message-script.js +12 -55
- package/frontend/src/chat/chat.html +68 -39
- package/frontend/src/chat/chat.js +26 -2
- package/frontend/src/clone-document/clone-document.html +7 -2
- package/frontend/src/clone-document/clone-document.js +1 -8
- package/frontend/src/create-dashboard/create-dashboard.html +11 -6
- package/frontend/src/create-dashboard/create-dashboard.js +0 -7
- package/frontend/src/create-document/create-document.html +15 -9
- package/frontend/src/create-document/create-document.js +5 -12
- package/frontend/src/dashboard/dashboard.html +14 -12
- package/frontend/src/dashboard/dashboard.js +12 -4
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +13 -7
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.js +13 -21
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.html +19 -17
- package/frontend/src/dashboard-result/dashboard-chart/dashboard-chart.js +97 -2
- package/frontend/src/dashboard-result/dashboard-map/dashboard-map.js +27 -3
- package/frontend/src/dashboard-result/dashboard-result.html +3 -3
- package/frontend/src/dashboards/dashboards.html +101 -109
- package/frontend/src/dashboards/dashboards.js +25 -1
- package/frontend/src/detail-default/detail-default.html +2 -2
- package/frontend/src/detail-default/detail-default.js +24 -3
- package/frontend/src/document/confirm-changes/confirm-changes.html +1 -1
- package/frontend/src/document/confirm-delete/confirm-delete.html +1 -1
- package/frontend/src/document/document.css +1 -1
- package/frontend/src/document/document.html +28 -28
- package/frontend/src/document/execute-script/execute-script.html +20 -21
- package/frontend/src/document/execute-script/execute-script.js +1 -43
- package/frontend/src/document-details/document-details.css +4 -9
- package/frontend/src/document-details/document-details.html +34 -33
- package/frontend/src/document-details/document-details.js +2 -53
- package/frontend/src/document-details/document-property/document-property.html +12 -12
- package/frontend/src/edit-array/edit-array.html +7 -6
- package/frontend/src/edit-array/edit-array.js +10 -50
- package/frontend/src/edit-boolean/edit-boolean.html +12 -12
- package/frontend/src/edit-date/edit-date.html +2 -2
- package/frontend/src/edit-default/edit-default.html +1 -1
- package/frontend/src/edit-string/edit-string.html +3 -3
- package/frontend/src/edit-subdocument/edit-subdocument.html +5 -3
- package/frontend/src/edit-subdocument/edit-subdocument.js +1 -15
- package/frontend/src/export-query-results/export-query-results.html +3 -3
- package/frontend/src/json-node/json-node.html +3 -3
- package/frontend/src/list-json/json-node.html +1 -1
- package/frontend/src/models/document-search/document-search.html +3 -3
- package/frontend/src/models/model-switcher/model-switcher.html +53 -0
- package/frontend/src/models/model-switcher/model-switcher.js +123 -0
- package/frontend/src/models/models.css +3 -10
- package/frontend/src/models/models.html +146 -80
- package/frontend/src/models/models.js +108 -4
- package/frontend/src/navbar/navbar.html +157 -97
- package/frontend/src/navbar/navbar.js +31 -12
- package/frontend/src/routes.js +1 -1
- package/frontend/src/splash/splash.html +5 -5
- package/frontend/src/task-single/task-single.html +29 -29
- package/frontend/src/task-single/task-single.js +10 -10
- package/frontend/src/tasks/task-details/task-details.html +38 -38
- package/frontend/src/tasks/task-details/task-details.js +7 -2
- package/frontend/src/tasks/tasks.html +36 -35
- package/frontend/src/tasks/tasks.js +2 -25
- package/frontend/src/team/new-invitation/new-invitation.html +8 -8
- package/frontend/src/team/team.html +27 -27
- package/frontend/src/update-document/update-document.html +7 -2
- package/frontend/src/update-document/update-document.js +2 -11
- package/package.json +2 -1
- package/tailwind.config.js +75 -11
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const template = require('./ace-editor.html');
|
|
4
|
+
const { createAceEditor, destroyAceEditor } = require('../aceEditor');
|
|
5
|
+
|
|
6
|
+
module.exports = app => app.component('ace-editor', {
|
|
7
|
+
template,
|
|
8
|
+
props: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: ''
|
|
12
|
+
},
|
|
13
|
+
// Support :value for explicit binding
|
|
14
|
+
value: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: ''
|
|
17
|
+
},
|
|
18
|
+
mode: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: 'javascript',
|
|
21
|
+
validator: (v) => ['javascript', 'json'].includes(v)
|
|
22
|
+
},
|
|
23
|
+
lineNumbers: {
|
|
24
|
+
type: Boolean,
|
|
25
|
+
default: true
|
|
26
|
+
},
|
|
27
|
+
readOnly: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false
|
|
30
|
+
},
|
|
31
|
+
wrap: {
|
|
32
|
+
type: Boolean,
|
|
33
|
+
default: false
|
|
34
|
+
},
|
|
35
|
+
minLines: { type: Number, default: null },
|
|
36
|
+
maxLines: { type: Number, default: null }
|
|
37
|
+
},
|
|
38
|
+
emits: ['input', 'update:modelValue'],
|
|
39
|
+
data() {
|
|
40
|
+
return { editor: null };
|
|
41
|
+
},
|
|
42
|
+
mounted() {
|
|
43
|
+
this.$nextTick(() => {
|
|
44
|
+
const container = this.$refs.container;
|
|
45
|
+
if (!container) return;
|
|
46
|
+
this.editor = createAceEditor(container, {
|
|
47
|
+
value: this.modelValue !== '' ? this.modelValue : this.value,
|
|
48
|
+
mode: this.mode,
|
|
49
|
+
lineNumbers: this.lineNumbers,
|
|
50
|
+
readOnly: this.readOnly,
|
|
51
|
+
wrap: this.wrap,
|
|
52
|
+
minLines: this.minLines,
|
|
53
|
+
maxLines: this.maxLines
|
|
54
|
+
});
|
|
55
|
+
this.editor.session.on('change', () => {
|
|
56
|
+
const val = this.editor.getValue();
|
|
57
|
+
this.$emit('input', val);
|
|
58
|
+
this.$emit('update:modelValue', val);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
beforeDestroy() {
|
|
63
|
+
if (this.editor) {
|
|
64
|
+
destroyAceEditor(this.editor);
|
|
65
|
+
this.editor = null;
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
watch: {
|
|
69
|
+
modelValue(newVal) {
|
|
70
|
+
const val = newVal ?? '';
|
|
71
|
+
if (this.editor && this.editor.getValue() !== val) {
|
|
72
|
+
this.editor.setValue(val, -1);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
value(newVal) {
|
|
76
|
+
const val = newVal ?? '';
|
|
77
|
+
if (this.editor && this.editor.getValue() !== val) {
|
|
78
|
+
this.editor.setValue(val, -1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
methods: {
|
|
83
|
+
setValue(val) {
|
|
84
|
+
if (this.editor) {
|
|
85
|
+
this.editor.setValue(val ?? '', -1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ace = require('ace-builds');
|
|
4
|
+
require('ace-builds/src-noconflict/mode-javascript');
|
|
5
|
+
require('ace-builds/src-noconflict/mode-json');
|
|
6
|
+
require('ace-builds/src-noconflict/theme-chrome');
|
|
7
|
+
require('ace-builds/src-noconflict/theme-one_dark');
|
|
8
|
+
|
|
9
|
+
const LIGHT_THEME = 'ace/theme/chrome';
|
|
10
|
+
const DARK_THEME = 'ace/theme/one_dark';
|
|
11
|
+
|
|
12
|
+
function isDarkMode() {
|
|
13
|
+
return typeof document !== 'undefined' && document.documentElement.classList.contains('dark');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create an Ace editor on a container element (div). The container must have
|
|
18
|
+
* explicit dimensions (e.g. height/min-height and width).
|
|
19
|
+
* @param {HTMLElement} container - A div element to attach the editor to
|
|
20
|
+
* @param {Object} options - { value: string, mode: 'javascript'|'json', lineNumbers: boolean, ... }
|
|
21
|
+
* @returns {ace.Ace.Editor} The Ace editor instance
|
|
22
|
+
*/
|
|
23
|
+
function createAceEditor(container, options = {}) {
|
|
24
|
+
const {
|
|
25
|
+
value = '',
|
|
26
|
+
mode = 'javascript',
|
|
27
|
+
lineNumbers = true,
|
|
28
|
+
minLines,
|
|
29
|
+
maxLines,
|
|
30
|
+
readOnly = false,
|
|
31
|
+
wrap = false
|
|
32
|
+
} = options;
|
|
33
|
+
|
|
34
|
+
const editor = ace.edit(container);
|
|
35
|
+
editor.setTheme(isDarkMode() ? DARK_THEME : LIGHT_THEME);
|
|
36
|
+
editor.session.setMode(mode === 'json' ? 'ace/mode/json' : 'ace/mode/javascript');
|
|
37
|
+
editor.setValue(value, -1);
|
|
38
|
+
editor.setOptions({
|
|
39
|
+
showLineNumbers: lineNumbers,
|
|
40
|
+
readOnly,
|
|
41
|
+
wrap
|
|
42
|
+
});
|
|
43
|
+
if (minLines != null) editor.setOption('minLines', minLines);
|
|
44
|
+
if (maxLines != null) editor.setOption('maxLines', maxLines);
|
|
45
|
+
|
|
46
|
+
// Listen for theme toggles
|
|
47
|
+
const onThemeChanged = (e) => {
|
|
48
|
+
editor.setTheme(e.detail?.dark ? DARK_THEME : LIGHT_THEME);
|
|
49
|
+
};
|
|
50
|
+
document.documentElement.addEventListener('studio-theme-changed', onThemeChanged);
|
|
51
|
+
editor._studioThemeHandler = onThemeChanged;
|
|
52
|
+
|
|
53
|
+
return editor;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Destroy an Ace editor and release resources.
|
|
58
|
+
* @param {ace.Ace.Editor|null} editor - The editor instance from createAceEditor
|
|
59
|
+
*/
|
|
60
|
+
function destroyAceEditor(editor) {
|
|
61
|
+
if (editor) {
|
|
62
|
+
if (editor._studioThemeHandler) {
|
|
63
|
+
document.documentElement.removeEventListener('studio-theme-changed', editor._studioThemeHandler);
|
|
64
|
+
}
|
|
65
|
+
editor.destroy();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = { createAceEditor, destroyAceEditor };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
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-
|
|
6
|
+
<div class="text-sm text-content 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>
|
|
@@ -9,7 +9,7 @@ module.exports = app => app.component('chat-message', {
|
|
|
9
9
|
props: ['message', 'targetDashboardId'],
|
|
10
10
|
computed: {
|
|
11
11
|
styleForMessage() {
|
|
12
|
-
return this.message.role === 'user' ? 'p-3 bg-
|
|
12
|
+
return this.message.role === 'user' ? 'p-3 bg-muted' : 'py-3 pr-3';
|
|
13
13
|
},
|
|
14
14
|
contentSplitByScripts() {
|
|
15
15
|
const content = this.message.content;
|
|
@@ -1,39 +1,46 @@
|
|
|
1
|
-
<div class="relative border rounded bg-
|
|
2
|
-
<div class="flex border-b py-1 pl-1 text-xs font-medium bg-
|
|
1
|
+
<div class="chat-message-script relative border rounded bg-surface my-1 text-content text-sm overflow-hidden">
|
|
2
|
+
<div class="flex border-b py-1 pl-1 text-xs font-medium bg-surface">
|
|
3
3
|
<button
|
|
4
|
-
class="px-4 py-1 border-r border-
|
|
4
|
+
class="px-4 py-1 border-r border-edge-strong text-content-secondary font-semibold transition-colors duration-200 focus:outline-none"
|
|
5
5
|
:class="[
|
|
6
6
|
'rounded-l-md',
|
|
7
7
|
activeTab === 'code'
|
|
8
8
|
? 'bg-gray-700 text-white shadow'
|
|
9
|
-
: 'bg-
|
|
9
|
+
: 'bg-muted hover:bg-muted text-gray-600'
|
|
10
10
|
]"
|
|
11
11
|
@click="activeTab = 'code'">
|
|
12
12
|
Code
|
|
13
13
|
</button>
|
|
14
14
|
<button
|
|
15
|
-
class="px-4 py-1 text-
|
|
15
|
+
class="px-4 py-1 text-content-secondary font-semibold transition-colors duration-200 focus:outline-none"
|
|
16
16
|
:class="[
|
|
17
17
|
'rounded-r-md',
|
|
18
18
|
activeTab === 'output'
|
|
19
19
|
? 'bg-gray-700 text-white shadow'
|
|
20
|
-
: 'bg-
|
|
20
|
+
: 'bg-muted hover:bg-muted text-gray-600'
|
|
21
21
|
]"
|
|
22
22
|
@click="activeTab = 'output'">
|
|
23
23
|
Output
|
|
24
24
|
</button>
|
|
25
|
-
<div class="ml-auto mr-1 flex">
|
|
25
|
+
<div class="ml-auto mr-1 flex items-center">
|
|
26
|
+
<button
|
|
27
|
+
v-if="activeTab === 'output' && isChartOutput"
|
|
28
|
+
class="px-2 py-1 mr-1 text-xs bg-gray-700 text-white border-none rounded cursor-pointer hover:bg-primary-hover transition-colors flex items-center"
|
|
29
|
+
@click="exportChartPNG"
|
|
30
|
+
title="Export PNG">
|
|
31
|
+
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.2em;" 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>
|
|
32
|
+
</button>
|
|
26
33
|
<button
|
|
27
34
|
v-if="activeTab === 'output'"
|
|
28
|
-
class="px-2 py-1 mr-1 text-xs bg-
|
|
35
|
+
class="px-2 py-1 mr-1 text-xs bg-gray-700 text-white border-none rounded cursor-pointer hover:bg-primary-hover transition-colors flex items-center"
|
|
29
36
|
@click="openDetailModal">
|
|
30
|
-
<svg xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
<svg xmlns="http://www.w3.org/2000/svg" style="height: 1.2em;" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
31
38
|
<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
39
|
</svg>
|
|
33
40
|
</button>
|
|
34
41
|
<button
|
|
35
42
|
v-if="activeTab === 'code' && !isEditing"
|
|
36
|
-
class="px-2 py-1 mr-1 text-xs bg-
|
|
43
|
+
class="px-2 py-1 mr-1 text-xs bg-page0 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center"
|
|
37
44
|
@click.stop="startEditing">
|
|
38
45
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
|
|
39
46
|
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM4 13.5V16h2.5l7.086-7.086-2.828-2.828L4 13.5z" />
|
|
@@ -41,7 +48,7 @@
|
|
|
41
48
|
</button>
|
|
42
49
|
<async-button
|
|
43
50
|
v-if="!isEditing"
|
|
44
|
-
class="px-2 py-1 text-xs bg-
|
|
51
|
+
class="px-2 py-1 text-xs bg-primary hover:bg-primary-hover text-primary-text border-none rounded cursor-pointer transition-colors disabled:bg-gray-400"
|
|
45
52
|
@click="executeScript">
|
|
46
53
|
Run
|
|
47
54
|
</async-button>
|
|
@@ -55,25 +62,25 @@
|
|
|
55
62
|
</button>
|
|
56
63
|
<div
|
|
57
64
|
v-if="showDropdown"
|
|
58
|
-
class="absolute right-0 z-10 mt-1 w-64 origin-top-right rounded-md bg-
|
|
65
|
+
class="absolute right-0 z-10 mt-1 w-64 origin-top-right rounded-md bg-surface py-1 shadow-lg ring-1 ring-black/5">
|
|
59
66
|
<button
|
|
60
|
-
class="block w-full text-left px-4 py-2 text-xs text-
|
|
67
|
+
class="block w-full text-left px-4 py-2 text-xs text-content-secondary hover:bg-muted"
|
|
61
68
|
@click="openCreateDashboardModal(); showDropdown = false">
|
|
62
69
|
Create Dashboard
|
|
63
70
|
</button>
|
|
64
71
|
<button
|
|
65
|
-
class="block w-full text-left px-4 py-2 text-xs text-
|
|
72
|
+
class="block w-full text-left px-4 py-2 text-xs text-content-secondary hover:bg-muted"
|
|
66
73
|
@click="copyOutput(); showDropdown = false">
|
|
67
74
|
Copy Output As Text
|
|
68
75
|
</button>
|
|
69
76
|
<button
|
|
70
77
|
v-if="canOverwriteDashboard"
|
|
71
|
-
class="block w-full text-left px-4 py-2 text-xs text-
|
|
78
|
+
class="block w-full text-left px-4 py-2 text-xs text-content-secondary hover:bg-muted"
|
|
72
79
|
@click="openOverwriteDashboardConfirmation(); showDropdown = false">
|
|
73
80
|
Overwrite Dashboard
|
|
74
81
|
</button>
|
|
75
82
|
<button
|
|
76
|
-
class="block w-full text-left px-4 py-2 text-xs text-
|
|
83
|
+
class="block w-full text-left px-4 py-2 text-xs text-content-secondary hover:bg-muted"
|
|
77
84
|
@click="$emit('copyMessage'); showDropdown = false">
|
|
78
85
|
Copy Full Message
|
|
79
86
|
</button>
|
|
@@ -83,9 +90,14 @@
|
|
|
83
90
|
</div>
|
|
84
91
|
|
|
85
92
|
<div class="p-0 max-h-[50vh] max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] overflow-y-auto" v-show="activeTab === 'code'">
|
|
86
|
-
<div v-if="isEditing" class="flex flex-col space-y-2">
|
|
87
|
-
<div class="border border-
|
|
88
|
-
<
|
|
93
|
+
<div v-if="isEditing" class="flex flex-col space-y-2 chat-script-editor-wrap">
|
|
94
|
+
<div class="border border-edge">
|
|
95
|
+
<ace-editor
|
|
96
|
+
v-model="editedScript"
|
|
97
|
+
mode="javascript"
|
|
98
|
+
:line-numbers="true"
|
|
99
|
+
class="w-full h-[45vh] min-h-[200px]"
|
|
100
|
+
/>
|
|
89
101
|
</div>
|
|
90
102
|
<div class="flex justify-end gap-2 pb-2">
|
|
91
103
|
<button
|
|
@@ -100,17 +112,17 @@
|
|
|
100
112
|
</async-button>
|
|
101
113
|
</div>
|
|
102
114
|
</div>
|
|
103
|
-
<pre v-else class="whitespace-pre-wrap !my-0
|
|
115
|
+
<pre v-else class="whitespace-pre-wrap !my-0 bg-muted"><code v-text="script" ref="code" :class="'language-' + language"></code></pre>
|
|
104
116
|
</div>
|
|
105
117
|
|
|
106
|
-
<div class="p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-
|
|
107
|
-
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" />
|
|
118
|
+
<div class="p-3 whitespace-pre-wrap max-h-[50vh] overflow-y-auto bg-surface border-t max-w-[calc(100vw-4rem)] lg:max-w-[calc(100vw-20rem)] relative" v-show="activeTab === 'output'">
|
|
119
|
+
<dashboard-chart v-if="message.executionResult?.output?.$chart" :value="message.executionResult?.output" ref="chartOutput" />
|
|
108
120
|
<dashboard-map v-else-if="message.executionResult?.output?.$featureCollection" :value="message.executionResult?.output" />
|
|
109
121
|
<pre v-else>{{ message.executionResult?.output || 'No output' }}</pre>
|
|
110
122
|
|
|
111
|
-
<div v-if="message.executionResult?.logs?.length" class="mt-3 pt-3 border-t border-
|
|
123
|
+
<div v-if="message.executionResult?.logs?.length" class="mt-3 pt-3 border-t border-edge">
|
|
112
124
|
<div class="text-xs font-semibold text-gray-600 uppercase tracking-wide">Console</div>
|
|
113
|
-
<pre class="mt-1 bg-
|
|
125
|
+
<pre class="mt-1 bg-muted text-content p-3 rounded whitespace-pre-wrap overflow-x-auto max-h-[280px]">{{ message.executionResult.logs }}</pre>
|
|
114
126
|
</div>
|
|
115
127
|
</div>
|
|
116
128
|
|
|
@@ -131,19 +143,24 @@
|
|
|
131
143
|
<template #body>
|
|
132
144
|
<div class="modal-exit" @click="showCreateDashboardModal = false">×</div>
|
|
133
145
|
<div>
|
|
134
|
-
<div class="mt-4 text-
|
|
146
|
+
<div class="mt-4 text-content font-semibold">Create Dashboard</div>
|
|
135
147
|
<div class="mt-4">
|
|
136
|
-
<label class="block text-sm font-medium leading-6 text-
|
|
148
|
+
<label class="block text-sm font-medium leading-6 text-content">Title</label>
|
|
137
149
|
<div class="mt-2">
|
|
138
150
|
<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">
|
|
139
|
-
<input type="text" v-model="newDashboardTitle" class="outline-none block flex-1 border-0 bg-transparent py-1.5 pl-1 text-
|
|
151
|
+
<input type="text" v-model="newDashboardTitle" class="outline-none block flex-1 border-0 bg-transparent py-1.5 pl-1 text-content placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" placeholder="My Dashboard">
|
|
140
152
|
</div>
|
|
141
153
|
</div>
|
|
142
154
|
</div>
|
|
143
155
|
<div class="my-4">
|
|
144
|
-
<label class="block text-sm font-medium leading-6 text-
|
|
145
|
-
<div class="border border-
|
|
146
|
-
<
|
|
156
|
+
<label class="block text-sm font-medium leading-6 text-content">Code</label>
|
|
157
|
+
<div class="border border-edge">
|
|
158
|
+
<ace-editor
|
|
159
|
+
v-model="dashboardCode"
|
|
160
|
+
mode="javascript"
|
|
161
|
+
:line-numbers="true"
|
|
162
|
+
class="h-[300px] w-full"
|
|
163
|
+
/>
|
|
147
164
|
</div>
|
|
148
165
|
</div>
|
|
149
166
|
<async-button
|
|
@@ -173,14 +190,14 @@
|
|
|
173
190
|
<template #body>
|
|
174
191
|
<div class="modal-exit" @click="showOverwriteDashboardConfirmationModal = false">×</div>
|
|
175
192
|
<div>
|
|
176
|
-
<div class="mt-4 text-
|
|
177
|
-
<p class="mt-2 text-sm text-
|
|
193
|
+
<div class="mt-4 text-content font-semibold">Overwrite Dashboard</div>
|
|
194
|
+
<p class="mt-2 text-sm text-content-secondary">
|
|
178
195
|
This will replace the linked dashboard's code with the script below.
|
|
179
196
|
</p>
|
|
180
197
|
<p class="mt-1 text-xs text-gray-600 break-all" v-if="targetDashboardId">
|
|
181
198
|
Dashboard ID: {{ targetDashboardId }}
|
|
182
199
|
</p>
|
|
183
|
-
<div class="my-4 border border-
|
|
200
|
+
<div class="my-4 border border-edge bg-page rounded">
|
|
184
201
|
<pre class="p-2 h-[300px] overflow-auto whitespace-pre-wrap text-xs">{{ overwriteDashboardCode }}</pre>
|
|
185
202
|
</div>
|
|
186
203
|
<div class="flex items-center gap-2">
|
|
@@ -190,7 +207,7 @@
|
|
|
190
207
|
Confirm Overwrite
|
|
191
208
|
</async-button>
|
|
192
209
|
<button
|
|
193
|
-
class="px-2.5 py-1.5 rounded-md text-sm font-semibold text-
|
|
210
|
+
class="px-2.5 py-1.5 rounded-md text-sm font-semibold text-content-secondary bg-gray-200 hover:bg-gray-300"
|
|
194
211
|
@click="showOverwriteDashboardConfirmationModal = false">
|
|
195
212
|
Cancel
|
|
196
213
|
</button>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* global
|
|
1
|
+
/* global Prism */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const api = require('../../api');
|
|
@@ -18,9 +18,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
18
18
|
newDashboardTitle: '',
|
|
19
19
|
dashboardCode: '',
|
|
20
20
|
createError: null,
|
|
21
|
-
dashboardEditor: null,
|
|
22
21
|
isEditing: false,
|
|
23
|
-
codeEditor: null,
|
|
24
22
|
editedScript: null,
|
|
25
23
|
overwriteDashboardCode: '',
|
|
26
24
|
overwriteError: null
|
|
@@ -28,18 +26,21 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
28
26
|
},
|
|
29
27
|
computed: {
|
|
30
28
|
styleForMessage() {
|
|
31
|
-
return this.message.role === 'user' ? 'bg-
|
|
29
|
+
return this.message.role === 'user' ? 'bg-muted' : '';
|
|
32
30
|
},
|
|
33
31
|
canOverwriteDashboard() {
|
|
34
32
|
return !!this.targetDashboardId;
|
|
33
|
+
},
|
|
34
|
+
isChartOutput() {
|
|
35
|
+
return !!this.message.executionResult?.output?.$chart;
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
methods: {
|
|
39
|
+
exportChartPNG() {
|
|
40
|
+
this.$refs.chartOutput?.exportPNG?.();
|
|
41
|
+
},
|
|
38
42
|
async executeScript() {
|
|
39
|
-
|
|
40
|
-
if (this.isEditing) {
|
|
41
|
-
scriptToRun = this.codeEditor ? this.codeEditor.getValue() : this.editedScript;
|
|
42
|
-
}
|
|
43
|
+
const scriptToRun = this.isEditing ? this.editedScript : this.script;
|
|
43
44
|
this.editedScript = scriptToRun;
|
|
44
45
|
const { chatMessage } = await api.ChatMessage.executeScript({
|
|
45
46
|
chatMessageId: this.message._id,
|
|
@@ -66,25 +67,12 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
66
67
|
this.dashboardCode = this.script;
|
|
67
68
|
this.createError = null;
|
|
68
69
|
this.showCreateDashboardModal = true;
|
|
69
|
-
this.$nextTick(() => {
|
|
70
|
-
if (this.dashboardEditor) {
|
|
71
|
-
this.dashboardEditor.toTextArea();
|
|
72
|
-
}
|
|
73
|
-
this.$refs.dashboardCodeEditor.value = this.dashboardCode;
|
|
74
|
-
this.dashboardEditor = CodeMirror.fromTextArea(this.$refs.dashboardCodeEditor, {
|
|
75
|
-
mode: 'javascript',
|
|
76
|
-
lineNumbers: true
|
|
77
|
-
});
|
|
78
|
-
this.dashboardEditor.on('change', () => {
|
|
79
|
-
this.dashboardCode = this.dashboardEditor.getValue();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
70
|
},
|
|
83
71
|
openOverwriteDashboardConfirmation() {
|
|
84
72
|
if (!this.canOverwriteDashboard) {
|
|
85
73
|
return;
|
|
86
74
|
}
|
|
87
|
-
this.overwriteDashboardCode = this.
|
|
75
|
+
this.overwriteDashboardCode = this.isEditing ? this.editedScript : this.script;
|
|
88
76
|
this.overwriteError = null;
|
|
89
77
|
this.showOverwriteDashboardConfirmationModal = true;
|
|
90
78
|
},
|
|
@@ -94,39 +82,16 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
94
82
|
startEditing() {
|
|
95
83
|
this.isEditing = true;
|
|
96
84
|
this.editedScript = this.script;
|
|
97
|
-
this.$nextTick(() => {
|
|
98
|
-
if (!this.$refs.scriptEditor) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
this.$refs.scriptEditor.value = this.editedScript;
|
|
102
|
-
if (typeof CodeMirror === 'undefined') {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
this.destroyCodeMirror();
|
|
106
|
-
this.codeEditor = CodeMirror.fromTextArea(this.$refs.scriptEditor, {
|
|
107
|
-
mode: 'javascript',
|
|
108
|
-
lineNumbers: true,
|
|
109
|
-
smartIndent: false
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
85
|
},
|
|
113
86
|
cancelEditing() {
|
|
114
87
|
this.isEditing = false;
|
|
115
|
-
this.destroyCodeMirror();
|
|
116
88
|
this.editedScript = this.script;
|
|
117
89
|
this.highlightCode();
|
|
118
90
|
},
|
|
119
91
|
finishEditing() {
|
|
120
92
|
this.isEditing = false;
|
|
121
|
-
this.destroyCodeMirror();
|
|
122
93
|
this.highlightCode();
|
|
123
94
|
},
|
|
124
|
-
destroyCodeMirror() {
|
|
125
|
-
if (this.codeEditor) {
|
|
126
|
-
this.codeEditor.toTextArea();
|
|
127
|
-
this.codeEditor = null;
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
95
|
handleScriptInput(event) {
|
|
131
96
|
this.editedScript = event?.target?.value || '';
|
|
132
97
|
},
|
|
@@ -144,9 +109,8 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
144
109
|
}
|
|
145
110
|
},
|
|
146
111
|
async createDashboardFromScript() {
|
|
147
|
-
this.dashboardCode = this.dashboardEditor.getValue();
|
|
148
112
|
const { dashboard } = await api.Dashboard.createDashboard({
|
|
149
|
-
code: this.dashboardCode,
|
|
113
|
+
code: this.dashboardCode || '',
|
|
150
114
|
title: this.newDashboardTitle
|
|
151
115
|
}).catch(err => {
|
|
152
116
|
if (err.response?.data?.message) {
|
|
@@ -167,7 +131,7 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
167
131
|
return;
|
|
168
132
|
}
|
|
169
133
|
|
|
170
|
-
this.overwriteDashboardCode = this.
|
|
134
|
+
this.overwriteDashboardCode = this.isEditing ? this.editedScript : this.script;
|
|
171
135
|
|
|
172
136
|
const params = {
|
|
173
137
|
dashboardId: this.targetDashboardId,
|
|
@@ -209,12 +173,6 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
209
173
|
}
|
|
210
174
|
},
|
|
211
175
|
watch: {
|
|
212
|
-
showCreateDashboardModal(val) {
|
|
213
|
-
if (!val && this.dashboardEditor) {
|
|
214
|
-
this.dashboardEditor.toTextArea();
|
|
215
|
-
this.dashboardEditor = null;
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
176
|
script(newScript) {
|
|
219
177
|
if (!this.isEditing) {
|
|
220
178
|
this.editedScript = newScript;
|
|
@@ -232,7 +190,6 @@ module.exports = app => app.component('chat-message-script', {
|
|
|
232
190
|
}
|
|
233
191
|
},
|
|
234
192
|
unmounted() {
|
|
235
|
-
this.destroyCodeMirror();
|
|
236
193
|
document.body.removeEventListener('click', this.handleBodyClick);
|
|
237
194
|
}
|
|
238
195
|
});
|