@mongoosejs/studio 0.3.10 → 0.4.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/ChatThread/createChatMessage.js +15 -3
- package/backend/actions/ChatThread/createChatThread.js +8 -1
- package/backend/actions/ChatThread/index.js +1 -0
- package/backend/actions/ChatThread/streamChatMessage.js +49 -14
- package/backend/actions/ChatThread/toggleAgentMode.js +37 -0
- package/backend/actions/Model/streamChatMessage.js +15 -4
- package/backend/authorize.js +1 -0
- package/backend/chatAgent/agentSystemPrompt.js +45 -0
- package/backend/chatAgent/agentToolMetadata.js +20 -0
- package/backend/chatAgent/getAgentTools.js +140 -0
- package/backend/db/chatMessageSchema.js +5 -0
- package/backend/db/chatThreadSchema.js +4 -0
- package/backend/integrations/callLLM.js +4 -2
- package/backend/integrations/streamLLM.js +12 -4
- package/eslint.config.js +2 -1
- package/frontend/public/app.js +245 -45
- package/frontend/public/tw.css +38 -8
- package/frontend/src/api.js +6 -0
- package/frontend/src/chat/chat-message/chat-message.html +12 -1
- package/frontend/src/chat/chat-message/chat-message.js +8 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +2 -2
- package/frontend/src/chat/chat.html +91 -44
- package/frontend/src/chat/chat.js +119 -19
- package/frontend/src/create-document/create-document.js +3 -0
- package/frontend/src/dashboard/edit-dashboard/edit-dashboard.html +1 -1
- package/frontend/src/models/models.html +1 -1
- package/frontend/src/splash/splash.html +2 -2
- package/frontend/src/team/team.html +1 -1
- package/package.json +3 -2
package/frontend/public/tw.css
CHANGED
|
@@ -1072,6 +1072,10 @@ video {
|
|
|
1072
1072
|
height: 0.75rem;
|
|
1073
1073
|
}
|
|
1074
1074
|
|
|
1075
|
+
.h-3\.5 {
|
|
1076
|
+
height: 0.875rem;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1075
1079
|
.h-4 {
|
|
1076
1080
|
height: 1rem;
|
|
1077
1081
|
}
|
|
@@ -1212,6 +1216,10 @@ video {
|
|
|
1212
1216
|
width: 0.75rem;
|
|
1213
1217
|
}
|
|
1214
1218
|
|
|
1219
|
+
.w-3\.5 {
|
|
1220
|
+
width: 0.875rem;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1215
1223
|
.w-36 {
|
|
1216
1224
|
width: 9rem;
|
|
1217
1225
|
}
|
|
@@ -1256,6 +1264,10 @@ video {
|
|
|
1256
1264
|
width: 2rem;
|
|
1257
1265
|
}
|
|
1258
1266
|
|
|
1267
|
+
.w-80 {
|
|
1268
|
+
width: 20rem;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1259
1271
|
.w-\[240px\] {
|
|
1260
1272
|
width: 240px;
|
|
1261
1273
|
}
|
|
@@ -1320,14 +1332,14 @@ video {
|
|
|
1320
1332
|
max-width: 280px;
|
|
1321
1333
|
}
|
|
1322
1334
|
|
|
1323
|
-
.max-w-\[calc\(100vw-3rem\)\] {
|
|
1324
|
-
max-width: calc(100vw - 3rem);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
1335
|
.max-w-\[calc\(100vw-4rem\)\] {
|
|
1328
1336
|
max-width: calc(100vw - 4rem);
|
|
1329
1337
|
}
|
|
1330
1338
|
|
|
1339
|
+
.max-w-full {
|
|
1340
|
+
max-width: 100%;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1331
1343
|
.max-w-lg {
|
|
1332
1344
|
max-width: 32rem;
|
|
1333
1345
|
}
|
|
@@ -1774,6 +1786,10 @@ video {
|
|
|
1774
1786
|
border-bottom-width: 4px;
|
|
1775
1787
|
}
|
|
1776
1788
|
|
|
1789
|
+
.border-l {
|
|
1790
|
+
border-left-width: 1px;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1777
1793
|
.border-l-0 {
|
|
1778
1794
|
border-left-width: 0px;
|
|
1779
1795
|
}
|
|
@@ -3577,6 +3593,10 @@ video {
|
|
|
3577
3593
|
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
|
|
3578
3594
|
}
|
|
3579
3595
|
|
|
3596
|
+
.disabled\:bg-page:disabled {
|
|
3597
|
+
background-color: var(--color-page);
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3580
3600
|
.disabled\:text-gray-300:disabled {
|
|
3581
3601
|
--tw-text-opacity: 1;
|
|
3582
3602
|
color: rgb(209 213 219 / var(--tw-text-opacity));
|
|
@@ -3753,6 +3773,10 @@ video {
|
|
|
3753
3773
|
margin-right: -2rem;
|
|
3754
3774
|
}
|
|
3755
3775
|
|
|
3776
|
+
.lg\:flex {
|
|
3777
|
+
display: flex;
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3756
3780
|
.lg\:hidden {
|
|
3757
3781
|
display: none;
|
|
3758
3782
|
}
|
|
@@ -3769,10 +3793,6 @@ video {
|
|
|
3769
3793
|
width: 16rem;
|
|
3770
3794
|
}
|
|
3771
3795
|
|
|
3772
|
-
.lg\:max-w-\[calc\(100vw-15rem\)\] {
|
|
3773
|
-
max-width: calc(100vw - 15rem);
|
|
3774
|
-
}
|
|
3775
|
-
|
|
3776
3796
|
.lg\:max-w-\[calc\(100vw-20rem\)\] {
|
|
3777
3797
|
max-width: calc(100vw - 20rem);
|
|
3778
3798
|
}
|
|
@@ -3809,4 +3829,14 @@ video {
|
|
|
3809
3829
|
|
|
3810
3830
|
:is(:where(.dark) .dark\:bg-shark-800\/80) {
|
|
3811
3831
|
background-color: rgb(33 37 41 / 0.8);
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
:is(:where(.dark) .dark\:text-gray-400) {
|
|
3835
|
+
--tw-text-opacity: 1;
|
|
3836
|
+
color: rgb(156 163 175 / var(--tw-text-opacity));
|
|
3837
|
+
}
|
|
3838
|
+
|
|
3839
|
+
:is(:where(.dark) .dark\:text-gray-500) {
|
|
3840
|
+
--tw-text-opacity: 1;
|
|
3841
|
+
color: rgb(107 114 128 / var(--tw-text-opacity));
|
|
3812
3842
|
}
|
package/frontend/src/api.js
CHANGED
|
@@ -62,6 +62,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
62
62
|
shareChatThread(params) {
|
|
63
63
|
return client.post('', { action: 'ChatThread.shareChatThread', ...params }).then(res => res.data);
|
|
64
64
|
},
|
|
65
|
+
toggleAgentMode(params) {
|
|
66
|
+
return client.post('', { action: 'ChatThread.toggleAgentMode', ...params }).then(res => res.data);
|
|
67
|
+
},
|
|
65
68
|
streamChatMessage: async function* streamChatMessage(params) {
|
|
66
69
|
// Don't stream on Next.js or Netlify for now.
|
|
67
70
|
const data = await client.post('', { action: 'ChatThread.createChatMessage', ...params }).then(res => res.data);
|
|
@@ -238,6 +241,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
238
241
|
shareChatThread: function shareChatThread(params) {
|
|
239
242
|
return client.post('/ChatThread/shareChatThread', params).then(res => res.data);
|
|
240
243
|
},
|
|
244
|
+
toggleAgentMode: function toggleAgentMode(params) {
|
|
245
|
+
return client.post('/ChatThread/toggleAgentMode', params).then(res => res.data);
|
|
246
|
+
},
|
|
241
247
|
streamChatMessage: async function* streamChatMessage(params) {
|
|
242
248
|
const accessToken = window.localStorage.getItem('_mongooseStudioAccessToken') || null;
|
|
243
249
|
const url = window.MONGOOSE_STUDIO_CONFIG.baseURL + '/ChatThread/streamChatMessage?' + new URLSearchParams(params).toString();
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
<div class="relative flex items-start" :class="{'justify-end': message.role === 'user'}">
|
|
2
2
|
<div
|
|
3
|
-
class="min-w-0 max-w-
|
|
3
|
+
class="min-w-0 max-w-full"
|
|
4
4
|
:class="{'text-right': message.role === 'user'}">
|
|
5
5
|
|
|
6
|
+
<div v-if="message.toolCalls && message.toolCalls.length" class="mb-2 text-xs text-gray-500 dark:text-gray-400">
|
|
7
|
+
<div
|
|
8
|
+
v-for="(tc, i) in message.toolCalls"
|
|
9
|
+
:key="i"
|
|
10
|
+
class="flex items-center gap-1.5 py-0.5 font-mono">
|
|
11
|
+
<svg :class="['w-3.5 h-3.5 shrink-0', tc.status === 'running' ? 'animate-spin text-gray-400 dark:text-gray-500' : 'text-gray-500 dark:text-gray-400']" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75a4.5 4.5 0 0 1-4.884 4.484c-1.076-.091-2.264.071-2.95.904l-7.152 8.684a2.548 2.548 0 1 1-3.586-3.586l8.684-7.152c.833-.686.995-1.874.904-2.95a4.5 4.5 0 0 1 6.336-4.486l-3.276 3.276a3.004 3.004 0 0 0 2.25 2.25l3.276-3.276c.256.565.398 1.192.398 1.852Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M4.867 19.125h.008v.008h-.008v-.008Z" /></svg>
|
|
12
|
+
<span>{{ tc.toolName }}</span>
|
|
13
|
+
<span v-if="tc.toolName !== 'typeCheck'" class="text-gray-400 dark:text-gray-500">{{ formatToolInput(tc.input) }}</span>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
6
17
|
<div class="text-sm text-content rounded-md inline-block relative" :class="styleForMessage">
|
|
7
18
|
<div v-for="part in contentSplitByScripts">
|
|
8
19
|
<div v-if="part.type === 'text'" v-html="marked(part.content)">
|
|
@@ -54,6 +54,14 @@ module.exports = app => app.component('chat-message', {
|
|
|
54
54
|
marked(text) {
|
|
55
55
|
return marked(text);
|
|
56
56
|
},
|
|
57
|
+
formatToolInput(input) {
|
|
58
|
+
if (!input) return '';
|
|
59
|
+
const parts = [];
|
|
60
|
+
if (input.modelName) parts.push(input.modelName);
|
|
61
|
+
if (input.filter && Object.keys(input.filter).length) parts.push(JSON.stringify(input.filter));
|
|
62
|
+
if (input.limit && input.limit !== 10) parts.push('limit=' + input.limit);
|
|
63
|
+
return parts.length ? '(' + parts.join(', ') + ')' : '';
|
|
64
|
+
},
|
|
57
65
|
async executeScript(message, script) {
|
|
58
66
|
const { chatMessage } = await api.ChatMessage.executeScript({
|
|
59
67
|
chatMessageId: message._id,
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
</button>
|
|
34
34
|
<button
|
|
35
35
|
v-if="activeTab === 'code' && !isEditing"
|
|
36
|
-
class="px-2 py-1 mr-1 text-xs bg-
|
|
36
|
+
class="px-2 py-1 mr-1 text-xs bg-gray-700 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center"
|
|
37
37
|
@click.stop="startEditing">
|
|
38
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-
|
|
38
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4" viewBox="0 0 20 20" fill="currentColor">
|
|
39
39
|
<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" />
|
|
40
40
|
</svg>
|
|
41
41
|
</button>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
class="rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted"
|
|
70
70
|
title="Hide sidebar"
|
|
71
71
|
>
|
|
72
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-
|
|
72
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
|
73
73
|
<path stroke-linecap="round" stroke-linejoin="round" d="m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5" />
|
|
74
74
|
</svg>
|
|
75
75
|
</button>
|
|
@@ -82,57 +82,104 @@
|
|
|
82
82
|
aria-label="Share thread with workspace"
|
|
83
83
|
:title="'Share thread with workspace' + (!hasWorkspace ? ' (requires a pro workspace)' : !chatThreadId ? ': Open a thread first!' : '')"
|
|
84
84
|
>
|
|
85
|
-
<svg v-if="hasWorkspace" xmlns="http://www.w3.org/2000/svg" class="w-
|
|
86
|
-
<svg v-else xmlns="http://www.w3.org/2000/svg" class="w-
|
|
85
|
+
<svg v-if="hasWorkspace" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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>
|
|
86
|
+
<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>
|
|
87
|
+
</button>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
@click="toggleAgentMode"
|
|
91
|
+
class="rounded p-1.5 transition-colors"
|
|
92
|
+
:class="isAgentModeEnabled ? 'text-primary bg-primary/10' : 'text-gray-400 hover:text-gray-600 hover:bg-muted'"
|
|
93
|
+
:aria-label="isAgentModeEnabled ? 'Turn agent mode off' : 'Turn agent mode on'"
|
|
94
|
+
:aria-pressed="isAgentModeEnabled"
|
|
95
|
+
:title="isAgentModeEnabled ? 'Agent mode on' : 'Agent mode off'"
|
|
96
|
+
>
|
|
97
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="currentColor" viewBox="0 0 200 200"><path d="m187 170.9-38.72-13.73-0.55-0.25-11.24-12.18v-9.98c6.3-6.82 6.43-11.03 8.3-23.22 7.34-1.41 10.2-7.7 12.28-18.9 0.97-5.02 2.72-9.88 0.14-13.92-1.38-2.35-3.49-3.08-5.62-3.38 1.65-11.57 5.47-27.07-2.68-42.38-5.47-9.94-14-14.18-21.8-14.92-3.5-9.15-12.32-13.06-27.11-13.06h-1.06c-27.2 0-48.53 17.96-52.18 39.74-2.05 11.38-0.41 20.41 0.74 30.03-2.23 0.19-4.38 1.02-5.84 3.42-2.21 3.83-1.27 8.84 0.06 14.19 2 8.28 2.26 16.18 12.9 18.96 1.47 6.52 0.58 14.07 8.3 22.84v10.77l-12.54 12.83-38.38 12.85v24.18h57.31c-3.11-14.37-6.53-23.75-5.45-42.72l0.44-0.34c5.71 9.04 16.02 15.97 29.22 25.91l-12.68 17.15h38.07l-13.16-17.2c11.44-9.29 22.31-16.55 29.2-25.38 4.68 9.53-1.48 26.7-4.72 42.58h56.77v-23.89zm-49.56-49.09c-1.43 5.43-2.53 6.16-9.69 14.68l-11.68 13.11c-3.48 3.27-4.8 3.27-11.11 3.27h-10.39c-6.25 0-7.45-0.78-11.01-4.46-6.78-7.7-11.76-13.37-15.09-17.32-5.39-6.33-5.85-7.2-7.16-18.89-0.73-4.86-3.02-14.25-2.94-14.91 3.94 3.43 13.59 3.35 16.89 3.35 12.76 0 15.79-2.74 19.92-17.12 0.68-2.98 1.71-3.53 4-3.53 2.04 0 3.04 0.98 3.86 3.71 3.9 13.69 5.2 16.52 16.15 16.76h2.99c8.1 0 15.01-1.52 18.58-2.93-0.5 5.06-2.28 16.7-3.32 24.28zm4.72-39.02c-1.97 10.98-2.94 12.3-17.69 12.91-9.05 0.38-11.35-0.71-14.17-8.69-3.69-11.25-2.17-13 5.55-13.83 6.36-0.83 11.74-0.79 15.92-0.79 10.01 0 12.11 0.27 10.39 10.4zm-84.38-32c0-11.99 9.26-21.63 15.54-23.52 4.46-1.14 7.99 3.61 15.25 5.74 5.06 1.54 10.71 1.32 11.84 1.32 11.49 0 16.71-2.62 21.55-6.91 1.66-1.28 3.22-1.57 4.86-0.67 10.89 6.36 15.34 16.28 14.74 26.07-0.36 5.5-2.18 9.03-1.38 12.23l1.14 3.62c-3.83-0.82-6.2-0.92-10.69-0.92-9.44 0-17.61 1.24-22.14 2.5-3.66 1.24-5.2 1.44-8.35 1.44-2.98 0-4.92-0.2-7.56-1.44-4.97-1.54-14.49-2.5-21.47-2.5-3.69 0-7 0.01-10.9 0.62l-1.84 0.3 0.42-3.07c0.82-3.01-1.01-7.56-1.01-14.81z"/><path d="m116.6 125.4-12.18-2.58c-2.29-0.68-3.7 0.76-5.4 0.76-1.66 0-2.79-1.35-5.4-0.66l-10.88 2.36c-1.35 0.12-1.55 1.44-0.79 3.32 0.38 1.02 1.26 0.7 3.07 0.36 3.25-0.46 4.65-0.84 8.11-1.04 1.85-0.17 2.59 0.41 5.06 0.41h1.14c1.72 0 2.62-0.55 4.15-0.31 3.81 0.31 5.64 0.72 11.64 1.22 2.08 0.38 2.4-1.15 2.21-2.52-0.07-0.65-0.24-1.1-0.73-1.32z"/><path d="m94.08 133.5c-1.96 0-2.49 1.23-2.4 2.39 0.06 1.38 0.93 2.27 2.57 2.27h10.06c2.13 0 2.7-1.25 2.7-2.56 0-1.13-0.65-2.1-2.53-2.1h-10.4z"/><path d="m91.31 106.6c-2.13 0-2.51 3.32-1.24 4.55 1.11 1.08 7.39 3.76 9.34 3.76s8.38-3.24 9.4-3.87c1.9-1.2 0.85-4.82-1.7-4.44-1.84 0.3-6.01 3.39-7.96 3.01-1.53-0.32-6.08-3.01-7.84-3.01z"/><path d="m85.62 73.71c-5.3-1.1-10.53-1.15-14.51-1.15-10.96 0-14.08-0.44-14.33 5.26-0.47 11.15 1.82 15.96 6.69 17.19 4.7 1.26 6.84 1.08 11.71 1.08 8.88 0 10.9-1.18 14.23-10.67 2.38-6.81 1.87-10.59-3.79-11.71z"/><path d="m114.5 73.51c-7.72 0.83-7.35 2.71-6.39 9.73 1.78 7.47 3.64 11.94 10.97 12.49 3.07 0.14 4.97-0.05 8-0.32 10.72-0.96 12.6-2.48 14.45-12.22 1.88-10.29-0.54-10.77-9.79-10.77-4.18 0-10.45 0.26-17.24 1.09z"/></svg>
|
|
87
98
|
</button>
|
|
88
99
|
</div>
|
|
89
100
|
</aside>
|
|
90
101
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
<div
|
|
95
|
-
<div
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
<div class="flex-1 min-w-0 flex">
|
|
103
|
+
<!-- Main Chat Area -->
|
|
104
|
+
<main class="flex-1 min-w-0 flex flex-col bg-slate-50">
|
|
105
|
+
<div class="flex-1 overflow-y-auto p-6 space-y-4" ref="messagesContainer">
|
|
106
|
+
<div v-if="chatMessages?.length === 0">
|
|
107
|
+
<div class="flex items-center w-full h-full justify-center py-3 mb-4">
|
|
108
|
+
<p class="mx-4 font-bold text-content">
|
|
109
|
+
Ask Mongoose Studio to analyze your data or generate a script
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
99
112
|
</div>
|
|
113
|
+
<ul role="list" class="space-y-4" v-else>
|
|
114
|
+
<li v-for="message in chatMessages" :key="message._id">
|
|
115
|
+
<chat-message :message="message" :target-dashboard-id="currentThread?.dashboardId"></chat-message>
|
|
116
|
+
</li>
|
|
117
|
+
</ul>
|
|
100
118
|
</div>
|
|
101
|
-
<ul role="list" class="space-y-4" v-else>
|
|
102
|
-
<li v-for="message in chatMessages" :key="message._id">
|
|
103
|
-
<chat-message :message="message" :target-dashboard-id="currentThread?.dashboardId"></chat-message>
|
|
104
|
-
</li>
|
|
105
|
-
</ul>
|
|
106
|
-
</div>
|
|
107
119
|
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
121
|
+
<!-- Input Area -->
|
|
122
|
+
<div class="border-t p-4">
|
|
123
|
+
<form @submit.prevent="sendMessage" :disabled="sendingMessage" class="flex gap-2 items-end justify-end">
|
|
124
|
+
<textarea
|
|
125
|
+
v-model="newMessage"
|
|
126
|
+
:placeholder="sendingMessage ? 'Sending...' : 'Ask about your data, generate a query, or build a chart…'"
|
|
127
|
+
class="flex-1 border rounded px-4 py-2 resize-none overflow-y-auto shadow-sm"
|
|
128
|
+
:disabled="sendingMessage"
|
|
129
|
+
rows="2"
|
|
130
|
+
ref="messageInput"
|
|
131
|
+
@input="adjustTextareaHeight"
|
|
132
|
+
@keydown.enter.exact.prevent="handleEnter"
|
|
133
|
+
></textarea>
|
|
134
|
+
<button class="bg-primary hover:bg-primary-hover text-white px-4 h-[42px] rounded disabled:bg-gray-600" :disabled="sendingMessage">
|
|
135
|
+
<svg v-if="sendingMessage" style="height: 1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
136
|
+
<g>
|
|
137
|
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2" opacity="0.3" />
|
|
138
|
+
<path d="M12 2a10 10 0 0 1 10 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
139
|
+
<animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite" />
|
|
140
|
+
</path>
|
|
141
|
+
</g>
|
|
142
|
+
</svg>
|
|
143
|
+
<span v-else>Send</span>
|
|
144
|
+
</button>
|
|
145
|
+
</form>
|
|
146
|
+
</div>
|
|
147
|
+
</main>
|
|
148
|
+
|
|
149
|
+
<aside
|
|
150
|
+
v-if="isAgentModeEnabled"
|
|
151
|
+
class="hidden lg:flex shrink-0 border-l border-edge bg-page transition-all duration-300 ease-in-out overflow-hidden"
|
|
152
|
+
:class="showAgentSidebar ? 'w-80' : 'w-0 border-l-0'"
|
|
153
|
+
>
|
|
154
|
+
<div v-if="showAgentSidebar" class="flex h-full w-80 flex-col">
|
|
155
|
+
<div class="flex items-center justify-between border-b border-edge px-4 py-3">
|
|
156
|
+
<div>
|
|
157
|
+
<h2 class="text-sm font-semibold text-content">Agent Mode</h2>
|
|
158
|
+
<p class="mt-1 text-xs text-content-tertiary">Agent mode lets Mongoose Studio inspect your data and validate scripts before it responds.</p>
|
|
159
|
+
</div>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
@click="closeAgentSidebar"
|
|
163
|
+
class="rounded p-1.5 text-gray-400 hover:bg-muted hover:text-gray-600"
|
|
164
|
+
title="Hide agent sidebar"
|
|
165
|
+
>
|
|
166
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
167
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
|
168
|
+
</svg>
|
|
169
|
+
</button>
|
|
170
|
+
</div>
|
|
171
|
+
<div class="flex-1 overflow-y-auto px-4 py-4">
|
|
172
|
+
<div class="mb-3 text-xs font-semibold uppercase tracking-wider text-gray-400">Available Tools</div>
|
|
173
|
+
<ul role="list" class="space-y-3">
|
|
174
|
+
<li v-for="tool in agentTools" :key="tool.name" class="rounded-md border border-edge bg-surface px-3 py-3">
|
|
175
|
+
<div class="text-sm font-medium text-content">{{ tool.name }}</div>
|
|
176
|
+
<div class="mt-1 text-sm text-content-secondary">{{ tool.description }}</div>
|
|
177
|
+
</li>
|
|
178
|
+
</ul>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</aside>
|
|
182
|
+
</div>
|
|
136
183
|
|
|
137
184
|
<pro-upgrade-modal
|
|
138
185
|
:show="showProUpgradeModal"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const api = require('../api');
|
|
4
|
+
const agentToolMetadata = require('../../../backend/chatAgent/agentToolMetadata');
|
|
4
5
|
const getCurrentDateTimeContext = require('../getCurrentDateTimeContext');
|
|
5
6
|
const template = require('./chat.html');
|
|
6
7
|
|
|
8
|
+
const AGENT_MODE_STORAGE_KEY = '_mongooseStudioAgentMode';
|
|
9
|
+
|
|
7
10
|
module.exports = {
|
|
8
11
|
template: template,
|
|
9
12
|
props: ['threadId'],
|
|
@@ -12,12 +15,15 @@ module.exports = {
|
|
|
12
15
|
sendingMessage: false,
|
|
13
16
|
newMessage: '',
|
|
14
17
|
chatThreadId: null,
|
|
18
|
+
draftAgentMode: false,
|
|
15
19
|
chatThreads: [],
|
|
16
20
|
chatMessages: [],
|
|
17
21
|
hideSidebar: null,
|
|
22
|
+
showAgentSidebar: false,
|
|
18
23
|
sharingThread: false,
|
|
19
24
|
threadSearch: '',
|
|
20
|
-
showProUpgradeModal: false
|
|
25
|
+
showProUpgradeModal: false,
|
|
26
|
+
agentTools: agentToolMetadata
|
|
21
27
|
}),
|
|
22
28
|
methods: {
|
|
23
29
|
async sendMessage() {
|
|
@@ -26,7 +32,9 @@ module.exports = {
|
|
|
26
32
|
const content = this.newMessage;
|
|
27
33
|
this.newMessage = '';
|
|
28
34
|
if (!this.chatThreadId) {
|
|
29
|
-
const { chatThread } = await api.ChatThread.createChatThread(
|
|
35
|
+
const { chatThread } = await api.ChatThread.createChatThread({
|
|
36
|
+
agentMode: this.draftAgentMode
|
|
37
|
+
});
|
|
30
38
|
this.chatThreads.unshift(chatThread);
|
|
31
39
|
this.chatThreadId = chatThread._id;
|
|
32
40
|
this.chatMessages = [];
|
|
@@ -40,11 +48,7 @@ module.exports = {
|
|
|
40
48
|
role: 'user'
|
|
41
49
|
});
|
|
42
50
|
|
|
43
|
-
this
|
|
44
|
-
if (this.$refs.messagesContainer) {
|
|
45
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
51
|
+
this.scrollToBottom();
|
|
48
52
|
|
|
49
53
|
const params = {
|
|
50
54
|
chatThreadId: this.chatThreadId,
|
|
@@ -53,6 +57,7 @@ module.exports = {
|
|
|
53
57
|
};
|
|
54
58
|
let userChatMessage = null;
|
|
55
59
|
let assistantChatMessage = null;
|
|
60
|
+
const toolCalls = [];
|
|
56
61
|
for await (const event of api.ChatThread.streamChatMessage(params)) {
|
|
57
62
|
if (event.chatMessage) {
|
|
58
63
|
if (!userChatMessage) {
|
|
@@ -61,6 +66,7 @@ module.exports = {
|
|
|
61
66
|
} else {
|
|
62
67
|
const assistantChatMessageIndex = this.chatMessages.indexOf(assistantChatMessage);
|
|
63
68
|
assistantChatMessage = event.chatMessage;
|
|
69
|
+
assistantChatMessage.toolCalls = toolCalls;
|
|
64
70
|
if (assistantChatMessageIndex !== -1) {
|
|
65
71
|
this.chatMessages.splice(assistantChatMessageIndex, 1, assistantChatMessage);
|
|
66
72
|
} else {
|
|
@@ -73,27 +79,44 @@ module.exports = {
|
|
|
73
79
|
thread.title = event.chatThread.title;
|
|
74
80
|
}
|
|
75
81
|
}
|
|
82
|
+
} else if (event.toolCall) {
|
|
83
|
+
toolCalls.push({ toolName: event.toolCall.toolName, input: event.toolCall.input, status: 'running' });
|
|
84
|
+
if (!assistantChatMessage) {
|
|
85
|
+
assistantChatMessage = {
|
|
86
|
+
_id: Math.random().toString(36).substr(2, 9),
|
|
87
|
+
content: '',
|
|
88
|
+
role: 'assistant',
|
|
89
|
+
toolCalls: [...toolCalls]
|
|
90
|
+
};
|
|
91
|
+
this.chatMessages.push(assistantChatMessage);
|
|
92
|
+
assistantChatMessage = this.chatMessages[this.chatMessages.length - 1];
|
|
93
|
+
} else {
|
|
94
|
+
assistantChatMessage.toolCalls = [...toolCalls];
|
|
95
|
+
}
|
|
96
|
+
this.scrollToBottom();
|
|
97
|
+
} else if (event.toolResult) {
|
|
98
|
+
const tc = toolCalls.find(t => t.toolName === event.toolResult.toolName && t.status === 'running');
|
|
99
|
+
if (tc) {
|
|
100
|
+
tc.status = 'done';
|
|
101
|
+
}
|
|
102
|
+
if (assistantChatMessage) {
|
|
103
|
+
assistantChatMessage.toolCalls = [...toolCalls];
|
|
104
|
+
}
|
|
105
|
+
this.scrollToBottom();
|
|
76
106
|
} else if (event.textPart) {
|
|
77
107
|
if (!assistantChatMessage) {
|
|
78
108
|
assistantChatMessage = {
|
|
79
109
|
_id: Math.random().toString(36).substr(2, 9),
|
|
80
110
|
content: event.textPart,
|
|
81
|
-
role: 'assistant'
|
|
111
|
+
role: 'assistant',
|
|
112
|
+
toolCalls: [...toolCalls]
|
|
82
113
|
};
|
|
83
114
|
this.chatMessages.push(assistantChatMessage);
|
|
84
115
|
assistantChatMessage = this.chatMessages[this.chatMessages.length - 1];
|
|
85
|
-
this
|
|
86
|
-
if (this.$refs.messagesContainer) {
|
|
87
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
116
|
+
this.scrollToBottom();
|
|
90
117
|
} else {
|
|
91
118
|
assistantChatMessage.content += event.textPart;
|
|
92
|
-
this
|
|
93
|
-
if (this.$refs.messagesContainer) {
|
|
94
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
95
|
-
}
|
|
96
|
-
});
|
|
119
|
+
this.scrollToBottom();
|
|
97
120
|
}
|
|
98
121
|
} else if (event.message) {
|
|
99
122
|
throw new Error(event.message);
|
|
@@ -112,10 +135,38 @@ module.exports = {
|
|
|
112
135
|
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
113
136
|
}
|
|
114
137
|
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
this.$toast.error(err?.message || 'Failed to send message.');
|
|
115
140
|
} finally {
|
|
116
141
|
this.sendingMessage = false;
|
|
117
142
|
}
|
|
118
143
|
},
|
|
144
|
+
async toggleAgentMode() {
|
|
145
|
+
const wasEnabled = this.isAgentModeEnabled;
|
|
146
|
+
const newValue = !this.isAgentModeEnabled;
|
|
147
|
+
this.draftAgentMode = newValue;
|
|
148
|
+
this.persistAgentModePreference(newValue);
|
|
149
|
+
if (!this.chatThreadId) {
|
|
150
|
+
this.maybeOpenAgentSidebar({ wasEnabled, isEnabled: newValue });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const { chatThread } = await api.ChatThread.toggleAgentMode({
|
|
154
|
+
chatThreadId: this.chatThreadId,
|
|
155
|
+
agentMode: newValue
|
|
156
|
+
});
|
|
157
|
+
const idx = this.chatThreads.findIndex(t => t._id === chatThread._id);
|
|
158
|
+
if (idx !== -1) {
|
|
159
|
+
this.chatThreads.splice(idx, 1, chatThread);
|
|
160
|
+
}
|
|
161
|
+
this.maybeOpenAgentSidebar({ wasEnabled, isEnabled: newValue });
|
|
162
|
+
},
|
|
163
|
+
scrollToBottom() {
|
|
164
|
+
this.$nextTick(() => {
|
|
165
|
+
if (this.$refs.messagesContainer) {
|
|
166
|
+
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
},
|
|
119
170
|
handleEnter(ev) {
|
|
120
171
|
if (!ev.shiftKey) {
|
|
121
172
|
this.sendMessage();
|
|
@@ -135,7 +186,9 @@ module.exports = {
|
|
|
135
186
|
return message.role === 'user' ? 'bg-muted' : '';
|
|
136
187
|
},
|
|
137
188
|
async createNewThread() {
|
|
138
|
-
const { chatThread } = await api.ChatThread.createChatThread(
|
|
189
|
+
const { chatThread } = await api.ChatThread.createChatThread({
|
|
190
|
+
agentMode: this.draftAgentMode
|
|
191
|
+
});
|
|
139
192
|
this.$toast.success('Chat thread created!');
|
|
140
193
|
this.$router.push('/chat/' + chatThread._id);
|
|
141
194
|
},
|
|
@@ -177,12 +230,57 @@ module.exports = {
|
|
|
177
230
|
} finally {
|
|
178
231
|
this.sharingThread = false;
|
|
179
232
|
}
|
|
233
|
+
},
|
|
234
|
+
isDesktopViewport() {
|
|
235
|
+
return typeof window !== 'undefined' &&
|
|
236
|
+
typeof window.matchMedia === 'function' &&
|
|
237
|
+
window.matchMedia('(min-width: 1024px)').matches;
|
|
238
|
+
},
|
|
239
|
+
getAgentModePreference() {
|
|
240
|
+
if (typeof window === 'undefined') {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return window.localStorage?.getItem(AGENT_MODE_STORAGE_KEY) === 'true';
|
|
244
|
+
},
|
|
245
|
+
persistAgentModePreference(agentMode) {
|
|
246
|
+
if (typeof window !== 'undefined') {
|
|
247
|
+
window.localStorage?.setItem(AGENT_MODE_STORAGE_KEY, String(agentMode));
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
async syncCurrentThreadAgentMode() {
|
|
251
|
+
if (!this.chatThreadId || !this.currentThread || !this.draftAgentMode || this.currentThread.agentMode) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const { chatThread } = await api.ChatThread.toggleAgentMode({
|
|
255
|
+
chatThreadId: this.chatThreadId,
|
|
256
|
+
agentMode: true
|
|
257
|
+
});
|
|
258
|
+
const idx = this.chatThreads.findIndex(t => t._id === chatThread._id);
|
|
259
|
+
if (idx !== -1) {
|
|
260
|
+
this.chatThreads.splice(idx, 1, chatThread);
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
maybeOpenAgentSidebar({ wasEnabled, isEnabled }) {
|
|
264
|
+
if (!isEnabled) {
|
|
265
|
+
this.showAgentSidebar = false;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (wasEnabled || !this.isDesktopViewport()) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
this.showAgentSidebar = true;
|
|
272
|
+
},
|
|
273
|
+
closeAgentSidebar() {
|
|
274
|
+
this.showAgentSidebar = false;
|
|
180
275
|
}
|
|
181
276
|
},
|
|
182
277
|
computed: {
|
|
183
278
|
currentThread() {
|
|
184
279
|
return this.chatThreads.find(t => t._id === this.chatThreadId);
|
|
185
280
|
},
|
|
281
|
+
isAgentModeEnabled() {
|
|
282
|
+
return this.currentThread?.agentMode ?? this.draftAgentMode;
|
|
283
|
+
},
|
|
186
284
|
hasWorkspace() {
|
|
187
285
|
return !!window.MONGOOSE_STUDIO_CONFIG.workspace?._id;
|
|
188
286
|
},
|
|
@@ -200,10 +298,12 @@ module.exports = {
|
|
|
200
298
|
async mounted() {
|
|
201
299
|
window.pageState = this;
|
|
202
300
|
|
|
301
|
+
this.draftAgentMode = this.getAgentModePreference();
|
|
203
302
|
this.chatThreadId = this.threadId;
|
|
204
303
|
const { chatThreads } = await api.ChatThread.listChatThreads();
|
|
205
304
|
this.chatThreads = chatThreads;
|
|
206
305
|
if (this.chatThreadId) {
|
|
306
|
+
await this.syncCurrentThreadAgentMode();
|
|
207
307
|
const { chatMessages } = await api.ChatThread.getChatThread({ chatThreadId: this.chatThreadId });
|
|
208
308
|
this.chatMessages = chatMessages;
|
|
209
309
|
}
|
|
@@ -53,6 +53,9 @@ module.exports = app => app.component('create-document', {
|
|
|
53
53
|
documentData: this.aiOriginalDocument,
|
|
54
54
|
currentDateTime: getCurrentDateTimeContext()
|
|
55
55
|
})) {
|
|
56
|
+
if (event?.message) {
|
|
57
|
+
throw new Error(event.message);
|
|
58
|
+
}
|
|
56
59
|
if (event?.textPart) {
|
|
57
60
|
this.aiSuggestion += event.textPart;
|
|
58
61
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<div class="flex space-x-2">
|
|
23
23
|
<async-button @click="updateCode" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500">Submit</async-button>
|
|
24
|
-
<button @click="closeEditor" class="px-4 py-2 bg-
|
|
24
|
+
<button @click="closeEditor" class="px-4 py-2 bg-gray-700 text-white rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500">Cancel</button>
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
@click="stagingSelect"
|
|
118
118
|
type="button"
|
|
119
119
|
:class="{
|
|
120
|
-
'bg-
|
|
120
|
+
'bg-gray-700 ring-inset ring-2 ring-gray-300 hover:bg-gray-200 text-content-secondary': selectMultiple,
|
|
121
121
|
'bg-primary hover:bg-primary-hover text-primary-text': !selectMultiple
|
|
122
122
|
}"
|
|
123
123
|
class="rounded px-2 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<async-button
|
|
18
18
|
type="button"
|
|
19
19
|
@click="loginWithGithub"
|
|
20
|
-
class="rounded bg-primary px-2 py-2 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:bg-
|
|
20
|
+
class="rounded bg-primary px-2 py-2 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:bg-page">
|
|
21
21
|
<svg viewBox="0 0 98 98" class="inline mr-1" height="1.5em" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
|
22
22
|
Login With GitHub
|
|
23
23
|
</async-button>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<async-button
|
|
27
27
|
type="button"
|
|
28
28
|
@click="loginWithGoogle"
|
|
29
|
-
class="rounded bg-primary px-2 py-2 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:bg-
|
|
29
|
+
class="rounded bg-primary px-2 py-2 text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:bg-page">
|
|
30
30
|
<svg class="inline" xmlns="http://www.w3.org/2000/svg" height="1.5em" viewBox="0 0 512 512"><path fill="#fff" d="M386 400c45-42 65-112 53-179H260v74h102c-4 24-18 44-38 57z"/><path fill="#fff" d="M90 341a192 192 0 0 0 296 59l-62-48c-53 35-141 22-171-60z"/><path fill="#fff" d="M153 292c-8-25-8-48 0-73l-63-49c-23 46-30 111 0 171z"/><path fill="#fff" d="M153 219c22-69 116-109 179-50l55-54c-78-75-230-72-297 55z"/></svg>
|
|
31
31
|
Login With Google
|
|
32
32
|
</async-button>
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
@click="showNewInvitationModal = true"
|
|
94
94
|
:disabled="status === 'loading'"
|
|
95
95
|
:tier="workspace?.subscriptionTier"
|
|
96
|
-
class="block rounded-md bg-primary px-3 py-2 text-center text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover disabled:bg-
|
|
96
|
+
class="block rounded-md bg-primary px-3 py-2 text-center text-sm font-semibold text-primary-text shadow-sm hover:bg-primary-hover disabled:bg-page disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary">
|
|
97
97
|
New Invitation
|
|
98
98
|
<svg class="inline w-4 h-4 ml-1" v-if="workspace && !workspace.subscriptionTier" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
|
99
99
|
<path fill-rule="evenodd" d="M12 1.5a5.25 5.25 0 00-5.25 5.25v3a3 3 0 00-3 3v6.75a3 3 0 003 3h10.5a3 3 0 003-3v-6.75a3 3 0 00-3-3v-3c0-2.9-2.35-5.25-5.25-5.25zm3.75 8.25v-3a3.75 3.75 0 10-7.5 0v3h7.5z" clip-rule="evenodd" />
|