@swiss-ai-hub/web 0.319.0 → 0.320.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/{pages/auth/login.vue → components/Auth/LoginPanel.vue} +3 -33
- package/components/FormKit/CronInput.vue +208 -0
- package/components/Knowledge/Document/List.vue +20 -9
- package/composables/app/useAppVersion.ts +30 -11
- package/composables/document/useScheduledDeletions.ts +16 -8
- package/formkit.config.ts +34 -3
- package/i18n/locales/de.yaml +24 -0
- package/i18n/locales/en.yaml +23 -0
- package/i18n/locales/fr.yaml +24 -0
- package/i18n/locales/it.yaml +24 -0
- package/middleware/auth.global.ts +34 -16
- package/package.json +1 -1
- package/pages/auth/login/[idp].vue +57 -0
- package/pages/auth/login/index.vue +46 -0
- package/sdk/client/client/client.gen.ts +1 -3
- package/sdk/client/client/types.gen.ts +7 -13
- package/sdk/client/client/utils.gen.ts +1 -2
- package/sdk/client/core/queryKeySerializer.gen.ts +1 -6
- package/sdk/client/core/types.gen.ts +5 -3
- package/sdk/client/index.ts +18 -2
- package/sdk/client/schemas.gen.ts +614 -171
- package/sdk/client/sdk.gen.ts +72 -0
- package/sdk/client/types.gen.ts +568 -159
|
@@ -6,20 +6,42 @@ let lastSyncedTenant: string | null = null
|
|
|
6
6
|
|
|
7
7
|
const REDIRECT_KEY = 'aihub_redirect_after_login'
|
|
8
8
|
|
|
9
|
+
const normalize = (path: string) => (path.endsWith('/') ? path.slice(0, -1) : path)
|
|
10
|
+
|
|
11
|
+
const stripLocale = (path: string, localeCodes: string[]): string => {
|
|
12
|
+
const prefix = localeCodes.find(code => path === `/${code}` || path.startsWith(`/${code}/`))
|
|
13
|
+
return prefix ? path.slice(prefix.length + 1) : path
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The whole login subtree is anonymous, not just the login page itself:
|
|
18
|
+
* per-tenant login links live at `/auth/login/<idp-alias>`. No
|
|
19
|
+
* authenticated-only page may ever be nested below that path.
|
|
20
|
+
*
|
|
21
|
+
* The locale prefix is optional. This middleware runs before @nuxtjs/i18n's
|
|
22
|
+
* `locale-changing` middleware (Nuxt orders file-based global middleware ahead
|
|
23
|
+
* of plugin-registered ones), so bouncing a hand-distributed link that dropped
|
|
24
|
+
* `/en/` would strip the tenant before i18n ever restores the prefix.
|
|
25
|
+
*/
|
|
26
|
+
const isAnonymousPath = (path: string, localeCodes: string[]): boolean => {
|
|
27
|
+
const unprefixedPath = stripLocale(normalize(path), localeCodes)
|
|
28
|
+
|
|
29
|
+
return ['/auth/login', '/auth/callback', '/auth/renew'].includes(unprefixedPath)
|
|
30
|
+
|| unprefixedPath.startsWith('/auth/login/')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const rememberRedirect = (fullPath: string, isAuthPath: boolean) => {
|
|
34
|
+
if (import.meta.client && fullPath !== '/' && !isAuthPath) {
|
|
35
|
+
sessionStorage.setItem(REDIRECT_KEY, fullPath)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
export default defineNuxtRouteMiddleware(async (to) => {
|
|
10
40
|
const { $auth, $i18n } = useNuxtApp()
|
|
11
41
|
const locale = $i18n.locale.value
|
|
42
|
+
const localeCodes = $i18n.locales.value.map(entry => entry.code)
|
|
12
43
|
|
|
13
|
-
|
|
14
|
-
`/${locale}/auth/login`,
|
|
15
|
-
`/${locale}/auth/callback`,
|
|
16
|
-
`/${locale}/auth/renew`,
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
// No auth check for public paths (normalize trailing slashes on both sides)
|
|
20
|
-
const normalize = (p: string) => (p.endsWith('/') ? p.slice(0, -1) : p)
|
|
21
|
-
const normalizedPath = normalize(to.path)
|
|
22
|
-
if (noAuthPaths.some(p => normalize(p) === normalizedPath)) {
|
|
44
|
+
if (isAnonymousPath(to.path, localeCodes)) {
|
|
23
45
|
return
|
|
24
46
|
}
|
|
25
47
|
|
|
@@ -29,9 +51,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|
|
29
51
|
const isAuthPath = to.path.includes('/auth/')
|
|
30
52
|
|
|
31
53
|
if (!user) {
|
|
32
|
-
|
|
33
|
-
sessionStorage.setItem(REDIRECT_KEY, to.fullPath)
|
|
34
|
-
}
|
|
54
|
+
rememberRedirect(to.fullPath, isAuthPath)
|
|
35
55
|
return navigateTo(`/${locale}/auth/login`)
|
|
36
56
|
}
|
|
37
57
|
|
|
@@ -41,9 +61,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|
|
41
61
|
}
|
|
42
62
|
catch {
|
|
43
63
|
await $auth.removeUser()
|
|
44
|
-
|
|
45
|
-
sessionStorage.setItem(REDIRECT_KEY, to.fullPath)
|
|
46
|
-
}
|
|
64
|
+
rememberRedirect(to.fullPath, isAuthPath)
|
|
47
65
|
return navigateTo(`/${locale}/auth/login`)
|
|
48
66
|
}
|
|
49
67
|
}
|
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.320.0",
|
|
7
7
|
"description": "Swiss AI Hub - Admin & Management UI (Nuxt 3 layer)",
|
|
8
8
|
"main": "./nuxt.config.ts",
|
|
9
9
|
"repository": {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<AuthLoginPanel>
|
|
3
|
+
<template #heading>
|
|
4
|
+
<template v-if="provider">
|
|
5
|
+
{{ t('auth.login.welcomeProvider', { provider: provider.display_name }) }}
|
|
6
|
+
</template>
|
|
7
|
+
</template>
|
|
8
|
+
<template #message>
|
|
9
|
+
<template v-if="provider">
|
|
10
|
+
{{ t('auth.login.pleaseLoginWith', { provider: provider.display_name }) }}
|
|
11
|
+
</template>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<Button
|
|
15
|
+
v-if="provider"
|
|
16
|
+
:label="t('auth.login.loginWith', { provider: provider.display_name })"
|
|
17
|
+
:icon="`pi ${provider.icon}`"
|
|
18
|
+
icon-pos="right"
|
|
19
|
+
class="!bg-white !text-black"
|
|
20
|
+
@click="login(provider.alias)"
|
|
21
|
+
/>
|
|
22
|
+
<ProgressSpinner
|
|
23
|
+
v-else
|
|
24
|
+
class="!h-8 !w-8"
|
|
25
|
+
/>
|
|
26
|
+
</AuthLoginPanel>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
definePageMeta({
|
|
31
|
+
layout: 'anonymous',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const { t, locale } = useI18n()
|
|
35
|
+
const route = useRoute()
|
|
36
|
+
const { login } = useAuth()
|
|
37
|
+
const { authProviders, isLoading } = useAuthProviders()
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The empty alias belongs to the synthetic "Keycloak" entry, which has no
|
|
41
|
+
* kc_idp_hint and must therefore not be addressable through a tenant link.
|
|
42
|
+
*/
|
|
43
|
+
const requestedAlias = computed(() => String(route.params.idp ?? ''))
|
|
44
|
+
const provider = computed(() =>
|
|
45
|
+
requestedAlias.value
|
|
46
|
+
? authProviders.value?.find(candidate => candidate.alias === requestedAlias.value)
|
|
47
|
+
: undefined,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
// Only decide once the query settled — an unknown, disabled or hidden alias
|
|
51
|
+
// (and a failed provider request) falls back to the all-providers page.
|
|
52
|
+
watch([isLoading, provider], ([providersLoading, matchedProvider]) => {
|
|
53
|
+
if (!providersLoading && !matchedProvider) {
|
|
54
|
+
navigateTo(`/${locale.value}/auth/login`, { replace: true })
|
|
55
|
+
}
|
|
56
|
+
}, { immediate: true })
|
|
57
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<AuthLoginPanel>
|
|
3
|
+
<template #heading>
|
|
4
|
+
{{ t('auth.login.welcome', { companyName }) }}
|
|
5
|
+
</template>
|
|
6
|
+
<template #message>
|
|
7
|
+
{{ t('auth.login.pleaseLogin') }}
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<ProgressSpinner
|
|
11
|
+
v-if="isLoading"
|
|
12
|
+
class="!h-8 !w-8"
|
|
13
|
+
/>
|
|
14
|
+
<template v-else>
|
|
15
|
+
<Button
|
|
16
|
+
v-for="idp in authProviders ?? []"
|
|
17
|
+
:key="idp.alias"
|
|
18
|
+
:label="t('auth.login.loginWith', { provider: idp.display_name })"
|
|
19
|
+
:icon="`pi ${idp.icon}`"
|
|
20
|
+
icon-pos="right"
|
|
21
|
+
class="!bg-white !text-black"
|
|
22
|
+
@click="login(idp.alias || undefined)"
|
|
23
|
+
/>
|
|
24
|
+
<Button
|
|
25
|
+
v-if="(authProviders?.length ?? 0) === 0"
|
|
26
|
+
:label="t('auth.login.title')"
|
|
27
|
+
icon="pi pi-sign-in"
|
|
28
|
+
icon-pos="right"
|
|
29
|
+
class="!bg-white !text-black"
|
|
30
|
+
@click="login()"
|
|
31
|
+
/>
|
|
32
|
+
</template>
|
|
33
|
+
</AuthLoginPanel>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
definePageMeta({
|
|
38
|
+
layout: 'anonymous',
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const { t } = useI18n()
|
|
42
|
+
const { login } = useAuth()
|
|
43
|
+
const { authProviders, isLoading } = useAuthProviders()
|
|
44
|
+
|
|
45
|
+
const companyName = 'bbv Software Services AG'
|
|
46
|
+
</script>
|
|
@@ -197,9 +197,7 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
197
197
|
method,
|
|
198
198
|
onRequest: undefined,
|
|
199
199
|
serializedBody: getValidRequestBody(opts) as
|
|
200
|
-
|
|
|
201
|
-
| null
|
|
202
|
-
| undefined,
|
|
200
|
+
BodyInit | null | undefined,
|
|
203
201
|
signal: unwrapRefs(opts.signal) as AbortSignal,
|
|
204
202
|
url,
|
|
205
203
|
});
|
|
@@ -33,14 +33,12 @@ export type QuerySerializer = (
|
|
|
33
33
|
|
|
34
34
|
type WithRefs<TData> = {
|
|
35
35
|
[K in keyof TData]: NonNullable<TData[K]> extends object
|
|
36
|
-
?
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| Ref<NonNullable<TData[K]>>
|
|
43
|
-
| Extract<TData[K], null>;
|
|
36
|
+
? | WithRefs<NonNullable<TData[K]>>
|
|
37
|
+
| Ref<NonNullable<TData[K]>>
|
|
38
|
+
| Extract<TData[K], null>
|
|
39
|
+
: | NonNullable<TData[K]>
|
|
40
|
+
| Ref<NonNullable<TData[K]>>
|
|
41
|
+
| Extract<TData[K], null>;
|
|
44
42
|
};
|
|
45
43
|
|
|
46
44
|
// copied from Nuxt
|
|
@@ -206,8 +204,4 @@ type FetchOptions<TData> = Omit<
|
|
|
206
204
|
>;
|
|
207
205
|
|
|
208
206
|
export type Composable =
|
|
209
|
-
|
|
210
|
-
| "useAsyncData"
|
|
211
|
-
| "useFetch"
|
|
212
|
-
| "useLazyAsyncData"
|
|
213
|
-
| "useLazyFetch";
|
|
207
|
+
"$fetch" | "useAsyncData" | "useFetch" | "useLazyAsyncData" | "useLazyFetch";
|
|
@@ -195,8 +195,7 @@ export const setAuthParams = async ({
|
|
|
195
195
|
options.query = {};
|
|
196
196
|
}
|
|
197
197
|
const queryValue = toValue(options.query) as
|
|
198
|
-
|
|
199
|
-
| undefined;
|
|
198
|
+
Record<string, unknown> | undefined;
|
|
200
199
|
if (queryValue) {
|
|
201
200
|
queryValue[name] = token;
|
|
202
201
|
}
|
|
@@ -4,12 +4,7 @@
|
|
|
4
4
|
* JSON-friendly union that mirrors what Pinia Colada can hash.
|
|
5
5
|
*/
|
|
6
6
|
export type JsonValue =
|
|
7
|
-
|
|
|
8
|
-
| string
|
|
9
|
-
| number
|
|
10
|
-
| boolean
|
|
11
|
-
| JsonValue[]
|
|
12
|
-
| { [key: string]: JsonValue };
|
|
7
|
+
null | string | number | boolean | JsonValue[] | { [key: string]: JsonValue };
|
|
13
8
|
|
|
14
9
|
/**
|
|
15
10
|
* Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes.
|
|
@@ -112,7 +112,9 @@ type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
|
|
|
112
112
|
: false;
|
|
113
113
|
|
|
114
114
|
export type OmitNever<T extends Record<string, unknown>> = {
|
|
115
|
-
[
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
[
|
|
116
|
+
K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true
|
|
117
|
+
? never
|
|
118
|
+
: K
|
|
119
|
+
]: T[K];
|
|
118
120
|
};
|
package/sdk/client/index.ts
CHANGED
|
@@ -50,6 +50,8 @@ export {
|
|
|
50
50
|
getLitellmModel,
|
|
51
51
|
getLitellmModels,
|
|
52
52
|
getLitellmModelsByMode,
|
|
53
|
+
getLlmSpendByTenant,
|
|
54
|
+
getLlmSpendByUser,
|
|
53
55
|
getLocale,
|
|
54
56
|
getModels,
|
|
55
57
|
getModelWithAssistants,
|
|
@@ -315,6 +317,8 @@ export {
|
|
|
315
317
|
type CreateTranscriptionResponses,
|
|
316
318
|
type CronInput,
|
|
317
319
|
type CronInputWritable,
|
|
320
|
+
type CronStartEvent,
|
|
321
|
+
type CronStartEventWritable,
|
|
318
322
|
type CustomOutput,
|
|
319
323
|
type DashboardDto,
|
|
320
324
|
type DashboardItemDto,
|
|
@@ -526,6 +530,16 @@ export {
|
|
|
526
530
|
type GetLitellmModelsData,
|
|
527
531
|
type GetLitellmModelsResponse,
|
|
528
532
|
type GetLitellmModelsResponses,
|
|
533
|
+
type GetLlmSpendByTenantData,
|
|
534
|
+
type GetLlmSpendByTenantError,
|
|
535
|
+
type GetLlmSpendByTenantErrors,
|
|
536
|
+
type GetLlmSpendByTenantResponse,
|
|
537
|
+
type GetLlmSpendByTenantResponses,
|
|
538
|
+
type GetLlmSpendByUserData,
|
|
539
|
+
type GetLlmSpendByUserError,
|
|
540
|
+
type GetLlmSpendByUserErrors,
|
|
541
|
+
type GetLlmSpendByUserResponse,
|
|
542
|
+
type GetLlmSpendByUserResponses,
|
|
529
543
|
type GetLocaleData,
|
|
530
544
|
type GetLocaleResponse,
|
|
531
545
|
type GetLocaleResponses,
|
|
@@ -733,6 +747,7 @@ export {
|
|
|
733
747
|
type LlmCostEventWritable,
|
|
734
748
|
type LlmEvent,
|
|
735
749
|
type LlmEventWritable,
|
|
750
|
+
type LlmSpend,
|
|
736
751
|
type LlmStopEvent,
|
|
737
752
|
type LlmStopEventWritable,
|
|
738
753
|
type LocaleInput,
|
|
@@ -741,8 +756,11 @@ export {
|
|
|
741
756
|
type LocaleString,
|
|
742
757
|
type Logprob,
|
|
743
758
|
type MailAttachmentRef,
|
|
759
|
+
type MailBatchClassifiedEvent,
|
|
760
|
+
type MailBatchClassifiedEventWritable,
|
|
744
761
|
type MailBatchDraftedEvent,
|
|
745
762
|
type MailBatchDraftedEventWritable,
|
|
763
|
+
type MailClassificationRef,
|
|
746
764
|
type MailFetchedEvent,
|
|
747
765
|
type MailFetchedEventWritable,
|
|
748
766
|
type MailMessageRef,
|
|
@@ -886,8 +904,6 @@ export {
|
|
|
886
904
|
type RouterEventWritable,
|
|
887
905
|
type RunStatistics,
|
|
888
906
|
type RunStatisticsWritable,
|
|
889
|
-
type ScheduledStartEvent,
|
|
890
|
-
type ScheduledStartEventWritable,
|
|
891
907
|
type SearchContextCostPerQueryDto,
|
|
892
908
|
type SearchOrganizationMemoriesData,
|
|
893
909
|
type SearchOrganizationMemoriesError,
|