@swiss-ai-hub/web 0.295.4 → 0.296.1
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/components/Thread/List.vue +18 -1
- package/composables/agent/useAgentInstances.ts +21 -3
- package/composables/thread/useThreads.ts +61 -3
- package/i18n/locales/de.yaml +16 -0
- package/i18n/locales/en.yaml +16 -0
- package/i18n/locales/fr.yaml +16 -0
- package/i18n/locales/it.yaml +16 -0
- package/package.json +1 -1
- package/pages/[tenant]/service/agents.vue +71 -12
- package/pages/[tenant]/service/threads.vue +93 -0
- package/sdk/client/sdk.gen.ts +1 -0
- package/sdk/client/types.gen.ts +60 -0
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<DataTable
|
|
3
3
|
:value="threads"
|
|
4
|
+
lazy
|
|
5
|
+
:sort-field="sortField"
|
|
6
|
+
:sort-order="sortOrder"
|
|
4
7
|
table-style="min-width: 50rem"
|
|
5
8
|
selection-mode="single"
|
|
6
9
|
:selection="selectedThread"
|
|
7
10
|
size="small"
|
|
8
11
|
@update:selection="emit('selected', $event)"
|
|
12
|
+
@sort="onSort"
|
|
9
13
|
>
|
|
10
14
|
<Column
|
|
11
15
|
field="name"
|
|
12
16
|
:header="t('thread.list.name')"
|
|
17
|
+
sortable
|
|
13
18
|
/>
|
|
14
19
|
<Column
|
|
15
20
|
field="agents"
|
|
@@ -50,8 +55,9 @@
|
|
|
50
55
|
</template>
|
|
51
56
|
</Column>
|
|
52
57
|
<Column
|
|
53
|
-
field="
|
|
58
|
+
field="created_at"
|
|
54
59
|
:header="t('thread.list.created')"
|
|
60
|
+
sortable
|
|
55
61
|
>
|
|
56
62
|
<template #body="{ data }">
|
|
57
63
|
<p>{{ formatted(data.created_at) }}</p>
|
|
@@ -112,18 +118,29 @@
|
|
|
112
118
|
|
|
113
119
|
<script setup lang="ts">
|
|
114
120
|
import type { ThreadDto, MinimalUserDto } from '@core/sdk/client'
|
|
121
|
+
import type { DataTableSortEvent } from 'primevue'
|
|
115
122
|
|
|
116
123
|
const route = useRoute()
|
|
117
124
|
const { t } = useI18n()
|
|
118
125
|
|
|
119
126
|
const props = defineProps<{
|
|
120
127
|
threads: ThreadDto[]
|
|
128
|
+
sortField: string
|
|
129
|
+
sortOrder: 1 | -1
|
|
121
130
|
}>()
|
|
122
131
|
|
|
123
132
|
const emit = defineEmits<{
|
|
124
133
|
selected: [thread: ThreadDto]
|
|
134
|
+
sort: [payload: { field: string, order: 1 | -1 }]
|
|
125
135
|
}>()
|
|
126
136
|
|
|
137
|
+
const onSort = (event: DataTableSortEvent) => {
|
|
138
|
+
emit('sort', {
|
|
139
|
+
field: event.sortField as string,
|
|
140
|
+
order: (event.sortOrder ?? -1) as 1 | -1,
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
127
144
|
const initials = (user: MinimalUserDto) => user.name?.split(' ').map(n => n[0]).join('')
|
|
128
145
|
const formatted = (datestr: string) => useDateFormat(new Date(datestr), 'DD.MM.YYYY HH:mm:ss')
|
|
129
146
|
const { pendingType } = useThreadUtils()
|
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
import { type FullAgentInstanceDto, getAllAgentInstances } from '@core/sdk/client'
|
|
2
2
|
import { minutesToMilliseconds } from 'date-fns'
|
|
3
3
|
|
|
4
|
-
export const useAgentInstances = defineQuery((
|
|
4
|
+
export const useAgentInstances = defineQuery(() => {
|
|
5
5
|
const { tenantId } = useTenant()
|
|
6
|
+
const searchQuery = ref<string | null>(null)
|
|
7
|
+
const agentClass = useRouteQuery<string | null>('agent_type', null)
|
|
8
|
+
const status = useRouteQuery<string | null>('agent_status', null)
|
|
9
|
+
|
|
10
|
+
const debouncedSearch = refDebounced(searchQuery, 300)
|
|
11
|
+
|
|
12
|
+
const getOnlineStatus = () => {
|
|
13
|
+
if (status.value === 'enabled') return true
|
|
14
|
+
if (status.value === 'disabled') return false
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
6
17
|
|
|
7
18
|
const { data: agentInstances, isPending: agentInstancesAreLoading } = useQuery<FullAgentInstanceDto[]>({
|
|
8
|
-
key: () => ['tenant', tenantId.value, 'agent-instances',
|
|
19
|
+
key: () => ['tenant', tenantId.value, 'agent-instances', status.value, agentClass.value, debouncedSearch.value],
|
|
9
20
|
staleTime: minutesToMilliseconds(5),
|
|
10
21
|
enabled: useTenantReady(),
|
|
22
|
+
placeholderData: previousData => previousData,
|
|
11
23
|
query: async () => {
|
|
12
24
|
return await getAllAgentInstances({
|
|
13
25
|
composable: '$fetch',
|
|
14
26
|
path: { tenant_id: tenantId.value! },
|
|
15
27
|
query: {
|
|
16
|
-
online:
|
|
28
|
+
online: getOnlineStatus(),
|
|
29
|
+
agent_class: agentClass.value || undefined,
|
|
30
|
+
search: debouncedSearch.value || undefined,
|
|
17
31
|
},
|
|
18
32
|
})
|
|
19
33
|
},
|
|
20
34
|
})
|
|
35
|
+
|
|
21
36
|
return {
|
|
22
37
|
agentInstances,
|
|
23
38
|
agentInstancesAreLoading,
|
|
39
|
+
searchQuery,
|
|
40
|
+
agentClass,
|
|
41
|
+
status,
|
|
24
42
|
}
|
|
25
43
|
})
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { getUserThreads, type ThreadDto } from '@core/sdk/client'
|
|
2
|
+
import { endOfDay } from 'date-fns/endOfDay'
|
|
3
|
+
import { format } from 'date-fns/format'
|
|
4
|
+
import { startOfDay } from 'date-fns/startOfDay'
|
|
5
|
+
|
|
6
|
+
export type ThreadSortField = 'created_at' | 'name'
|
|
7
|
+
export type ThreadSortOrder = 1 | -1
|
|
2
8
|
|
|
3
9
|
export const useThreads = defineQuery(() => {
|
|
4
10
|
const { tenantId } = useTenant()
|
|
5
11
|
const currentPage = ref(1)
|
|
6
12
|
const pageSize = ref(10)
|
|
13
|
+
const sortField = ref<ThreadSortField>('created_at')
|
|
14
|
+
const sortOrder = ref<ThreadSortOrder>(-1)
|
|
15
|
+
const searchQuery = ref<string | null>(null)
|
|
16
|
+
const debouncedSearch = refDebounced(searchQuery, 300)
|
|
17
|
+
const agentInstanceId = useRouteQuery<string | null>('agent_id', null)
|
|
18
|
+
const userSearchId = useRouteQuery<string | null>('user_id', null)
|
|
19
|
+
const status = useRouteQuery<string | null>('thread_status', null)
|
|
20
|
+
const fromDate = useRouteQuery<string | null>('from', null)
|
|
21
|
+
const toDate = useRouteQuery<string | null>('to', null)
|
|
7
22
|
|
|
8
23
|
const threadsQuery = useQuery({
|
|
9
|
-
key: () => ['tenant', tenantId.value, 'threads',
|
|
24
|
+
key: () => ['tenant', tenantId.value, 'threads', currentPage.value, pageSize.value, sortField.value, sortOrder.value, debouncedSearch.value, agentInstanceId.value, userSearchId.value, status.value, fromDate.value, toDate.value],
|
|
10
25
|
enabled: useTenantReady(),
|
|
26
|
+
placeholderData: previousData => previousData,
|
|
11
27
|
query: async () => {
|
|
12
28
|
const pageToFetch = Math.max(1, currentPage.value)
|
|
13
29
|
|
|
@@ -17,10 +33,17 @@ export const useThreads = defineQuery(() => {
|
|
|
17
33
|
query: {
|
|
18
34
|
page: pageToFetch,
|
|
19
35
|
page_size: pageSize.value,
|
|
36
|
+
sort_field: sortField.value,
|
|
37
|
+
sort_order: sortOrder.value,
|
|
38
|
+
search: debouncedSearch.value || undefined,
|
|
39
|
+
agent_id: agentInstanceId.value || undefined,
|
|
40
|
+
user_id: userSearchId.value || undefined,
|
|
41
|
+
status: status.value || undefined,
|
|
42
|
+
from: fromDate.value ? startOfDay(new Date(fromDate.value)).toISOString() : undefined,
|
|
43
|
+
to: toDate.value ? endOfDay(new Date(toDate.value)).toISOString() : undefined,
|
|
20
44
|
},
|
|
21
45
|
})
|
|
22
46
|
},
|
|
23
|
-
placeholderData: previousData => previousData,
|
|
24
47
|
})
|
|
25
48
|
|
|
26
49
|
const setPageSize = (newSize: number) => {
|
|
@@ -49,7 +72,34 @@ export const useThreads = defineQuery(() => {
|
|
|
49
72
|
|
|
50
73
|
const threads = computed(() => (threadsQuery.state.value?.data)?.threads ?? [] as ThreadDto[])
|
|
51
74
|
|
|
52
|
-
const isLoading = computed(() => threadsQuery.asyncStatus.value === 'loading')
|
|
75
|
+
const isLoading = computed(() => threadsQuery.asyncStatus.value === 'loading' && !threadsQuery.state.value?.data)
|
|
76
|
+
|
|
77
|
+
const setSort = (field: ThreadSortField, order: ThreadSortOrder) => {
|
|
78
|
+
sortField.value = field
|
|
79
|
+
sortOrder.value = order
|
|
80
|
+
currentPage.value = 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const dateRange = computed<(Date | null)[] | null>({
|
|
84
|
+
get() {
|
|
85
|
+
if (!fromDate.value && !toDate.value) return null
|
|
86
|
+
|
|
87
|
+
return [
|
|
88
|
+
fromDate.value ? new Date(fromDate.value) : null,
|
|
89
|
+
toDate.value ? new Date(toDate.value) : null,
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
set(range) {
|
|
93
|
+
const [start, end] = range ?? [null, null]
|
|
94
|
+
if (range && start && !end) return
|
|
95
|
+
|
|
96
|
+
fromDate.value = start ? format(start, 'yyyy-MM-dd') : null
|
|
97
|
+
toDate.value = end ? format(end, 'yyyy-MM-dd') : null
|
|
98
|
+
currentPage.value = 1
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
watch([status, agentInstanceId, userSearchId, debouncedSearch], () => currentPage.value = 1)
|
|
53
103
|
|
|
54
104
|
return {
|
|
55
105
|
threads,
|
|
@@ -59,6 +109,14 @@ export const useThreads = defineQuery(() => {
|
|
|
59
109
|
pageSize,
|
|
60
110
|
setPage,
|
|
61
111
|
setPageSize,
|
|
112
|
+
setSort,
|
|
62
113
|
refetch: threadsQuery.refetch,
|
|
114
|
+
sortField,
|
|
115
|
+
sortOrder,
|
|
116
|
+
searchQuery,
|
|
117
|
+
agentInstanceId,
|
|
118
|
+
userSearchId,
|
|
119
|
+
status,
|
|
120
|
+
dateRange,
|
|
63
121
|
}
|
|
64
122
|
})
|
package/i18n/locales/de.yaml
CHANGED
|
@@ -140,6 +140,15 @@ thread:
|
|
|
140
140
|
numEvents: Anzahl der Ereignisse
|
|
141
141
|
status: Status
|
|
142
142
|
pending: Ausstehend
|
|
143
|
+
search_placeholder: Nach Namen suchen
|
|
144
|
+
filter:
|
|
145
|
+
status_placeholder: Nach Status filtern
|
|
146
|
+
active: Aktiv
|
|
147
|
+
completed: Abgeschlossen
|
|
148
|
+
failed: Fehlgeschlagen
|
|
149
|
+
agent_name_placeholder: Nach Agent filtern
|
|
150
|
+
user_name_placeholder: Nach Benutzer filtern
|
|
151
|
+
date_range_placeholder: Nach Datum filtern
|
|
143
152
|
utils:
|
|
144
153
|
pendingTypes:
|
|
145
154
|
hitl: Mensch in der Schleife
|
|
@@ -341,6 +350,13 @@ agent:
|
|
|
341
350
|
online: Online
|
|
342
351
|
offline: Offline
|
|
343
352
|
clone: Klonen
|
|
353
|
+
search_placeholder: Nach Namen suchen
|
|
354
|
+
no_results: Keine Agenten gefunden
|
|
355
|
+
filter:
|
|
356
|
+
type_placeholder: Nach Agententyp filtern
|
|
357
|
+
status_placeholder: Nach Status filtern
|
|
358
|
+
enabled: Aktiviert
|
|
359
|
+
disabled: Deaktiviert
|
|
344
360
|
workflow:
|
|
345
361
|
title: Agenten-Workflow
|
|
346
362
|
view_tooltip: Workflow anzeigen
|
package/i18n/locales/en.yaml
CHANGED
|
@@ -139,6 +139,15 @@ thread:
|
|
|
139
139
|
numEvents: Number of Events
|
|
140
140
|
status: Status
|
|
141
141
|
pending: Pending
|
|
142
|
+
search_placeholder: Search by name
|
|
143
|
+
filter:
|
|
144
|
+
status_placeholder: Filter by status
|
|
145
|
+
active: Active
|
|
146
|
+
completed: Completed
|
|
147
|
+
failed: Failed
|
|
148
|
+
agent_name_placeholder: Filter by agent
|
|
149
|
+
user_name_placeholder: Filter by user
|
|
150
|
+
date_range_placeholder: Filter by date
|
|
142
151
|
utils:
|
|
143
152
|
pendingTypes:
|
|
144
153
|
hitl: Human in the Loop
|
|
@@ -337,6 +346,13 @@ agent:
|
|
|
337
346
|
online: Online
|
|
338
347
|
offline: Offline
|
|
339
348
|
clone: Clone
|
|
349
|
+
search_placeholder: Search by name
|
|
350
|
+
no_results: No agents found
|
|
351
|
+
filter:
|
|
352
|
+
type_placeholder: Filter by agent type
|
|
353
|
+
status_placeholder: Filter by status
|
|
354
|
+
enabled: Enabled
|
|
355
|
+
disabled: Disabled
|
|
340
356
|
workflow:
|
|
341
357
|
title: Agentic Workflow
|
|
342
358
|
view_tooltip: View workflow
|
package/i18n/locales/fr.yaml
CHANGED
|
@@ -139,6 +139,15 @@ thread:
|
|
|
139
139
|
numEvents: Nombre d'événements
|
|
140
140
|
status: Statut
|
|
141
141
|
pending: En attente
|
|
142
|
+
search_placeholder: Rechercher par nom
|
|
143
|
+
filter:
|
|
144
|
+
status_placeholder: Filtrer par statut
|
|
145
|
+
active: Actif
|
|
146
|
+
completed: Terminé
|
|
147
|
+
failed: Échoué
|
|
148
|
+
agent_name_placeholder: Filtrer par agent
|
|
149
|
+
user_name_placeholder: Filtrer par utilisateur
|
|
150
|
+
date_range_placeholder: Filtrer par date
|
|
142
151
|
utils:
|
|
143
152
|
pendingTypes:
|
|
144
153
|
hitl: Humain dans la boucle
|
|
@@ -338,6 +347,13 @@ agent:
|
|
|
338
347
|
online: En ligne
|
|
339
348
|
offline: Hors ligne
|
|
340
349
|
clone: Cloner
|
|
350
|
+
search_placeholder: Rechercher par nom
|
|
351
|
+
no_results: Aucun agent trouvé
|
|
352
|
+
filter:
|
|
353
|
+
type_placeholder: Filtrer par type d'agent
|
|
354
|
+
status_placeholder: Filtrer par statut
|
|
355
|
+
enabled: Activé
|
|
356
|
+
disabled: Désactivé
|
|
341
357
|
workflow:
|
|
342
358
|
title: Flux de travail agentique
|
|
343
359
|
view_tooltip: Afficher le flux de travail
|
package/i18n/locales/it.yaml
CHANGED
|
@@ -139,6 +139,15 @@ thread:
|
|
|
139
139
|
numEvents: Numero di eventi
|
|
140
140
|
status: Stato
|
|
141
141
|
pending: In attesa
|
|
142
|
+
search_placeholder: Cerca per nome
|
|
143
|
+
filter:
|
|
144
|
+
status_placeholder: Filtra per stato
|
|
145
|
+
active: Attivo
|
|
146
|
+
completed: Completato
|
|
147
|
+
failed: Fallito
|
|
148
|
+
agent_name_placeholder: Filtra per agente
|
|
149
|
+
user_name_placeholder: Filtra per utente
|
|
150
|
+
date_range_placeholder: Filtra per data
|
|
142
151
|
utils:
|
|
143
152
|
pendingTypes:
|
|
144
153
|
hitl: Umano nel loop
|
|
@@ -338,6 +347,13 @@ agent:
|
|
|
338
347
|
online: Online
|
|
339
348
|
offline: Offline
|
|
340
349
|
clone: Clonare
|
|
350
|
+
search_placeholder: Cerca per nome
|
|
351
|
+
no_results: Nessun agente trovato
|
|
352
|
+
filter:
|
|
353
|
+
type_placeholder: Filtra per tipo di agente
|
|
354
|
+
status_placeholder: Filtra per stato
|
|
355
|
+
enabled: Abilitato
|
|
356
|
+
disabled: Disabilitato
|
|
341
357
|
workflow:
|
|
342
358
|
title: Flusso di lavoro agentico
|
|
343
359
|
view_tooltip: Visualizza il flusso di lavoro
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"license": "AGPL-3.0-or-later",
|
|
4
4
|
"author": "bbv Software Services AG (https://www.bbv.ch)",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.296.1",
|
|
7
7
|
"description": "Swiss AI Hub - Admin & Management UI (Nuxt 3 layer)",
|
|
8
8
|
"main": "./nuxt.config.ts",
|
|
9
9
|
"repository": {
|
|
@@ -6,20 +6,50 @@
|
|
|
6
6
|
:loading="isLoading"
|
|
7
7
|
size="large"
|
|
8
8
|
>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
<div class="flex justify-between">
|
|
10
|
+
<SelectButton
|
|
11
|
+
:model-value="activeNavItem"
|
|
12
|
+
:options="navItems"
|
|
13
|
+
data-key="key"
|
|
14
|
+
option-label="name"
|
|
15
|
+
size="small"
|
|
16
|
+
@update:model-value="toNavItem"
|
|
17
|
+
/>
|
|
18
|
+
<div class="flex items-center gap-4">
|
|
19
|
+
<Select
|
|
20
|
+
v-model="agentClass"
|
|
21
|
+
:options="agentClassOptions"
|
|
22
|
+
option-label="label"
|
|
23
|
+
option-value="value"
|
|
24
|
+
:placeholder="t('agent.list.filter.type_placeholder')"
|
|
25
|
+
show-clear
|
|
26
|
+
class="w-52"
|
|
27
|
+
/>
|
|
28
|
+
<Select
|
|
29
|
+
v-model="status"
|
|
30
|
+
:options="statusOptions"
|
|
31
|
+
option-label="label"
|
|
32
|
+
option-value="value"
|
|
33
|
+
:placeholder="t('agent.list.filter.status_placeholder')"
|
|
34
|
+
show-clear
|
|
35
|
+
class="w-52"
|
|
36
|
+
/>
|
|
37
|
+
<InputText
|
|
38
|
+
v-model="searchQuery"
|
|
39
|
+
:placeholder="t('agent.list.search_placeholder')"
|
|
40
|
+
class="w-80"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="flex flex-col gap-8 pt-4">
|
|
18
45
|
<div
|
|
19
46
|
v-for="group in groupedAgents"
|
|
20
47
|
:key="group.agentClass"
|
|
21
48
|
>
|
|
22
|
-
<div
|
|
49
|
+
<div
|
|
50
|
+
v-if="group.instances.length > 0 && !showNoResults"
|
|
51
|
+
class="pb-4"
|
|
52
|
+
>
|
|
23
53
|
<div class="flex items-center gap-2 pb-2">
|
|
24
54
|
<Icon
|
|
25
55
|
:name="group.icon"
|
|
@@ -58,11 +88,17 @@
|
|
|
58
88
|
@clone="handleClone"
|
|
59
89
|
/>
|
|
60
90
|
<AgentEmptyCard
|
|
61
|
-
v-if="group.isAvailable"
|
|
91
|
+
v-if="group.isAvailable && (!searchQuery && !status && !agentClass)"
|
|
62
92
|
@add="openCreateModal(group.agentClass)"
|
|
63
93
|
/>
|
|
64
94
|
</div>
|
|
65
95
|
</div>
|
|
96
|
+
<div
|
|
97
|
+
v-if="showNoResults"
|
|
98
|
+
class="flex items-center justify-center py-8 text-surface-500"
|
|
99
|
+
>
|
|
100
|
+
<span class="text-xl">{{ t('agent.list.no_results') }}</span>
|
|
101
|
+
</div>
|
|
66
102
|
</div>
|
|
67
103
|
<AgentCreateModal
|
|
68
104
|
v-model="createModalOpen"
|
|
@@ -99,7 +135,7 @@ const route = useRoute()
|
|
|
99
135
|
const tenantPath = useTenantPath()
|
|
100
136
|
const { t, locale } = useI18n()
|
|
101
137
|
|
|
102
|
-
const { agentInstances, agentInstancesAreLoading } = useAgentInstances()
|
|
138
|
+
const { agentInstances, agentInstancesAreLoading, searchQuery, agentClass, status } = useAgentInstances()
|
|
103
139
|
const { agentClasses, agentClassesAreLoading } = useAgentClasses()
|
|
104
140
|
const { navItems, activeNavItem, toNavItem } = useAgentNavigation()
|
|
105
141
|
|
|
@@ -113,6 +149,29 @@ const initialDataForCreate = ref<Record<string, unknown> | null>(null)
|
|
|
113
149
|
const workflowModalOpen = ref(false)
|
|
114
150
|
const selectedGroupForWorkflow = ref<AgentGroup | null>(null)
|
|
115
151
|
|
|
152
|
+
const agentClassOptions = computed(() => {
|
|
153
|
+
if (!agentClasses.value) return []
|
|
154
|
+
|
|
155
|
+
return agentClasses.value.map(c => ({
|
|
156
|
+
label: c.name?.[locale.value] ?? c.agent_class,
|
|
157
|
+
value: c.agent_class,
|
|
158
|
+
}))
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
const statusOptions = computed(() => [
|
|
163
|
+
{ label: t('agent.list.filter.enabled'), value: 'enabled' },
|
|
164
|
+
{ label: t('agent.list.filter.disabled'), value: 'disabled' },
|
|
165
|
+
])
|
|
166
|
+
|
|
167
|
+
const hasVisibleInstances = computed(() =>
|
|
168
|
+
groupedAgents.value.some(group => group.instances.length > 0),
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
const showNoResults = computed(() =>
|
|
172
|
+
!hasVisibleInstances.value && (!!searchQuery.value || !!agentClass.value || !!status.value),
|
|
173
|
+
)
|
|
174
|
+
|
|
116
175
|
const openWorkflowModal = (group: AgentGroup) => {
|
|
117
176
|
selectedGroupForWorkflow.value = group
|
|
118
177
|
workflowModalOpen.value = true
|
|
@@ -4,9 +4,59 @@
|
|
|
4
4
|
:title="t('thread.title')"
|
|
5
5
|
:loading="isLoading"
|
|
6
6
|
>
|
|
7
|
+
<div class="mb-4 flex items-center justify-between">
|
|
8
|
+
<div class="mr-2 flex items-center gap-2">
|
|
9
|
+
<DatePicker
|
|
10
|
+
v-model="dateRange"
|
|
11
|
+
show-button-bar
|
|
12
|
+
selection-mode="range"
|
|
13
|
+
:manual-input="false"
|
|
14
|
+
:placeholder="t('thread.list.filter.date_range_placeholder')"
|
|
15
|
+
update-model-type="string"
|
|
16
|
+
show-clear
|
|
17
|
+
show-icon
|
|
18
|
+
date-format="yy-mm-dd"
|
|
19
|
+
class="w-48"
|
|
20
|
+
/>
|
|
21
|
+
<Select
|
|
22
|
+
v-model="status"
|
|
23
|
+
:options="statusOptions"
|
|
24
|
+
option-label="label"
|
|
25
|
+
option-value="value"
|
|
26
|
+
:placeholder="t('thread.list.filter.status_placeholder')"
|
|
27
|
+
show-clear
|
|
28
|
+
class="w-48"
|
|
29
|
+
/>
|
|
30
|
+
<Select
|
|
31
|
+
v-model="agentInstanceId"
|
|
32
|
+
:options="agentInstanceOptions"
|
|
33
|
+
option-label="label"
|
|
34
|
+
option-value="value"
|
|
35
|
+
:placeholder="t('thread.list.filter.agent_name_placeholder')"
|
|
36
|
+
show-clear
|
|
37
|
+
class="w-48"
|
|
38
|
+
/>
|
|
39
|
+
<Select
|
|
40
|
+
v-model="userSearchId"
|
|
41
|
+
:options="userOptions"
|
|
42
|
+
option-label="label"
|
|
43
|
+
option-value="value"
|
|
44
|
+
:placeholder="t('thread.list.filter.user_name_placeholder')"
|
|
45
|
+
show-clear
|
|
46
|
+
class="w-48"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
<InputText
|
|
50
|
+
v-model="searchQuery"
|
|
51
|
+
:placeholder="t('thread.list.search_placeholder')"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
7
54
|
<ThreadList
|
|
8
55
|
:threads="threads"
|
|
56
|
+
:sort-field="sortField"
|
|
57
|
+
:sort-order="sortOrder"
|
|
9
58
|
@selected="toThread"
|
|
59
|
+
@sort="onSort"
|
|
10
60
|
/>
|
|
11
61
|
|
|
12
62
|
<div class="mt-4">
|
|
@@ -15,6 +65,8 @@
|
|
|
15
65
|
:total-records="pagination.total"
|
|
16
66
|
:rows-per-page-options="[10, 20, 30, 50]"
|
|
17
67
|
:first="(currentPage - 1) * pageSize"
|
|
68
|
+
template="FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink RowsPerPageDropdown"
|
|
69
|
+
current-page-report-template="Showing {first} to {last} of {totalRecords}"
|
|
18
70
|
@page="onPageChange"
|
|
19
71
|
/>
|
|
20
72
|
</div>
|
|
@@ -38,8 +90,23 @@ const {
|
|
|
38
90
|
pageSize,
|
|
39
91
|
setPage,
|
|
40
92
|
setPageSize,
|
|
93
|
+
sortField,
|
|
94
|
+
sortOrder,
|
|
95
|
+
setSort,
|
|
96
|
+
searchQuery,
|
|
97
|
+
agentInstanceId,
|
|
98
|
+
userSearchId,
|
|
99
|
+
status,
|
|
100
|
+
dateRange,
|
|
41
101
|
} = useThreads()
|
|
42
102
|
|
|
103
|
+
const { agentInstances } = useAgentInstances()
|
|
104
|
+
|
|
105
|
+
const { users } = useUsers()
|
|
106
|
+
|
|
107
|
+
const onSort = ({ field, order }: { field: string, order: 1 | -1 }) =>
|
|
108
|
+
setSort(field as ThreadSortField, order)
|
|
109
|
+
|
|
43
110
|
const toThread = (thread: ThreadDto) => {
|
|
44
111
|
router.push(tenantPath(`/service/threads/${thread.id}/overview`))
|
|
45
112
|
}
|
|
@@ -49,4 +116,30 @@ const onPageChange = (event) => {
|
|
|
49
116
|
const newPage = Math.floor(event.first / event.rows) + 1
|
|
50
117
|
setPage(newPage)
|
|
51
118
|
}
|
|
119
|
+
|
|
120
|
+
const agentInstanceOptions = computed(() => {
|
|
121
|
+
if (!agentInstances.value) return []
|
|
122
|
+
|
|
123
|
+
return agentInstances.value.map(agentInstance => ({
|
|
124
|
+
label: agentInstance.agent_config.name,
|
|
125
|
+
value: agentInstance.agent_config.agent_id,
|
|
126
|
+
}))
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
const userOptions = computed(() => {
|
|
131
|
+
if (!users.value) return []
|
|
132
|
+
|
|
133
|
+
return users.value.map(user => ({
|
|
134
|
+
label: user.name,
|
|
135
|
+
value: user.id,
|
|
136
|
+
}))
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const statusOptions = computed(() => [
|
|
141
|
+
{ label: t('thread.list.filter.active'), value: 'active' },
|
|
142
|
+
{ label: t('thread.list.filter.completed'), value: 'completed' },
|
|
143
|
+
{ label: t('thread.list.filter.failed'), value: 'failed' },
|
|
144
|
+
])
|
|
52
145
|
</script>
|
package/sdk/client/sdk.gen.ts
CHANGED
|
@@ -1429,6 +1429,7 @@ export const getAgentInstanceThreads = <
|
|
|
1429
1429
|
*
|
|
1430
1430
|
* Retrieve a list of all agent instances across all classes.
|
|
1431
1431
|
* Use `?online=true` for online instances only, `?online=false` for offline only.
|
|
1432
|
+
* Use `?search={agentName}` to search an agent with its name.
|
|
1432
1433
|
*/
|
|
1433
1434
|
export const getAllAgentInstances = <
|
|
1434
1435
|
TComposable extends Composable = "$fetch",
|
package/sdk/client/types.gen.ts
CHANGED
|
@@ -24311,6 +24311,42 @@ export type GetUserThreadsData = {
|
|
|
24311
24311
|
tenant_id: string;
|
|
24312
24312
|
};
|
|
24313
24313
|
query?: {
|
|
24314
|
+
/**
|
|
24315
|
+
* Search
|
|
24316
|
+
*
|
|
24317
|
+
* Search by thread name
|
|
24318
|
+
*/
|
|
24319
|
+
search?: string | null;
|
|
24320
|
+
/**
|
|
24321
|
+
* Agent Id
|
|
24322
|
+
*
|
|
24323
|
+
* Filter by agent id
|
|
24324
|
+
*/
|
|
24325
|
+
agent_id?: string | null;
|
|
24326
|
+
/**
|
|
24327
|
+
* User Id
|
|
24328
|
+
*
|
|
24329
|
+
* Filter by user id
|
|
24330
|
+
*/
|
|
24331
|
+
user_id?: string | null;
|
|
24332
|
+
/**
|
|
24333
|
+
* Status
|
|
24334
|
+
*
|
|
24335
|
+
* Filter by status: active, completed, failed
|
|
24336
|
+
*/
|
|
24337
|
+
status?: string | null;
|
|
24338
|
+
/**
|
|
24339
|
+
* From
|
|
24340
|
+
*
|
|
24341
|
+
* Filter threads created from this date
|
|
24342
|
+
*/
|
|
24343
|
+
from?: string | null;
|
|
24344
|
+
/**
|
|
24345
|
+
* To
|
|
24346
|
+
*
|
|
24347
|
+
* Filter threads created up to this date
|
|
24348
|
+
*/
|
|
24349
|
+
to?: string | null;
|
|
24314
24350
|
/**
|
|
24315
24351
|
* Page Number
|
|
24316
24352
|
*
|
|
@@ -24323,6 +24359,18 @@ export type GetUserThreadsData = {
|
|
|
24323
24359
|
* Number of items per page (maximum 100)
|
|
24324
24360
|
*/
|
|
24325
24361
|
page_size?: number;
|
|
24362
|
+
/**
|
|
24363
|
+
* Sort Field
|
|
24364
|
+
*
|
|
24365
|
+
* Field to sort by: name, created_at
|
|
24366
|
+
*/
|
|
24367
|
+
sort_field?: string;
|
|
24368
|
+
/**
|
|
24369
|
+
* Sort Order
|
|
24370
|
+
*
|
|
24371
|
+
* Sort order: 1 for ascending, -1 for descending
|
|
24372
|
+
*/
|
|
24373
|
+
sort_order?: -1 | 1;
|
|
24326
24374
|
};
|
|
24327
24375
|
url: "/{tenant_id}/threads/";
|
|
24328
24376
|
};
|
|
@@ -24974,6 +25022,18 @@ export type GetAllAgentInstancesData = {
|
|
|
24974
25022
|
* Filter by online status
|
|
24975
25023
|
*/
|
|
24976
25024
|
online?: boolean | null;
|
|
25025
|
+
/**
|
|
25026
|
+
* Agent Class
|
|
25027
|
+
*
|
|
25028
|
+
* Filter by agent class
|
|
25029
|
+
*/
|
|
25030
|
+
agent_class?: string | null;
|
|
25031
|
+
/**
|
|
25032
|
+
* Search
|
|
25033
|
+
*
|
|
25034
|
+
* Search by agent name
|
|
25035
|
+
*/
|
|
25036
|
+
search?: string | null;
|
|
24977
25037
|
};
|
|
24978
25038
|
url: "/{tenant_id}/agents/instances";
|
|
24979
25039
|
};
|