@swiss-ai-hub/web 0.316.3 → 0.317.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.
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <Select
3
+ v-model="selectedTenant"
4
+ :options="tenants ?? []"
5
+ option-label="name"
6
+ option-value="id"
7
+ :aria-label="placeholder ?? t('common.selectTenant')"
8
+ :placeholder="placeholder ?? t('common.selectTenant')"
9
+ :filter="filter"
10
+ :loading="isLoading"
11
+ class="w-full"
12
+ >
13
+ <template #option="{ option }">
14
+ <div class="flex items-center gap-2">
15
+ <Icon
16
+ name="mage:building-a"
17
+ size="1.2em"
18
+ />
19
+ <span>{{ option.name }}</span>
20
+ </div>
21
+ </template>
22
+ </Select>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ interface TenantSelectProps {
27
+ context: {
28
+ node: { input: (value: string | null) => void }
29
+ value?: string | null
30
+ placeholder?: string
31
+ filter?: boolean
32
+ }
33
+ }
34
+
35
+ const props = defineProps<TenantSelectProps>()
36
+ const { t } = useI18n()
37
+
38
+ const { tenants, tenantsAreLoading } = useTenantMemberships()
39
+ const { activeTenant, activeTenantIsLoading } = useActiveTenantQuery()
40
+
41
+ const placeholder = computed(() => props.context.placeholder)
42
+ const filter = computed(() => props.context.filter ?? true)
43
+ const isLoading = computed(() => tenantsAreLoading.value || activeTenantIsLoading.value)
44
+
45
+ const selectedTenant = computed({
46
+ get: () => props.context.value ?? null,
47
+ set: (value: string | null) => {
48
+ props.context.node.input(value)
49
+ },
50
+ })
51
+
52
+ // Pre-select the user's active tenant on a fresh field, while leaving an
53
+ // already-configured value (editing an existing instance) untouched.
54
+ watch(
55
+ [activeTenant, () => props.context.value],
56
+ ([active, current]) => {
57
+ if (!current && active?.id) {
58
+ props.context.node.input(active.id)
59
+ }
60
+ },
61
+ { immediate: true },
62
+ )
63
+ </script>
@@ -215,8 +215,13 @@ const handleSort = (event: DataTableSortEvent) => {
215
215
  const downloadFile = async (documentId: string) => {
216
216
  const database = route.params.db as string
217
217
  const namespace = route.params.namespace as string
218
- const url = await getDocumentSourceUrl(tenantId.value!, database, namespace, documentId)
219
- window.open(url, '_blank')
218
+ const url = await getDocumentSourceUrl(tenantId.value!, database, namespace, documentId, true)
219
+ const anchor = document.createElement('a')
220
+ anchor.href = url
221
+ anchor.rel = 'noopener'
222
+ document.body.appendChild(anchor)
223
+ anchor.click()
224
+ anchor.remove()
220
225
  }
221
226
 
222
227
  const confirmDelete = (document: DocumentDto) => {
@@ -1,7 +1,7 @@
1
1
  import { getDocumentUrl } from '@core/sdk/client'
2
2
 
3
3
  export const useDocumentUrl = () => {
4
- const getDocumentSourceUrl = async (tenantId: string, database: string, namespace: string, documentId: string): Promise<string> => {
4
+ const getDocumentSourceUrl = async (tenantId: string, database: string, namespace: string, documentId: string, download = false): Promise<string> => {
5
5
  const { url } = await getDocumentUrl({
6
6
  composable: '$fetch',
7
7
  path: {
@@ -10,6 +10,7 @@ export const useDocumentUrl = () => {
10
10
  namespace,
11
11
  document_id: documentId,
12
12
  },
13
+ query: { download },
13
14
  })
14
15
  return url
15
16
  }
package/formkit.config.ts CHANGED
@@ -4,6 +4,7 @@ import IconSelector from '@core/components/FormKit/IconSelector.vue'
4
4
  import KnowledgeDatabaseSelector from '@core/components/FormKit/KnowledgeDatabaseSelector.vue'
5
5
  import LocaleInput from '@core/components/FormKit/LocaleInput.vue'
6
6
  import ModelSelect from '@core/components/FormKit/ModelSelect.vue'
7
+ import TenantSelect from '@core/components/FormKit/TenantSelect.vue'
7
8
  import VectorStoreInput from '@core/components/FormKit/VectorStoreInput.vue'
8
9
  import { en, de, fr, it } from '@formkit/i18n'
9
10
  import { createInput } from '@formkit/vue'
@@ -14,7 +15,6 @@ import type { DefaultConfigOptions } from '@formkit/vue'
14
15
  const config: DefaultConfigOptions = {
15
16
  inputs: {
16
17
  ...primeInputs,
17
- orgMemoryTenantInput: primeInputs.primeInputText,
18
18
  agentSelector: createInput(AgentSelector, {
19
19
  props: ['startEvent', 'classPlaceholder', 'idPlaceholder', 'filter'],
20
20
  }),
@@ -33,6 +33,9 @@ const config: DefaultConfigOptions = {
33
33
  modelSelect: createInput(ModelSelect, {
34
34
  props: ['mode', 'placeholder', 'filter', 'showClear'],
35
35
  }),
36
+ tenantSelect: createInput(TenantSelect, {
37
+ props: ['placeholder', 'filter'],
38
+ }),
36
39
  vectorStoreInput: createInput(VectorStoreInput, {
37
40
  props: ['databasePlaceholder', 'namespacePlaceholder', 'filter'],
38
41
  }),
@@ -11,6 +11,7 @@ common:
11
11
  loading: Laden...
12
12
  selectModel: Modell auswählen
13
13
  selectDatabase: Datenbank auswählen
14
+ selectTenant: Mandant auswählen
14
15
  models:
15
16
  title: Modelle
16
17
  error: Fehler beim Laden der Modelle
@@ -11,6 +11,7 @@ common:
11
11
  loading: Loading...
12
12
  selectModel: Select a model
13
13
  selectDatabase: Select a database
14
+ selectTenant: Select a tenant
14
15
  models:
15
16
  title: Models
16
17
  error: Error loading models
@@ -11,6 +11,7 @@ common:
11
11
  loading: Chargement...
12
12
  selectModel: Sélectionner un modèle
13
13
  selectDatabase: Sélectionner une base de données
14
+ selectTenant: Sélectionner un locataire
14
15
  models:
15
16
  title: Modèles
16
17
  error: Erreur lors du chargement des modèles
@@ -11,6 +11,7 @@ common:
11
11
  loading: Caricamento...
12
12
  selectModel: Seleziona un modello
13
13
  selectDatabase: Seleziona un database
14
+ selectTenant: Seleziona un tenant
14
15
  models:
15
16
  title: Modelli
16
17
  error: Errore nel caricamento dei modelli
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.316.3",
6
+ "version": "0.317.0",
7
7
  "description": "Swiss AI Hub - Admin & Management UI (Nuxt 3 layer)",
8
8
  "main": "./nuxt.config.ts",
9
9
  "repository": {
@@ -6,9 +6,7 @@
6
6
  size="small"
7
7
  >
8
8
  <div class="flex flex-col gap-4">
9
- <RoleEdit
10
- v-model="clonedRole"
11
- />
9
+ <RoleEdit v-model="clonedRole" />
12
10
  <div class="flex justify-end">
13
11
  <Button
14
12
  type="button"
@@ -40,12 +38,12 @@ const clonedRole = ref<CreateRoleRequest>({
40
38
  description: '',
41
39
  access_rules: [],
42
40
  })
43
- watch(role, (newRole: RoleResponse) => {
41
+ watch(role, (newRole: RoleResponse | undefined) => {
44
42
  if (!newRole) {
45
43
  return
46
44
  }
47
45
  clonedRole.value = cloneDeep(newRole)
48
- })
46
+ }, { immediate: true })
49
47
 
50
48
  const saveRole = async () => {
51
49
  await updateRole({ roleId: role.value.id, updatedRole: clonedRole.value, tenantId: tenantId.value! })
@@ -793,8 +793,6 @@ export {
793
793
  type OpenChatHitlResponseWritable,
794
794
  type OpenWebuiWebhookPayload,
795
795
  type OpenWebuiWebhookUser,
796
- type OrgMemoryTenantInput,
797
- type OrgMemoryTenantInputWritable,
798
796
  type PaginatedDocumentsResponse,
799
797
  type PaginatedNotificationsResponse,
800
798
  type PaginatedProcessWalkthroughsResponse,
@@ -942,6 +940,8 @@ export {
942
940
  type TemplateData,
943
941
  type TenantIdentity,
944
942
  type TenantMembershipDto,
943
+ type TenantSelect,
944
+ type TenantSelectWritable,
945
945
  type Textarea,
946
946
  type TextareaWritable,
947
947
  type TextBlock,