@swiss-ai-hub/web 0.318.0 → 0.319.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/README.md CHANGED
@@ -155,8 +155,8 @@ The same single-instance requirement applies to **PrimeVue** (its theme system i
155
155
  > { "dependencies": { "vue-router": "4.6.4" } }
156
156
  > ```
157
157
  >
158
- > Verify with `pnpm why vue-router` (`@vueuse/router` must show `4.6.4`) and `pnpm build` (`nuxt generate` must succeed
159
- > forcing a single `vue-router` major instead breaks `@nuxtjs/i18n`, which needs 5.x).
158
+ > Verify with `pnpm why vue-router` (`@vueuse/router` must show `4.6.4`) and `pnpm build` (`nuxt generate` must succeed
159
+ > forcing a single `vue-router` major instead breaks `@nuxtjs/i18n`, which needs 5.x).
160
160
 
161
161
  ## Quick start
162
162
 
@@ -7,6 +7,7 @@
7
7
  :options="localeOptions"
8
8
  option-label="label"
9
9
  option-value="value"
10
+ :allow-empty="false"
10
11
  size="small"
11
12
  >
12
13
  <template #option="{ option }">
@@ -100,15 +101,24 @@ const localeOptions = locales.map(lang => ({
100
101
 
101
102
  const activeLocale = ref<Locale>('en')
102
103
 
104
+ function isLocale(value: unknown): value is Locale {
105
+ return locales.includes(value as Locale)
106
+ }
107
+
103
108
  // Get the current locale string value
104
109
  const localeValue = computed<LocaleStringDto>(() => {
105
110
  return props.context.value ?? { de: null, en: null, fr: null, it: null }
106
111
  })
107
112
 
108
113
  // Current input value for the active locale
114
+ // The guard is belt-and-braces next to `:allow-empty="false"`: with an unset `activeLocale`
115
+ // this setter used to write under the key `"null"`, producing a value whose four locales
116
+ // were all empty but which no longer looked like a locale object to the backend's
117
+ // normalization — so it slipped past validation and saved a blank name (issue #135).
109
118
  const currentValue = computed({
110
- get: () => localeValue.value[activeLocale.value] ?? '',
119
+ get: () => (isLocale(activeLocale.value) ? localeValue.value[activeLocale.value] ?? '' : ''),
111
120
  set: (newVal: string) => {
121
+ if (!isLocale(activeLocale.value)) return
112
122
  const updated: LocaleStringDto = {
113
123
  ...localeValue.value,
114
124
  [activeLocale.value]: newVal || null,
package/formkit.config.ts CHANGED
@@ -10,9 +10,39 @@ import { en, de, fr, it } from '@formkit/i18n'
10
10
  import { createInput } from '@formkit/vue'
11
11
  import { primeInputs } from '@sfxcode/formkit-primevue'
12
12
 
13
+ import type { FormKitNode } from '@formkit/core'
13
14
  import type { DefaultConfigOptions } from '@formkit/vue'
14
15
 
16
+ const LOCALES = ['de', 'en', 'fr', 'it'] as const
17
+
18
+ // FormKit's built-in `required` rule only asks whether a value is present, and a localeInput's
19
+ // value is always a `{de, en, fr, it}` object — non-empty, so `required` passes even when every
20
+ // locale inside it is blank. Backend `LocaleInput` elements emit `localeRequired` instead
21
+ // (see packages/core/swiss_ai_hub/core/form/elements/locale_input.py).
22
+ function localeRequired(node: FormKitNode): boolean {
23
+ const value = node.value as Record<string, string | null> | null | undefined
24
+ if (!value) return false
25
+ return LOCALES.some(locale => !!value[locale]?.trim())
26
+ }
27
+
28
+ // FormKit skips a rule entirely when the node's value is empty, unless the rule opts out —
29
+ // which is why the built-in `required` sets this too. Without it the rule would never run on a
30
+ // never-touched field, whose value is still `null`, and a blank Name would pass on a fresh
31
+ // create form: precisely the case this rule exists to catch.
32
+ localeRequired.skipEmpty = false
33
+
34
+ const localeRequiredMessages = {
35
+ de: 'Mindestens eine Sprache muss ausgefüllt sein.',
36
+ en: 'At least one language must be filled in.',
37
+ fr: 'Au moins une langue doit être renseignée.',
38
+ it: 'Almeno una lingua deve essere compilata.',
39
+ }
40
+
15
41
  const config: DefaultConfigOptions = {
42
+ rules: { localeRequired },
43
+ messages: Object.fromEntries(
44
+ LOCALES.map(locale => [locale, { validation: { localeRequired: localeRequiredMessages[locale] } }]),
45
+ ),
16
46
  inputs: {
17
47
  ...primeInputs,
18
48
  agentSelector: createInput(AgentSelector, {
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.318.0",
6
+ "version": "0.319.0",
7
7
  "description": "Swiss AI Hub - Admin & Management UI (Nuxt 3 layer)",
8
8
  "main": "./nuxt.config.ts",
9
9
  "repository": {
@@ -117,6 +117,9 @@ const submitConfiguration = async (formData: Record<string, unknown>) => {
117
117
  }
118
118
  catch (error) {
119
119
  console.error('Failed to save agent configuration:', error)
120
+ // No `detail` here on purpose: the SDK's global onResponseError (app.vue) already toasts the
121
+ // backend's `detail`, and formats pydantic's array-shaped errors while doing it. Passing
122
+ // `error.message` would only add a second toast reading `[PUT] "<url>": 400 Bad Request`.
120
123
  toast.add({
121
124
  severity: 'error',
122
125
  summary: t('agent.configuration.saveError'),
@@ -96,6 +96,8 @@ const submitConfiguration = async (formData: Record<string, unknown>) => {
96
96
  }
97
97
  catch (error) {
98
98
  console.error('Failed to save process configuration:', error)
99
+ // See the agent configuration page: the SDK's global onResponseError already surfaces the
100
+ // backend `detail`, so adding `error.message` here would only duplicate the toast with a URL.
99
101
  toast.add({
100
102
  severity: 'error',
101
103
  summary: t('process.configuration.saveError'),
@@ -313,6 +313,8 @@ export {
313
313
  type CreateTranscriptionErrors,
314
314
  type CreateTranscriptionResponse,
315
315
  type CreateTranscriptionResponses,
316
+ type CronInput,
317
+ type CronInputWritable,
316
318
  type CustomOutput,
317
319
  type DashboardDto,
318
320
  type DashboardItemDto,
@@ -743,6 +745,7 @@ export {
743
745
  type MailBatchDraftedEventWritable,
744
746
  type MailFetchedEvent,
745
747
  type MailFetchedEventWritable,
748
+ type MailMessageRef,
746
749
  type MailMovedEvent,
747
750
  type MailMovedEventWritable,
748
751
  type MemoriesResponse,
@@ -883,6 +886,8 @@ export {
883
886
  type RouterEventWritable,
884
887
  type RunStatistics,
885
888
  type RunStatisticsWritable,
889
+ type ScheduledStartEvent,
890
+ type ScheduledStartEventWritable,
886
891
  type SearchContextCostPerQueryDto,
887
892
  type SearchOrganizationMemoriesData,
888
893
  type SearchOrganizationMemoriesError,