Skip to content

Commit d998ad3

Browse files
authored
fix(data-studio): resolve UI bugs — duplicate status text, permission buttons, cancel action, source persistence, connection filtering (#103)
- Remove duplicate 'Waiting for model...' progress text (already shown in message bubble) - Tone down permission confirmation buttons (text-color styling instead of filled backgrounds) - Fix Cancel button in handleConfirmation to properly stop loop and reset session status - Fix getOrCreateSession to return existing active session instead of creating new one (prevented permissionsMode from resetting to Ask) - Persist session sources and permissions mode to backend on attach/detach/mode change - Expand AGENT_SUPPORTED_TYPES from 4 to 40+ PG/MySQL-wire compatible databases - Improve 'no connections' dropdown message to differentiate empty vs all-attached
1 parent 349f9f3 commit d998ad3

7 files changed

Lines changed: 100 additions & 17 deletions

File tree

src/components/chat-panel.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,7 @@ onBeforeUnmount(() => {
278278
<span v-if="progress.phase === 'iterating'">
279279
{{ t('dataStudio.agent.iteration') }} {{ progress.iter }}/{{ progress.maxIter }}
280280
</span>
281-
<span v-else-if="progress.phase === 'waiting_llm'">
282-
{{ t('dataStudio.agent.waitingModel') }}
283-
</span>
281+
<!-- waiting_llm phase hidden — message bubble activity timeline already shows "Waiting for model" -->
284282
<span v-else-if="progress.phase === 'compacting'">
285283
{{ t('dataStudio.agent.compacting') }}
286284
</span>

src/composables/useChatAgent.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,10 @@ export function useChatAgent(config: UseChatAgentConfig) {
556556
}
557557

558558
case 'cancel': {
559-
// cancelSession is defined below, but the function is hoisted in runtime
560-
cancelSessionHandler()
559+
// Mark tool call as denied first, then cancel the loop
560+
config.sessionStore.updateToolCallStatus(assistantMsgId, toolCallId, 'denied', undefined, undefined, sessionId)
561+
config.sessionStore.setSessionStatus(sessionId, 'idle')
562+
await cancelSessionHandler()
561563
break
562564
}
563565
}

src/lang/enUS.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ export const enUS = {
746746
selectConnection: 'Select Connection',
747747
searchPlaceholder: 'Search connections...',
748748
noConnections: 'No compatible connections found',
749+
allAttached: 'All compatible connections are already attached',
749750
connectionsFound: '{count} connections found',
750751
connectSource: 'Connect',
751752
},

src/lang/zhCN.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ export const zhCN = {
746746
selectConnection: '选择连接',
747747
searchPlaceholder: '搜索连接...',
748748
noConnections: '没有兼容的连接',
749+
allAttached: '所有兼容的连接已添加',
749750
connectionsFound: '找到 {count} 个连接',
750751
connectSource: '连接',
751752
},

src/pages/DataStudioPage.vue

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,54 @@ const { attachedSources, activeSession } = storeToRefs(dataStudioStore)
2323
2424
const { getDatabaseIcon } = useDatabaseIcon()
2525
26-
const AGENT_SUPPORTED_TYPES = new Set([
26+
// All PG-wire and MySQL-wire compatible databases + popular standalone engines
27+
// Knowledge blocks exist for PostgreSQL, MySQL, SQL Server, SQLite dialects;
28+
// wire-compatible types use the same SQL dialect through their respective bridge.
29+
const AGENT_SUPPORTED_TYPES = new Set<DatabaseType>([
30+
// Native adapters (direct knowledge blocks)
2731
DatabaseType.POSTGRESQL,
2832
DatabaseType.MYSQL,
2933
DatabaseType.SQLITE,
3034
DatabaseType.SQLSERVER,
35+
// PG-wire compatible
36+
DatabaseType.MARIADB,
37+
DatabaseType.COCKROACHDB,
38+
DatabaseType.REDSHIFT,
39+
DatabaseType.YUGABYTEDB,
40+
DatabaseType.TIMESCALEDB,
41+
DatabaseType.KINGBASEES,
42+
DatabaseType.GAUSSDB,
43+
DatabaseType.HIGHGO,
44+
DatabaseType.UXDB,
45+
DatabaseType.OPENGAUSS,
46+
DatabaseType.GBASE8C,
47+
DatabaseType.QUESTDB,
48+
DatabaseType.VASTBASE,
49+
DatabaseType.YASHANDB,
50+
DatabaseType.GREENPLUM,
51+
DatabaseType.ENTERPRISEDB,
52+
DatabaseType.CRATEDB,
53+
DatabaseType.MATERIALIZE,
54+
DatabaseType.ALLOYDB,
55+
DatabaseType.CLOUDSQLPG,
56+
DatabaseType.FUJITSUPG,
57+
// MySQL-wire compatible
58+
DatabaseType.TIDB,
59+
DatabaseType.OCEANBASE,
60+
DatabaseType.TDSQL,
61+
DatabaseType.POLARDB,
62+
DatabaseType.DM8,
63+
DatabaseType.DORIS,
64+
DatabaseType.SELECTDB,
65+
DatabaseType.STARROCKS,
66+
DatabaseType.DATABEND,
67+
DatabaseType.GOLDENDB,
68+
DatabaseType.MANTICORESEARCH,
69+
DatabaseType.SINGLESTOREMEMSQL,
70+
DatabaseType.CLOUDSQLMYSQL,
71+
// Popular standalone engines (well-known syntax, LLM understands them)
72+
DatabaseType.DUCKDB,
73+
DatabaseType.ORACLE,
3174
])
3275
3376
const {
@@ -104,6 +147,14 @@ const filteredAddConnections = computed(() => {
104147
: availableAddConnections.value
105148
})
106149
150+
const addSourceEmptyMessage = computed(() => {
151+
if (connections.value.length === 0)
152+
return t('dataStudio.addSource.noConnections')
153+
if (availableAddConnections.value.length === 0)
154+
return t('dataStudio.addSource.allAttached')
155+
return t('dataStudio.addSource.noConnections')
156+
})
157+
107158
function getConnectionMeta(conn: ServerConnection): string {
108159
const label = conn.type
109160
if (conn.type === DatabaseType.SQLITE)
@@ -137,7 +188,7 @@ async function confirmAddSource() {
137188
if (!dataStudioStore.activeSession) {
138189
await dataStudioStore.getOrCreateSession()
139190
}
140-
dataStudioStore.attachSourceToActiveSession(newSource.sourceId)
191+
await dataStudioStore.attachSourceToActiveSession(newSource.sourceId)
141192
if (addSourceMode.value === 'Ask' && dataStudioStore.activeSession) {
142193
dataStudioStore.updateSessionSourceMode(
143194
newSource.sourceId,
@@ -151,9 +202,9 @@ async function confirmAddSource() {
151202
}
152203
}
153204
154-
function setAutoMode(auto: boolean) {
205+
async function setAutoMode(auto: boolean) {
155206
permissionMenuOpen.value = false
156-
dataStudioStore.setSessionPermissionsMode(auto ? 'Auto' : 'Ask')
207+
await dataStudioStore.setSessionPermissionsMode(auto ? 'Auto' : 'Ask')
157208
}
158209
159210
async function switchSession(sessionId: string) {
@@ -357,7 +408,7 @@ function syncAllProviderModels() {
357408
/>
358409
</button>
359410
<div v-if="filteredAddConnections.length === 0" class="add-source-empty">
360-
{{ t('dataStudio.addSource.noConnections') }}
411+
{{ addSourceEmptyMessage }}
361412
</div>
362413
</div>
363414

src/store/dataStudioStore.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,17 @@ export const useDataStudioStore = defineStore('dataStudio', {
360360
return source
361361
},
362362

363-
attachSourceToActiveSession(sourceId: string) {
363+
async _persistSessionSources(sessionId: string) {
364+
const session = this.sessions.find(s => s.id === sessionId)
365+
if (!session)
366+
return
367+
const sourcesJson = JSON.stringify(session.sources)
368+
await agentApi.updateSessionMeta(sessionId, sourcesJson).catch(e =>
369+
console.warn('[persist] Failed to save session sources:', e),
370+
)
371+
},
372+
373+
async attachSourceToActiveSession(sourceId: string) {
364374
const session = this.activeSession
365375
if (!session)
366376
return
@@ -387,9 +397,11 @@ export const useDataStudioStore = defineStore('dataStudio', {
387397
? { ...s, sources: [...s.sources, sessionSource], updated_at: Date.now() }
388398
: s,
389399
)
400+
401+
await this._persistSessionSources(session.id)
390402
},
391403

392-
detachSourceFromSession(sourceId: string) {
404+
async detachSourceFromSession(sourceId: string) {
393405
const session = this.activeSession
394406
if (!session)
395407
return
@@ -407,9 +419,11 @@ export const useDataStudioStore = defineStore('dataStudio', {
407419
}
408420
: s,
409421
)
422+
423+
await this._persistSessionSources(session.id)
410424
},
411425

412-
setSessionPermissionsMode(mode: PermissionsMode) {
426+
async setSessionPermissionsMode(mode: PermissionsMode) {
413427
const session = this.activeSession
414428
if (!session)
415429
return
@@ -419,6 +433,10 @@ export const useDataStudioStore = defineStore('dataStudio', {
419433
? { ...s, permissionsMode: mode, updated_at: Date.now() }
420434
: s,
421435
)
436+
437+
await agentApi.updateSessionMeta(session.id, undefined, mode).catch(e =>
438+
console.warn('[persist] Failed to save permissions mode:', e),
439+
)
422440
},
423441

424442
updateSessionSourcePermissions(sourceId: string, permissions: DataSourcePermissions) {
@@ -501,6 +519,13 @@ export const useDataStudioStore = defineStore('dataStudio', {
501519
return existing
502520
}
503521
}
522+
// Return existing active session instead of creating new one
523+
// Prevents resetting permissionsMode/sources to defaults on sendMessage
524+
if (this.activeSessionId) {
525+
const active = this.sessions.find(s => s.id === this.activeSessionId)
526+
if (active)
527+
return active
528+
}
504529
return await this.createSession()
505530
},
506531

src/views/data-studio/components/tool-confirmation-card.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,35 +46,40 @@ function riskColor(risk: string): string {
4646
<div class="flex flex-wrap gap-1.5">
4747
<Button
4848
size="sm"
49-
variant="default"
49+
variant="outline"
50+
class="text-foreground"
5051
@click="emit('confirm', { toolCallId: props.toolCall.id, action: 'allow_once' })"
5152
>
5253
{{ t('dataStudio.agent.allowOnce') }}
5354
</Button>
5455
<Button
5556
size="sm"
56-
variant="outline"
57+
variant="ghost"
58+
class="text-foreground"
5759
@click="emit('confirm', { toolCallId: props.toolCall.id, action: 'allow_always' })"
5860
>
5961
{{ t('dataStudio.agent.allowAlways') }}
6062
</Button>
6163
<Button
6264
size="sm"
63-
variant="secondary"
65+
variant="ghost"
66+
class="text-muted-foreground"
6467
@click="emit('confirm', { toolCallId: props.toolCall.id, action: 'deny' })"
6568
>
6669
{{ t('dataStudio.agent.deny') }}
6770
</Button>
6871
<Button
6972
size="sm"
70-
variant="destructive"
73+
variant="ghost"
74+
class="text-muted-foreground hover:text-destructive"
7175
@click="emit('confirm', { toolCallId: props.toolCall.id, action: 'deny_always' })"
7276
>
7377
{{ t('dataStudio.agent.denyAlways') }}
7478
</Button>
7579
<Button
7680
size="sm"
7781
variant="ghost"
82+
class="text-muted-foreground"
7883
@click="emit('confirm', { toolCallId: props.toolCall.id, action: 'cancel' })"
7984
>
8085
{{ t('dataStudio.agent.cancelRun') }}

0 commit comments

Comments
 (0)