@cat-factory/app 0.116.0 → 0.116.2

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.
@@ -92,6 +92,18 @@ onMounted(() => void personal.load())
92
92
  const selectedMeta = computed(() => vendorMeta(vendor.value) ?? PERSONAL_VENDORS.value[0]!)
93
93
  const existing = computed(() => personal.subscriptions.find((s) => s.vendor === vendor.value))
94
94
 
95
+ /**
96
+ * Why the Connect button is disabled, or null when it's actionable. This is the single source
97
+ * of truth: the button's `:disabled` is bound to `disabledReason !== null`, and the same value
98
+ * renders in red next to it, so the button state and the shown reason can never disagree.
99
+ */
100
+ const disabledReason = computed(() => {
101
+ if (needsSignIn.value) return t('personalSubscriptions.disabledReason.signIn')
102
+ if (!token.value.trim()) return t('personalSubscriptions.disabledReason.token')
103
+ if (password.value.length < 6) return t('personalSubscriptions.disabledReason.password')
104
+ return null
105
+ })
106
+
95
107
  /** Renewal nudges for any connected subscription that's near or past expiry. */
96
108
  const renewals = computed(() =>
97
109
  personal.subscriptions
@@ -253,10 +265,11 @@ async function disconnect(v: SubscriptionVendor) {
253
265
  <UInput v-model="expiresOn" type="date" :disabled="needsSignIn" />
254
266
  </UFormField>
255
267
  </div>
256
- <div class="flex justify-end">
268
+ <div class="flex items-center justify-end gap-3">
269
+ <p v-if="disabledReason" class="text-sm text-rose-400">{{ disabledReason }}</p>
257
270
  <UButton
258
271
  :loading="busy"
259
- :disabled="needsSignIn || !token.trim() || password.length < 6"
272
+ :disabled="disabledReason !== null"
260
273
  icon="i-lucide-shield-check"
261
274
  @click="connect()"
262
275
  >
@@ -2564,6 +2564,11 @@
2564
2564
  "renewsField": "Abonnement verlängert sich am (optional)",
2565
2565
  "connect": "Verbinden",
2566
2566
  "replace": "Ersetzen",
2567
+ "disabledReason": {
2568
+ "signIn": "Melden Sie sich an, um ein persönliches Abonnement zu verbinden",
2569
+ "token": "Geben Sie Ihr Token ein, um fortzufahren",
2570
+ "password": "Geben Sie ein persönliches Passwort mit mindestens 6 Zeichen ein"
2571
+ },
2567
2572
  "expires": "Läuft ab am {date}",
2568
2573
  "noExpiry": "Kein Ablaufdatum gesetzt",
2569
2574
  "renewal": {
@@ -533,6 +533,11 @@
533
533
  "renewsField": "Subscription renews on (optional)",
534
534
  "connect": "Connect",
535
535
  "replace": "Replace",
536
+ "disabledReason": {
537
+ "signIn": "Sign in to connect a personal subscription",
538
+ "token": "Enter your token to continue",
539
+ "password": "Enter a personal password of at least 6 characters"
540
+ },
536
541
  "expires": "Expires {date}",
537
542
  "noExpiry": "No expiry set",
538
543
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "La suscripción se renueva el (opcional)",
483
483
  "connect": "Conectar",
484
484
  "replace": "Reemplazar",
485
+ "disabledReason": {
486
+ "signIn": "Inicia sesión para conectar una suscripción personal",
487
+ "token": "Introduce tu token para continuar",
488
+ "password": "Introduce una contraseña personal de al menos 6 caracteres"
489
+ },
485
490
  "expires": "Caduca el {date}",
486
491
  "noExpiry": "Sin fecha de caducidad",
487
492
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "L'abonnement se renouvelle le (facultatif)",
483
483
  "connect": "Connecter",
484
484
  "replace": "Remplacer",
485
+ "disabledReason": {
486
+ "signIn": "Connectez-vous pour associer un abonnement personnel",
487
+ "token": "Saisissez votre jeton pour continuer",
488
+ "password": "Saisissez un mot de passe personnel d'au moins 6 caractères"
489
+ },
485
490
  "expires": "Expire le {date}",
486
491
  "noExpiry": "Aucune date d'expiration",
487
492
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "המנוי מתחדש בתאריך (אופציונלי)",
483
483
  "connect": "חבר",
484
484
  "replace": "החלף",
485
+ "disabledReason": {
486
+ "signIn": "היכנס כדי לחבר מנוי אישי",
487
+ "token": "הזן את הטוקן שלך כדי להמשיך",
488
+ "password": "הזן סיסמה אישית באורך 6 תווים לפחות"
489
+ },
485
490
  "expires": "פג בתאריך {date}",
486
491
  "noExpiry": "לא הוגדרה תפוגה",
487
492
  "renewal": {
@@ -2564,6 +2564,11 @@
2564
2564
  "renewsField": "L'abbonamento si rinnova il (opzionale)",
2565
2565
  "connect": "Collega",
2566
2566
  "replace": "Sostituisci",
2567
+ "disabledReason": {
2568
+ "signIn": "Accedi per collegare un abbonamento personale",
2569
+ "token": "Inserisci il tuo token per continuare",
2570
+ "password": "Inserisci una password personale di almeno 6 caratteri"
2571
+ },
2567
2572
  "expires": "Scade il {date}",
2568
2573
  "noExpiry": "Nessuna scadenza impostata",
2569
2574
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "サブスクリプションの更新日 (任意)",
483
483
  "connect": "接続",
484
484
  "replace": "置き換え",
485
+ "disabledReason": {
486
+ "signIn": "個人サブスクリプションを接続するにはサインインしてください",
487
+ "token": "続行するにはトークンを入力してください",
488
+ "password": "6文字以上の個人パスワードを入力してください"
489
+ },
485
490
  "expires": "有効期限 {date}",
486
491
  "noExpiry": "有効期限は未設定",
487
492
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "Subskrypcja odnawia się (opcjonalnie)",
483
483
  "connect": "Połącz",
484
484
  "replace": "Zastąp",
485
+ "disabledReason": {
486
+ "signIn": "Zaloguj się, aby połączyć subskrypcję osobistą",
487
+ "token": "Wprowadź token, aby kontynuować",
488
+ "password": "Wprowadź hasło osobiste o długości co najmniej 6 znaków"
489
+ },
485
490
  "expires": "Wygasa {date}",
486
491
  "noExpiry": "Brak daty wygaśnięcia",
487
492
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "Abonelik yenilenme tarihi (isteğe bağlı)",
483
483
  "connect": "Bağlan",
484
484
  "replace": "Değiştir",
485
+ "disabledReason": {
486
+ "signIn": "Kişisel bir abonelik bağlamak için oturum açın",
487
+ "token": "Devam etmek için token'ınızı girin",
488
+ "password": "En az 6 karakterlik kişisel bir parola girin"
489
+ },
485
490
  "expires": "Son kullanma {date}",
486
491
  "noExpiry": "Son kullanma tarihi ayarlanmadı",
487
492
  "renewal": {
@@ -482,6 +482,11 @@
482
482
  "renewsField": "Підписка поновлюється (необов'язково)",
483
483
  "connect": "Підключити",
484
484
  "replace": "Замінити",
485
+ "disabledReason": {
486
+ "signIn": "Увійдіть, щоб підключити особисту підписку",
487
+ "token": "Введіть свій токен, щоб продовжити",
488
+ "password": "Введіть особистий пароль щонайменше з 6 символів"
489
+ },
485
490
  "expires": "Завершується {date}",
486
491
  "noExpiry": "Дата завершення не вказана",
487
492
  "renewal": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.116.0",
3
+ "version": "0.116.2",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "valibot": "^1.4.2",
35
35
  "vue": "3.5.39",
36
36
  "wretch": "^3.0.9",
37
- "@cat-factory/contracts": "0.128.0"
37
+ "@cat-factory/contracts": "0.128.1"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",