@trismegisto/spine 2.0.1 → 2.1.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.
Files changed (49) hide show
  1. package/README.md +35 -5
  2. package/fesm2022/trismegisto-spine-audit.mjs +1 -1
  3. package/fesm2022/trismegisto-spine-audit.mjs.map +1 -1
  4. package/fesm2022/trismegisto-spine-auto-service-apps.technical-ClMKB9cK.mjs +48 -0
  5. package/fesm2022/trismegisto-spine-auto-service-apps.technical-ClMKB9cK.mjs.map +1 -0
  6. package/fesm2022/trismegisto-spine-auto-service-apps.usage-Cf5SG-oQ.mjs +55 -0
  7. package/fesm2022/trismegisto-spine-auto-service-apps.usage-Cf5SG-oQ.mjs.map +1 -0
  8. package/fesm2022/trismegisto-spine-auto-service-audit.technical-C901aIIQ.mjs +42 -0
  9. package/fesm2022/trismegisto-spine-auto-service-audit.technical-C901aIIQ.mjs.map +1 -0
  10. package/fesm2022/trismegisto-spine-auto-service-audit.usage-GIJ2RwuH.mjs +63 -0
  11. package/fesm2022/trismegisto-spine-auto-service-audit.usage-GIJ2RwuH.mjs.map +1 -0
  12. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-C7SPavrX.mjs +784 -0
  13. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-C7SPavrX.mjs.map +1 -0
  14. package/fesm2022/trismegisto-spine-auto-service-auto-service-delete-6Bk46MOf.mjs +39 -0
  15. package/fesm2022/trismegisto-spine-auto-service-auto-service-delete-6Bk46MOf.mjs.map +1 -0
  16. package/fesm2022/{trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs → trismegisto-spine-auto-service-auto-service.component-BLN49F4a.mjs} +32 -7
  17. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-BLN49F4a.mjs.map +1 -0
  18. package/fesm2022/trismegisto-spine-auto-service-client.technical-BHWhpyWv.mjs +46 -0
  19. package/fesm2022/trismegisto-spine-auto-service-client.technical-BHWhpyWv.mjs.map +1 -0
  20. package/fesm2022/trismegisto-spine-auto-service-client.usage-CM2WB2e2.mjs +80 -0
  21. package/fesm2022/trismegisto-spine-auto-service-client.usage-CM2WB2e2.mjs.map +1 -0
  22. package/fesm2022/trismegisto-spine-auto-service-groups.technical-jQlwaQPn.mjs +39 -0
  23. package/fesm2022/trismegisto-spine-auto-service-groups.technical-jQlwaQPn.mjs.map +1 -0
  24. package/fesm2022/trismegisto-spine-auto-service-groups.usage-Bh7ig2zZ.mjs +54 -0
  25. package/fesm2022/trismegisto-spine-auto-service-groups.usage-Bh7ig2zZ.mjs.map +1 -0
  26. package/fesm2022/trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs +35 -0
  27. package/fesm2022/trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs.map +1 -0
  28. package/fesm2022/trismegisto-spine-auto-service-home.usage-D6cb4B3Z.mjs +43 -0
  29. package/fesm2022/trismegisto-spine-auto-service-home.usage-D6cb4B3Z.mjs.map +1 -0
  30. package/fesm2022/trismegisto-spine-auto-service.mjs +82 -40
  31. package/fesm2022/trismegisto-spine-auto-service.mjs.map +1 -1
  32. package/fesm2022/trismegisto-spine-layout.mjs +988 -46
  33. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -1
  34. package/fesm2022/trismegisto-spine-shell.mjs +3 -1
  35. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -1
  36. package/fesm2022/trismegisto-spine.mjs +591 -16
  37. package/fesm2022/trismegisto-spine.mjs.map +1 -1
  38. package/package.json +7 -7
  39. package/types/trismegisto-spine-auto-service.d.ts +41 -2
  40. package/types/trismegisto-spine-auto-service.d.ts.map +1 -1
  41. package/types/trismegisto-spine-layout.d.ts +214 -13
  42. package/types/trismegisto-spine-layout.d.ts.map +1 -1
  43. package/types/trismegisto-spine-shell.d.ts +1 -0
  44. package/types/trismegisto-spine-shell.d.ts.map +1 -1
  45. package/types/trismegisto-spine.d.ts +214 -8
  46. package/types/trismegisto-spine.d.ts.map +1 -1
  47. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs +0 -595
  48. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs.map +0 -1
  49. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs.map +0 -1
@@ -4,6 +4,7 @@ import * as i0 from '@angular/core';
4
4
  import { InjectionToken, inject, effect, PLATFORM_ID, Inject, Optional, Injectable, makeEnvironmentProviders, provideAppInitializer, NgZone, signal, computed, untracked, DestroyRef } from '@angular/core';
5
5
  import { HERMES_ICONS } from '@trismegisto/icons/catalog';
6
6
  import { extendThemeConfig, DEFAULT_THEME_CONFIG, mergeCatalog } from '@trismegisto/primitives';
7
+ import { AuthorizationService } from '@orfeu/angular/core';
7
8
 
8
9
  /** `router_id` da tela (nó 'page'), aceitando o argos antigo (que só mandava `route_id`, mesmo valor). */
9
10
  function routerIdOf(route) {
@@ -520,27 +521,141 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
520
521
  */
521
522
  const SPINE_ADMIN_API = new InjectionToken('SPINE_ADMIN_API');
522
523
 
524
+ /** Listas do shell guardadas no navegador, por usuário. */
525
+ const SPINE_USER_STORAGE_KEYS = {
526
+ favorites: 'nav_favorites',
527
+ recents: 'nav_recent',
528
+ recentSearches: 'header_recent_searches',
529
+ };
530
+ /** Históricos (o que a pessoa visitou/buscou): apagados no logout. Favoritos ficam (preferência do usuário). */
531
+ const HISTORY_KEYS = [SPINE_USER_STORAGE_KEYS.recents, SPINE_USER_STORAGE_KEYS.recentSearches];
532
+ /**
533
+ * Chaves de `localStorage` do shell por usuário: `<clientId>_<lista>_<sub>`, com o `sub` do token da sessão.
534
+ * Num computador compartilhado, uma pessoa não vê os recentes/buscas/favoritos de quem entrou antes.
535
+ *
536
+ * - Sem `sub` (sem sessão, ou app sem `@orfeu/angular`) a chave é a antiga, `<clientId>_<lista>`.
537
+ * - Com `sub`, a chave antiga sem usuário é apagada (era compartilhada entre todas as contas do navegador).
538
+ * - No logout (`clearHistory()`, chamado pelo spine antes do `logout()`, e o `isAuth$` indo para `false`, que
539
+ * cobre o logout vindo de outra aba) os HISTÓRICOS do usuário saem; os favoritos ficam.
540
+ */
541
+ class SpineUserStorage {
542
+ constructor() {
543
+ this.browser = isPlatformBrowser(inject(PLATFORM_ID));
544
+ this.auth = inject(AuthorizationService, { optional: true });
545
+ this.ns = inject(SPINE_CONFIG, { optional: true })?.clientId || 'app';
546
+ this.listeners = new Set();
547
+ /** Último usuário visto: o token some no logout, mas a limpeza precisa saber de quem era. */
548
+ this.lastUser = '';
549
+ const isAuth$ = this.auth?.isAuth$;
550
+ if (!this.browser || !isAuth$?.subscribe)
551
+ return;
552
+ let was = false;
553
+ const sub = isAuth$.subscribe((authenticated) => {
554
+ if (was && !authenticated)
555
+ this.clearHistory();
556
+ was = authenticated;
557
+ this.notify();
558
+ });
559
+ inject(DestroyRef).onDestroy(() => sub.unsubscribe());
560
+ }
561
+ /** `sub` do token da sessão (só leitura do payload); vazio sem sessão. */
562
+ userId() {
563
+ let token;
564
+ try {
565
+ token = this.auth?.getToken();
566
+ }
567
+ catch {
568
+ token = null;
569
+ }
570
+ const sub = token ? decodeSub(token) : '';
571
+ if (sub)
572
+ this.lastUser = sub;
573
+ return sub;
574
+ }
575
+ /** Chave de `localStorage` da lista para o usuário atual. */
576
+ key(list) {
577
+ const user = this.userId();
578
+ const legacy = `${this.ns}_${list}`;
579
+ if (!user)
580
+ return legacy;
581
+ this.dropLegacy(legacy);
582
+ return `${legacy}_${user}`;
583
+ }
584
+ /** Apaga buscas recentes e páginas recentes do usuário (o atual ou o último visto). Favoritos ficam. */
585
+ clearHistory() {
586
+ if (!this.browser)
587
+ return;
588
+ const user = this.userId() || this.lastUser;
589
+ for (const list of HISTORY_KEYS) {
590
+ try {
591
+ localStorage.removeItem(user ? `${this.ns}_${list}_${user}` : `${this.ns}_${list}`);
592
+ }
593
+ catch {
594
+ /* storage indisponível */
595
+ }
596
+ }
597
+ this.notify();
598
+ }
599
+ /** Avisa quando a sessão muda ou o histórico é limpo (quem guarda a lista em memória relê). */
600
+ onChange(listener) {
601
+ this.listeners.add(listener);
602
+ return () => this.listeners.delete(listener);
603
+ }
604
+ notify() {
605
+ for (const listener of [...this.listeners])
606
+ listener();
607
+ }
608
+ dropLegacy(key) {
609
+ if (!this.browser)
610
+ return;
611
+ try {
612
+ if (localStorage.getItem(key) !== null)
613
+ localStorage.removeItem(key);
614
+ }
615
+ catch {
616
+ /* storage indisponível */
617
+ }
618
+ }
619
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineUserStorage, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
620
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineUserStorage, providedIn: 'root' }); }
621
+ }
622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineUserStorage, decorators: [{
623
+ type: Injectable,
624
+ args: [{ providedIn: 'root' }]
625
+ }], ctorParameters: () => [] });
626
+ function decodeSub(token) {
627
+ const payload = token.split('.')[1];
628
+ if (!payload)
629
+ return '';
630
+ try {
631
+ const json = atob(payload.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(payload.length / 4) * 4, '='));
632
+ const sub = JSON.parse(json)['sub'];
633
+ return typeof sub === 'string' ? sub : '';
634
+ }
635
+ catch {
636
+ return '';
637
+ }
638
+ }
639
+
523
640
  // The sidebar navigation writes the same history list and trims it to this size; both writers must agree.
524
641
  const RECENT_LIMIT = 10;
525
642
  /**
526
643
  * Favorites and recently visited pages, shared by every consumer in the app (page bar, home screen)
527
- * and persisted per client in `localStorage`.
644
+ * and persisted per client and per user in `localStorage` (`SpineUserStorage`: `<clientId>_nav_favorites_<sub>`).
645
+ * Recents are cleared on logout; switching users reloads both lists.
528
646
  */
529
647
  class SpineQuickAccessService {
530
- constructor(config) {
648
+ constructor() {
531
649
  this.browser = isPlatformBrowser(inject(PLATFORM_ID));
650
+ this.storage = inject(SpineUserStorage);
532
651
  this.favoriteList = signal([], ...(ngDevMode ? [{ debugName: "favoriteList" }] : /* istanbul ignore next */ []));
533
652
  this.recentList = signal([], ...(ngDevMode ? [{ debugName: "recentList" }] : /* istanbul ignore next */ []));
534
653
  this.favorites = this.favoriteList.asReadonly();
535
654
  this.recents = this.recentList.asReadonly();
536
655
  this.favoriteSet = computed(() => new Set(this.favoriteList().map((item) => item.id)), ...(ngDevMode ? [{ debugName: "favoriteSet" }] : /* istanbul ignore next */ []));
537
- const prefix = config?.clientId || 'app';
538
- this.favoritesKey = `${prefix}_nav_favorites`;
539
- this.recentsKey = `${prefix}_nav_recent`;
540
656
  if (!this.browser)
541
657
  return;
542
- this.favoriteList.set(this.load(this.favoritesKey));
543
- this.recentList.set(this.load(this.recentsKey));
658
+ this.reload();
544
659
  const onStorage = (event) => {
545
660
  if (event.key === this.favoritesKey)
546
661
  this.favoriteList.set(this.load(this.favoritesKey));
@@ -548,7 +663,22 @@ class SpineQuickAccessService {
548
663
  this.recentList.set(this.load(this.recentsKey));
549
664
  };
550
665
  window.addEventListener('storage', onStorage);
551
- inject(DestroyRef).onDestroy(() => window.removeEventListener('storage', onStorage));
666
+ // Sessão mudou (logout, outra conta) ou histórico limpo: relê as listas do usuário atual.
667
+ const stop = this.storage.onChange(() => this.reload());
668
+ inject(DestroyRef).onDestroy(() => {
669
+ window.removeEventListener('storage', onStorage);
670
+ stop();
671
+ });
672
+ }
673
+ get favoritesKey() {
674
+ return this.storage.key(SPINE_USER_STORAGE_KEYS.favorites);
675
+ }
676
+ get recentsKey() {
677
+ return this.storage.key(SPINE_USER_STORAGE_KEYS.recents);
678
+ }
679
+ reload() {
680
+ this.favoriteList.set(this.load(this.favoritesKey));
681
+ this.recentList.set(this.load(this.recentsKey));
552
682
  }
553
683
  isFavorite(id) {
554
684
  return !!id && this.favoriteSet().has(id);
@@ -598,18 +728,13 @@ class SpineQuickAccessService {
598
728
  return item ? [item] : [];
599
729
  });
600
730
  }
601
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineQuickAccessService, deps: [{ token: SPINE_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
731
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineQuickAccessService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
602
732
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineQuickAccessService, providedIn: 'root' }); }
603
733
  }
604
734
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineQuickAccessService, decorators: [{
605
735
  type: Injectable,
606
736
  args: [{ providedIn: 'root' }]
607
- }], ctorParameters: () => [{ type: undefined, decorators: [{
608
- type: Optional
609
- }, {
610
- type: Inject,
611
- args: [SPINE_CONFIG]
612
- }] }] });
737
+ }], ctorParameters: () => [] });
613
738
  function normalize(entry) {
614
739
  if (!entry || typeof entry !== 'object')
615
740
  return null;
@@ -869,6 +994,20 @@ const SPINE_MESSAGES_PT_BR = {
869
994
  logout: 'Sair',
870
995
  logoutDescription: 'Encerra a sessão neste navegador.',
871
996
  logoutKeywords: 'logout desconectar',
997
+ security: 'Conta e segurança',
998
+ securityDescription: 'Verificação em duas etapas, códigos de recuperação e sessões da sua conta no Argos, o login das aplicações.',
999
+ securityKeywords: 'segurança argos senha autenticação mfa 2fa dispositivos',
1000
+ signedInAccount: 'Conta no Argos',
1001
+ signedInRealm: 'Realm {realm}',
1002
+ twoFactor: 'Verificação em duas etapas',
1003
+ twoFactorDescription: 'Adicione ou remova métodos (aplicativo autenticador ou e-mail) e troque o aparelho do autenticador.',
1004
+ twoFactorKeywords: 'mfa 2fa totp autenticador authenticator código e-mail método aparelho celular',
1005
+ recoveryCodes: 'Códigos de recuperação',
1006
+ recoveryCodesDescription: 'Servem para entrar se você perder o aparelho. Gerar novos códigos invalida os anteriores.',
1007
+ recoveryCodesKeywords: 'backup recuperação perdi celular aparelho mfa 2fa',
1008
+ sessions: 'Sessões e dispositivos',
1009
+ sessionsDescription: 'Veja onde a sua conta está conectada (navegador, sistema, IP, último uso) e encerre uma sessão ou todas as outras.',
1010
+ sessionsKeywords: 'dispositivos navegador ip encerrar desconectar sair aparelhos conectados',
872
1011
  about: 'Sobre',
873
1012
  aboutKeywords: 'versão build ambiente dependências suporte',
874
1013
  application: 'Aplicação',
@@ -946,6 +1085,115 @@ const SPINE_MESSAGES_PT_BR = {
946
1085
  revoked: 'Token "{name}" revogado. Pode levar até 2 minutos para parar de funcionar em todos os sistemas.',
947
1086
  revokeError: 'Não foi possível revogar o token.',
948
1087
  },
1088
+ accountSecurity: {
1089
+ loading: 'Carregando…',
1090
+ loadError: 'Não foi possível carregar a sua conta no Argos.',
1091
+ sessionEnded: 'A sessão deste login terminou no Argos. Entre de novo para gerenciar a conta.',
1092
+ retry: 'Tentar novamente',
1093
+ methodTotp: 'Aplicativo autenticador',
1094
+ methodEmail: 'E-mail',
1095
+ methodSms: 'SMS',
1096
+ active: 'Ativo',
1097
+ activeWithDetail: 'Ativo · {detail}',
1098
+ notRegistered: 'Não cadastrado',
1099
+ unavailable: 'Indisponível',
1100
+ requiredHint: 'Obrigatória neste ambiente: mantenha pelo menos um método.',
1101
+ add: 'Adicionar',
1102
+ replaceDevice: 'Trocar aparelho',
1103
+ remove: 'Remover',
1104
+ cancel: 'Cancelar',
1105
+ confirm: 'Confirmar',
1106
+ removeTitle: 'Remover {method}?',
1107
+ removeHint: 'Você deixa de poder usar este método para entrar.',
1108
+ removeLastHint: 'Sem nenhum método, os códigos de recuperação também deixam de valer.',
1109
+ reauthTitle: 'Confirme sua identidade',
1110
+ reauthHint: 'Para mudar a verificação em duas etapas ou gerar códigos, prove de novo quem é você. Vale por 5 minutos.',
1111
+ reauthHow: 'Como confirmar',
1112
+ reauthPassword: 'Senha',
1113
+ reauthRecoveryCode: 'Código de recuperação',
1114
+ currentPassword: 'Senha atual',
1115
+ passwordRequired: 'Informe a senha.',
1116
+ recoveryCode: 'Código de recuperação',
1117
+ recoveryCodePlaceholder: 'XXXXX-XXXXX',
1118
+ recoveryCodeRequired: 'Informe o código.',
1119
+ recoveryCodeLength: 'O código tem 10 letras e números.',
1120
+ sendEmailCode: 'Enviar código para o e-mail cadastrado',
1121
+ sixDigitCode: 'Código de 6 dígitos',
1122
+ totpTitle: 'Escaneie o QR Code no aplicativo autenticador',
1123
+ qrAlt: 'QR Code para configurar o aplicativo autenticador',
1124
+ manualKey: 'Sem câmera? Digite a chave:',
1125
+ appCode: 'Código do aplicativo',
1126
+ emailTitle: 'Cadastrar e-mail',
1127
+ email: 'E-mail',
1128
+ emailPlaceholder: 'nome@empresa.com',
1129
+ emailRequired: 'Informe o e-mail.',
1130
+ emailInvalid: 'Informe um e-mail válido.',
1131
+ sendCode: 'Enviar código',
1132
+ emailCodeTitle: 'Confirme o e-mail',
1133
+ emailCodeHint: 'Digite o código de 6 dígitos enviado para {email}.',
1134
+ codesRemaining: { zero: 'Nenhum código disponível.', one: '1 código disponível.', other: '{count} códigos disponíveis.' },
1135
+ codesHint: 'Cada um vale uma vez para entrar se você perder o seu método de verificação.',
1136
+ codesNeedMethod: 'Cadastre um método de verificação para gerar códigos de recuperação.',
1137
+ generateCodes: 'Gerar códigos',
1138
+ regenerateCodes: 'Gerar novos códigos',
1139
+ codesTitle: 'Seus códigos de recuperação',
1140
+ codesShownOnce: 'Guarde estes códigos num lugar seguro. Cada um vale uma única vez para entrar se você perder o acesso ao seu método de verificação. Eles não serão mostrados de novo.',
1141
+ copyCodes: 'Copiar',
1142
+ downloadCodes: 'Baixar .txt',
1143
+ codesCopied: 'Códigos copiados.',
1144
+ copyFailed: 'Não foi possível copiar. Selecione os códigos e copie manualmente.',
1145
+ codesSaved: 'Guardei os códigos',
1146
+ codesFileHeader: 'Códigos de recuperação do Argos (cada um vale uma vez)',
1147
+ codesFileName: 'codigos-de-recuperacao.txt',
1148
+ notices: {
1149
+ methodAdded: 'Método cadastrado.',
1150
+ deviceReplaced: 'Aparelho trocado. O anterior não gera mais códigos válidos.',
1151
+ methodRemoved: 'Método removido.',
1152
+ codesRegenerated: 'Códigos de recuperação gerados. Os anteriores não valem mais.',
1153
+ reauthCodeSent: 'Enviamos um código para o e-mail cadastrado.',
1154
+ },
1155
+ errors: {
1156
+ generic: 'Não foi possível concluir. Tente novamente.',
1157
+ network: 'Não foi possível falar com o Argos. Verifique a conexão e tente novamente.',
1158
+ login_required: 'A sessão deste login terminou no Argos. Entre de novo para gerenciar a conta.',
1159
+ invalid_token: 'A sessão deste login terminou no Argos. Entre de novo para gerenciar a conta.',
1160
+ reauthentication_required: 'A confirmação de identidade venceu. Confirme de novo para continuar.',
1161
+ invalid_password: 'Senha incorreta.',
1162
+ account_locked: 'Muitas tentativas com a senha. A conta ficou bloqueada por alguns minutos.',
1163
+ invalid_code: 'Código incorreto.',
1164
+ invalid_recovery_code: 'Código de recuperação inválido ou já usado.',
1165
+ code_expired: 'O código venceu. Peça outro.',
1166
+ code_not_requested: 'Peça o código antes de digitá-lo.',
1167
+ too_many_attempts: 'Muitas tentativas. Espere alguns minutos e tente de novo.',
1168
+ too_many_requests: 'Espere um pouco antes de pedir outro código.',
1169
+ mfa_method_not_allowed: 'Este método não é aceito neste ambiente.',
1170
+ mfa_method_not_found: 'Este método já não estava cadastrado.',
1171
+ mfa_last_method: 'A verificação em duas etapas é obrigatória: mantenha pelo menos um método.',
1172
+ invalid_email: 'Informe um e-mail válido.',
1173
+ enrollment_not_started: 'O cadastro venceu. Comece de novo.',
1174
+ sms_not_available: 'SMS indisponível.',
1175
+ mfa_required_for_recovery_codes: 'Cadastre um método de verificação antes de gerar códigos.',
1176
+ session_not_found: 'A sessão já tinha sido encerrada.',
1177
+ },
1178
+ sessionsEmpty: 'Nenhuma sessão ativa.',
1179
+ thisSession: 'Esta sessão',
1180
+ thisBrowser: 'Este navegador',
1181
+ appsOnly: 'Só aplicativos',
1182
+ sessionDetail: 'IP {ip} · último uso {date}',
1183
+ unknownIp: 'desconhecido',
1184
+ sessionSince: 'Desde {date}',
1185
+ sessionApps: 'Aplicativos: {apps}',
1186
+ unnamedApp: 'Aplicativo',
1187
+ endSession: 'Encerrar',
1188
+ confirmEndSession: 'Confirmar encerramento',
1189
+ endOthers: 'Encerrar todas as outras',
1190
+ endOthersConfirm: {
1191
+ one: 'Encerrar a outra sessão? Os aplicativos abertos nela vão pedir login de novo.',
1192
+ other: 'Encerrar as {count} outras sessões? Os aplicativos abertos nelas vão pedir login de novo.',
1193
+ },
1194
+ sessionEndedNotice: 'Sessão encerrada.',
1195
+ othersEndedNotice: { zero: 'Nenhuma sessão encerrada.', one: '1 sessão encerrada.', other: '{count} sessões encerradas.' },
1196
+ },
949
1197
  notification: {
950
1198
  genericError: 'Ocorreu um erro no processamento de sua solicitação.',
951
1199
  },
@@ -1120,6 +1368,18 @@ const SPINE_MESSAGES_PT_BR = {
1120
1368
  pathPlaceholder: 'ex.: dashboard',
1121
1369
  pathHint: 'Um trecho só do endereço: letras minúsculas e hífen. O "/" entre níveis é o roteador que monta.',
1122
1370
  pathInvalid: 'Use só letras minúsculas (a–z) e hífen, sem "/", espaço, número ou acento, e sem hífen no início ou no fim.',
1371
+ confirmDeleteAppHeading: 'Excluir aplicação?',
1372
+ confirmDeleteApp: 'A aplicação {name} será excluída e a credencial dela para de funcionar. Esta ação não pode ser desfeita.',
1373
+ confirmDeleteRouteHeading: 'Excluir rota?',
1374
+ confirmDeleteRoute: 'A rota {name} será excluída deste cliente. Esta ação não pode ser desfeita.',
1375
+ confirmDeleteRouterHeading: 'Excluir roteador?',
1376
+ confirmDeleteRouter: 'O roteador {path} será excluído e a página sai do menu. Esta ação não pode ser desfeita.',
1377
+ confirmRemoveAccessHeading: 'Remover acesso?',
1378
+ confirmRemoveAccess: 'O grupo {group} perde o acesso às rotas privadas deste cliente.',
1379
+ confirmRemoveConsumerHeading: 'Remover acesso à aplicação?',
1380
+ confirmRemoveConsumer: 'O grupo {group} deixa de consumir esta aplicação e perde as permissões de operação dela.',
1381
+ deleteDone: 'Exclusão concluída.',
1382
+ deleteError: 'Não foi possível excluir. Tente de novo.',
1123
1383
  colExcludable: 'Excluível',
1124
1384
  excludableYes: 'Sim',
1125
1385
  excludableNo: 'Não',
@@ -1127,6 +1387,21 @@ const SPINE_MESSAGES_PT_BR = {
1127
1387
  colDisplay: 'Exibição',
1128
1388
  colIcon: 'Ícone',
1129
1389
  colPath: 'Path',
1390
+ reorder: 'Reordenar',
1391
+ reorderTitle: 'Reordenar menu',
1392
+ reorderHint: 'Mude a ordem em que os itens aparecem no menu do app: arraste pela alça (ou, no teclado, Espaço na alça e as setas) ou use os botões de subir e descer. Para ordenar o que fica dentro de um item, entre nele.',
1393
+ reorderPath: 'Nível do menu',
1394
+ reorderRoot: 'Topo do menu',
1395
+ reorderListLabel: 'Ordem em {name}',
1396
+ reorderEmpty: 'Nenhum roteador cadastrado para ordenar.',
1397
+ moveUp: 'Mover {name} para cima',
1398
+ moveDown: 'Mover {name} para baixo',
1399
+ openLevel: 'Ordenar o que fica dentro de {name}',
1400
+ childCount: { one: '1 item dentro', other: '{count} itens dentro' },
1401
+ movedTo: '{name}: posição {position} de {total}',
1402
+ reorderLoadError: 'Não foi possível carregar o menu. Tente de novo.',
1403
+ reorderSaveError: 'Não foi possível salvar a ordem. Nada foi perdido: tente de novo.',
1404
+ reorderSave: 'Salvar ordem',
1130
1405
  },
1131
1406
  autoServiceAudit: {
1132
1407
  title: 'Auditoria',
@@ -1481,6 +1756,20 @@ const SPINE_MESSAGES_EN = {
1481
1756
  logout: 'Sign out',
1482
1757
  logoutDescription: 'Ends the session in this browser.',
1483
1758
  logoutKeywords: 'logout disconnect',
1759
+ security: 'Account and security',
1760
+ securityDescription: 'Two-step verification, recovery codes and sessions of your Argos account, the sign-in for the applications.',
1761
+ securityKeywords: 'security argos password authentication mfa 2fa devices',
1762
+ signedInAccount: 'Argos account',
1763
+ signedInRealm: 'Realm {realm}',
1764
+ twoFactor: 'Two-step verification',
1765
+ twoFactorDescription: 'Add or remove methods (authenticator app or email) and switch the authenticator to a new device.',
1766
+ twoFactorKeywords: 'mfa 2fa totp authenticator code email method device phone',
1767
+ recoveryCodes: 'Recovery codes',
1768
+ recoveryCodesDescription: 'Use them to sign in if you lose your device. Generating new codes invalidates the previous ones.',
1769
+ recoveryCodesKeywords: 'backup recovery lost phone device mfa 2fa',
1770
+ sessions: 'Sessions and devices',
1771
+ sessionsDescription: 'See where your account is signed in (browser, system, IP, last used) and end one session or all the others.',
1772
+ sessionsKeywords: 'devices browser ip end sign out disconnect connected',
1484
1773
  about: 'About',
1485
1774
  aboutKeywords: 'version build environment dependencies support',
1486
1775
  application: 'Application',
@@ -1558,6 +1847,115 @@ const SPINE_MESSAGES_EN = {
1558
1847
  revoked: 'Token "{name}" revoked. It may take up to 2 minutes to stop working in every system.',
1559
1848
  revokeError: "Couldn't revoke the token.",
1560
1849
  },
1850
+ accountSecurity: {
1851
+ loading: 'Loading…',
1852
+ loadError: "Couldn't load your Argos account.",
1853
+ sessionEnded: 'This sign-in session has ended in Argos. Sign in again to manage your account.',
1854
+ retry: 'Try again',
1855
+ methodTotp: 'Authenticator app',
1856
+ methodEmail: 'Email',
1857
+ methodSms: 'SMS',
1858
+ active: 'Active',
1859
+ activeWithDetail: 'Active · {detail}',
1860
+ notRegistered: 'Not set up',
1861
+ unavailable: 'Unavailable',
1862
+ requiredHint: 'Required in this environment: keep at least one method.',
1863
+ add: 'Add',
1864
+ replaceDevice: 'Switch device',
1865
+ remove: 'Remove',
1866
+ cancel: 'Cancel',
1867
+ confirm: 'Confirm',
1868
+ removeTitle: 'Remove {method}?',
1869
+ removeHint: "You won't be able to use this method to sign in anymore.",
1870
+ removeLastHint: 'With no method left, the recovery codes stop working too.',
1871
+ reauthTitle: 'Confirm your identity',
1872
+ reauthHint: 'To change two-step verification or generate codes, prove who you are again. It lasts 5 minutes.',
1873
+ reauthHow: 'How to confirm',
1874
+ reauthPassword: 'Password',
1875
+ reauthRecoveryCode: 'Recovery code',
1876
+ currentPassword: 'Current password',
1877
+ passwordRequired: 'Enter your password.',
1878
+ recoveryCode: 'Recovery code',
1879
+ recoveryCodePlaceholder: 'XXXXX-XXXXX',
1880
+ recoveryCodeRequired: 'Enter the code.',
1881
+ recoveryCodeLength: 'The code has 10 letters and digits.',
1882
+ sendEmailCode: 'Send a code to the registered email',
1883
+ sixDigitCode: '6-digit code',
1884
+ totpTitle: 'Scan the QR code with the authenticator app',
1885
+ qrAlt: 'QR code to set up the authenticator app',
1886
+ manualKey: 'No camera? Type the key:',
1887
+ appCode: 'Code from the app',
1888
+ emailTitle: 'Add email',
1889
+ email: 'Email',
1890
+ emailPlaceholder: 'name@company.com',
1891
+ emailRequired: 'Enter the email.',
1892
+ emailInvalid: 'Enter a valid email.',
1893
+ sendCode: 'Send code',
1894
+ emailCodeTitle: 'Confirm the email',
1895
+ emailCodeHint: 'Enter the 6-digit code sent to {email}.',
1896
+ codesRemaining: { zero: 'No codes available.', one: '1 code available.', other: '{count} codes available.' },
1897
+ codesHint: 'Each one signs you in once if you lose your verification method.',
1898
+ codesNeedMethod: 'Set up a verification method to generate recovery codes.',
1899
+ generateCodes: 'Generate codes',
1900
+ regenerateCodes: 'Generate new codes',
1901
+ codesTitle: 'Your recovery codes',
1902
+ codesShownOnce: "Keep these codes somewhere safe. Each one signs you in once if you lose access to your verification method. They won't be shown again.",
1903
+ copyCodes: 'Copy',
1904
+ downloadCodes: 'Download .txt',
1905
+ codesCopied: 'Codes copied.',
1906
+ copyFailed: "Couldn't copy. Select the codes and copy them manually.",
1907
+ codesSaved: "I've saved the codes",
1908
+ codesFileHeader: 'Argos recovery codes (each one works once)',
1909
+ codesFileName: 'recovery-codes.txt',
1910
+ notices: {
1911
+ methodAdded: 'Method added.',
1912
+ deviceReplaced: 'Device switched. The previous one no longer generates valid codes.',
1913
+ methodRemoved: 'Method removed.',
1914
+ codesRegenerated: 'Recovery codes generated. The previous ones no longer work.',
1915
+ reauthCodeSent: 'We sent a code to the registered email.',
1916
+ },
1917
+ errors: {
1918
+ generic: "Couldn't finish. Try again.",
1919
+ network: "Couldn't reach Argos. Check the connection and try again.",
1920
+ login_required: 'This sign-in session has ended in Argos. Sign in again to manage your account.',
1921
+ invalid_token: 'This sign-in session has ended in Argos. Sign in again to manage your account.',
1922
+ reauthentication_required: 'The identity confirmation expired. Confirm again to continue.',
1923
+ invalid_password: 'Wrong password.',
1924
+ account_locked: 'Too many password attempts. The account is locked for a few minutes.',
1925
+ invalid_code: 'Wrong code.',
1926
+ invalid_recovery_code: 'Invalid or already used recovery code.',
1927
+ code_expired: 'The code expired. Request another one.',
1928
+ code_not_requested: 'Request the code before typing it.',
1929
+ too_many_attempts: 'Too many attempts. Wait a few minutes and try again.',
1930
+ too_many_requests: 'Wait a moment before requesting another code.',
1931
+ mfa_method_not_allowed: "This method isn't accepted in this environment.",
1932
+ mfa_method_not_found: 'This method was no longer set up.',
1933
+ mfa_last_method: 'Two-step verification is required: keep at least one method.',
1934
+ invalid_email: 'Enter a valid email.',
1935
+ enrollment_not_started: 'The setup expired. Start again.',
1936
+ sms_not_available: 'SMS unavailable.',
1937
+ mfa_required_for_recovery_codes: 'Set up a verification method before generating codes.',
1938
+ session_not_found: 'The session had already ended.',
1939
+ },
1940
+ sessionsEmpty: 'No active sessions.',
1941
+ thisSession: 'This session',
1942
+ thisBrowser: 'This browser',
1943
+ appsOnly: 'Apps only',
1944
+ sessionDetail: 'IP {ip} · last used {date}',
1945
+ unknownIp: 'unknown',
1946
+ sessionSince: 'Since {date}',
1947
+ sessionApps: 'Apps: {apps}',
1948
+ unnamedApp: 'App',
1949
+ endSession: 'End',
1950
+ confirmEndSession: 'Confirm ending',
1951
+ endOthers: 'End all other sessions',
1952
+ endOthersConfirm: {
1953
+ one: 'End the other session? Apps open in it will ask you to sign in again.',
1954
+ other: 'End the {count} other sessions? Apps open in them will ask you to sign in again.',
1955
+ },
1956
+ sessionEndedNotice: 'Session ended.',
1957
+ othersEndedNotice: { zero: 'No sessions ended.', one: '1 session ended.', other: '{count} sessions ended.' },
1958
+ },
1561
1959
  notification: {
1562
1960
  genericError: 'An error occurred while processing your request.',
1563
1961
  },
@@ -1732,6 +2130,18 @@ const SPINE_MESSAGES_EN = {
1732
2130
  pathPlaceholder: 'e.g.: dashboard',
1733
2131
  pathHint: 'A single piece of the address: lowercase letters and hyphens. The router adds the "/" between levels.',
1734
2132
  pathInvalid: 'Use only lowercase letters (a–z) and hyphens — no "/", spaces, digits or accents, and no hyphen at the start or end.',
2133
+ confirmDeleteAppHeading: 'Delete application?',
2134
+ confirmDeleteApp: 'The application {name} will be deleted and its credential will stop working. This cannot be undone.',
2135
+ confirmDeleteRouteHeading: 'Delete route?',
2136
+ confirmDeleteRoute: 'The route {name} will be deleted from this client. This cannot be undone.',
2137
+ confirmDeleteRouterHeading: 'Delete router?',
2138
+ confirmDeleteRouter: 'The router {path} will be deleted and the page leaves the menu. This cannot be undone.',
2139
+ confirmRemoveAccessHeading: 'Remove access?',
2140
+ confirmRemoveAccess: 'The group {group} loses access to the private routes of this client.',
2141
+ confirmRemoveConsumerHeading: 'Remove access to the application?',
2142
+ confirmRemoveConsumer: 'The group {group} stops consuming this application and loses its operation permissions.',
2143
+ deleteDone: 'Deleted.',
2144
+ deleteError: 'Could not delete. Try again.',
1735
2145
  colExcludable: 'Deletable',
1736
2146
  excludableYes: 'Yes',
1737
2147
  excludableNo: 'No',
@@ -1739,6 +2149,21 @@ const SPINE_MESSAGES_EN = {
1739
2149
  colDisplay: 'Display',
1740
2150
  colIcon: 'Icon',
1741
2151
  colPath: 'Path',
2152
+ reorder: 'Reorder',
2153
+ reorderTitle: 'Reorder menu',
2154
+ reorderHint: 'Change the order in which items appear in the app menu: drag by the handle (or, on the keyboard, Space on the handle and the arrow keys) or use the up and down buttons. To order what sits inside an item, open it.',
2155
+ reorderPath: 'Menu level',
2156
+ reorderRoot: 'Top of the menu',
2157
+ reorderListLabel: 'Order in {name}',
2158
+ reorderEmpty: 'No router registered to order.',
2159
+ moveUp: 'Move {name} up',
2160
+ moveDown: 'Move {name} down',
2161
+ openLevel: 'Order what sits inside {name}',
2162
+ childCount: { one: '1 item inside', other: '{count} items inside' },
2163
+ movedTo: '{name}: position {position} of {total}',
2164
+ reorderLoadError: 'Could not load the menu. Try again.',
2165
+ reorderSaveError: 'Could not save the order. Nothing was lost: try again.',
2166
+ reorderSave: 'Save order',
1742
2167
  },
1743
2168
  autoServiceAudit: {
1744
2169
  title: 'Audit',
@@ -2093,6 +2518,20 @@ const SPINE_MESSAGES_ES = {
2093
2518
  logout: 'Salir',
2094
2519
  logoutDescription: 'Cierra la sesión en este navegador.',
2095
2520
  logoutKeywords: 'logout desconectar',
2521
+ security: 'Cuenta y seguridad',
2522
+ securityDescription: 'Verificación en dos pasos, códigos de recuperación y sesiones de tu cuenta de Argos, el inicio de sesión de las aplicaciones.',
2523
+ securityKeywords: 'seguridad argos contraseña autenticación mfa 2fa dispositivos',
2524
+ signedInAccount: 'Cuenta de Argos',
2525
+ signedInRealm: 'Realm {realm}',
2526
+ twoFactor: 'Verificación en dos pasos',
2527
+ twoFactorDescription: 'Agrega o quita métodos (aplicación de autenticación o correo electrónico) y cambia el dispositivo del autenticador.',
2528
+ twoFactorKeywords: 'mfa 2fa totp autenticador authenticator código correo método dispositivo celular',
2529
+ recoveryCodes: 'Códigos de recuperación',
2530
+ recoveryCodesDescription: 'Sirven para iniciar sesión si pierdes el dispositivo. Generar códigos nuevos invalida los anteriores.',
2531
+ recoveryCodesKeywords: 'respaldo recuperación perdí celular dispositivo mfa 2fa',
2532
+ sessions: 'Sesiones y dispositivos',
2533
+ sessionsDescription: 'Ve dónde está conectada tu cuenta (navegador, sistema, IP, último uso) y cierra una sesión o todas las demás.',
2534
+ sessionsKeywords: 'dispositivos navegador ip cerrar desconectar salir conectados',
2096
2535
  about: 'Acerca de',
2097
2536
  aboutKeywords: 'versión build entorno dependencias soporte',
2098
2537
  application: 'Aplicación',
@@ -2170,6 +2609,115 @@ const SPINE_MESSAGES_ES = {
2170
2609
  revoked: 'Token "{name}" revocado. Puede tardar hasta 2 minutos en dejar de funcionar en todos los sistemas.',
2171
2610
  revokeError: 'No se pudo revocar el token.',
2172
2611
  },
2612
+ accountSecurity: {
2613
+ loading: 'Cargando…',
2614
+ loadError: 'No se pudo cargar tu cuenta de Argos.',
2615
+ sessionEnded: 'La sesión de este inicio de sesión terminó en Argos. Inicia sesión de nuevo para administrar la cuenta.',
2616
+ retry: 'Intentar de nuevo',
2617
+ methodTotp: 'Aplicación de autenticación',
2618
+ methodEmail: 'Correo electrónico',
2619
+ methodSms: 'SMS',
2620
+ active: 'Activo',
2621
+ activeWithDetail: 'Activo · {detail}',
2622
+ notRegistered: 'No registrado',
2623
+ unavailable: 'No disponible',
2624
+ requiredHint: 'Obligatoria en este entorno: mantén al menos un método.',
2625
+ add: 'Agregar',
2626
+ replaceDevice: 'Cambiar dispositivo',
2627
+ remove: 'Quitar',
2628
+ cancel: 'Cancelar',
2629
+ confirm: 'Confirmar',
2630
+ removeTitle: '¿Quitar {method}?',
2631
+ removeHint: 'Ya no podrás usar este método para iniciar sesión.',
2632
+ removeLastHint: 'Sin ningún método, los códigos de recuperación también dejan de valer.',
2633
+ reauthTitle: 'Confirma tu identidad',
2634
+ reauthHint: 'Para cambiar la verificación en dos pasos o generar códigos, demuestra de nuevo quién eres. Vale por 5 minutos.',
2635
+ reauthHow: 'Cómo confirmar',
2636
+ reauthPassword: 'Contraseña',
2637
+ reauthRecoveryCode: 'Código de recuperación',
2638
+ currentPassword: 'Contraseña actual',
2639
+ passwordRequired: 'Ingresa la contraseña.',
2640
+ recoveryCode: 'Código de recuperación',
2641
+ recoveryCodePlaceholder: 'XXXXX-XXXXX',
2642
+ recoveryCodeRequired: 'Ingresa el código.',
2643
+ recoveryCodeLength: 'El código tiene 10 letras y números.',
2644
+ sendEmailCode: 'Enviar un código al correo registrado',
2645
+ sixDigitCode: 'Código de 6 dígitos',
2646
+ totpTitle: 'Escanea el código QR con la aplicación de autenticación',
2647
+ qrAlt: 'Código QR para configurar la aplicación de autenticación',
2648
+ manualKey: '¿Sin cámara? Escribe la clave:',
2649
+ appCode: 'Código de la aplicación',
2650
+ emailTitle: 'Registrar correo electrónico',
2651
+ email: 'Correo electrónico',
2652
+ emailPlaceholder: 'nombre@empresa.com',
2653
+ emailRequired: 'Ingresa el correo electrónico.',
2654
+ emailInvalid: 'Ingresa un correo electrónico válido.',
2655
+ sendCode: 'Enviar código',
2656
+ emailCodeTitle: 'Confirma el correo electrónico',
2657
+ emailCodeHint: 'Escribe el código de 6 dígitos enviado a {email}.',
2658
+ codesRemaining: { zero: 'Ningún código disponible.', one: '1 código disponible.', other: '{count} códigos disponibles.' },
2659
+ codesHint: 'Cada uno vale una vez para iniciar sesión si pierdes tu método de verificación.',
2660
+ codesNeedMethod: 'Registra un método de verificación para generar códigos de recuperación.',
2661
+ generateCodes: 'Generar códigos',
2662
+ regenerateCodes: 'Generar códigos nuevos',
2663
+ codesTitle: 'Tus códigos de recuperación',
2664
+ codesShownOnce: 'Guarda estos códigos en un lugar seguro. Cada uno vale una sola vez para iniciar sesión si pierdes el acceso a tu método de verificación. No se volverán a mostrar.',
2665
+ copyCodes: 'Copiar',
2666
+ downloadCodes: 'Descargar .txt',
2667
+ codesCopied: 'Códigos copiados.',
2668
+ copyFailed: 'No se pudo copiar. Selecciona los códigos y cópialos manualmente.',
2669
+ codesSaved: 'Ya guardé los códigos',
2670
+ codesFileHeader: 'Códigos de recuperación de Argos (cada uno vale una vez)',
2671
+ codesFileName: 'codigos-de-recuperacion.txt',
2672
+ notices: {
2673
+ methodAdded: 'Método registrado.',
2674
+ deviceReplaced: 'Dispositivo cambiado. El anterior ya no genera códigos válidos.',
2675
+ methodRemoved: 'Método quitado.',
2676
+ codesRegenerated: 'Códigos de recuperación generados. Los anteriores ya no valen.',
2677
+ reauthCodeSent: 'Enviamos un código al correo registrado.',
2678
+ },
2679
+ errors: {
2680
+ generic: 'No se pudo completar. Intenta de nuevo.',
2681
+ network: 'No se pudo conectar con Argos. Revisa la conexión e intenta de nuevo.',
2682
+ login_required: 'La sesión de este inicio de sesión terminó en Argos. Inicia sesión de nuevo para administrar la cuenta.',
2683
+ invalid_token: 'La sesión de este inicio de sesión terminó en Argos. Inicia sesión de nuevo para administrar la cuenta.',
2684
+ reauthentication_required: 'La confirmación de identidad venció. Confirma de nuevo para continuar.',
2685
+ invalid_password: 'Contraseña incorrecta.',
2686
+ account_locked: 'Demasiados intentos con la contraseña. La cuenta quedó bloqueada unos minutos.',
2687
+ invalid_code: 'Código incorrecto.',
2688
+ invalid_recovery_code: 'Código de recuperación inválido o ya usado.',
2689
+ code_expired: 'El código venció. Pide otro.',
2690
+ code_not_requested: 'Pide el código antes de escribirlo.',
2691
+ too_many_attempts: 'Demasiados intentos. Espera unos minutos e intenta de nuevo.',
2692
+ too_many_requests: 'Espera un poco antes de pedir otro código.',
2693
+ mfa_method_not_allowed: 'Este método no se acepta en este entorno.',
2694
+ mfa_method_not_found: 'Este método ya no estaba registrado.',
2695
+ mfa_last_method: 'La verificación en dos pasos es obligatoria: mantén al menos un método.',
2696
+ invalid_email: 'Ingresa un correo electrónico válido.',
2697
+ enrollment_not_started: 'El registro venció. Empieza de nuevo.',
2698
+ sms_not_available: 'SMS no disponible.',
2699
+ mfa_required_for_recovery_codes: 'Registra un método de verificación antes de generar códigos.',
2700
+ session_not_found: 'La sesión ya se había cerrado.',
2701
+ },
2702
+ sessionsEmpty: 'Ninguna sesión activa.',
2703
+ thisSession: 'Esta sesión',
2704
+ thisBrowser: 'Este navegador',
2705
+ appsOnly: 'Solo aplicaciones',
2706
+ sessionDetail: 'IP {ip} · último uso {date}',
2707
+ unknownIp: 'desconocida',
2708
+ sessionSince: 'Desde {date}',
2709
+ sessionApps: 'Aplicaciones: {apps}',
2710
+ unnamedApp: 'Aplicación',
2711
+ endSession: 'Cerrar',
2712
+ confirmEndSession: 'Confirmar cierre',
2713
+ endOthers: 'Cerrar todas las demás',
2714
+ endOthersConfirm: {
2715
+ one: '¿Cerrar la otra sesión? Las aplicaciones abiertas en ella pedirán iniciar sesión de nuevo.',
2716
+ other: '¿Cerrar las {count} otras sesiones? Las aplicaciones abiertas en ellas pedirán iniciar sesión de nuevo.',
2717
+ },
2718
+ sessionEndedNotice: 'Sesión cerrada.',
2719
+ othersEndedNotice: { zero: 'Ninguna sesión cerrada.', one: '1 sesión cerrada.', other: '{count} sesiones cerradas.' },
2720
+ },
2173
2721
  notification: {
2174
2722
  genericError: 'Ocurrió un error al procesar tu solicitud.',
2175
2723
  },
@@ -2344,6 +2892,18 @@ const SPINE_MESSAGES_ES = {
2344
2892
  pathPlaceholder: 'ej.: dashboard',
2345
2893
  pathHint: 'Un solo tramo de la dirección: letras minúsculas y guion. El "/" entre niveles lo arma el enrutador.',
2346
2894
  pathInvalid: 'Usa solo letras minúsculas (a–z) y guion — sin "/", espacios, números ni acentos, y sin guion al inicio o al final.',
2895
+ confirmDeleteAppHeading: '¿Eliminar aplicación?',
2896
+ confirmDeleteApp: 'La aplicación {name} se eliminará y su credencial dejará de funcionar. Esta acción no se puede deshacer.',
2897
+ confirmDeleteRouteHeading: '¿Eliminar ruta?',
2898
+ confirmDeleteRoute: 'La ruta {name} se eliminará de este cliente. Esta acción no se puede deshacer.',
2899
+ confirmDeleteRouterHeading: '¿Eliminar enrutador?',
2900
+ confirmDeleteRouter: 'El enrutador {path} se eliminará y la página sale del menú. Esta acción no se puede deshacer.',
2901
+ confirmRemoveAccessHeading: '¿Quitar acceso?',
2902
+ confirmRemoveAccess: 'El grupo {group} pierde el acceso a las rutas privadas de este cliente.',
2903
+ confirmRemoveConsumerHeading: '¿Quitar acceso a la aplicación?',
2904
+ confirmRemoveConsumer: 'El grupo {group} deja de consumir esta aplicación y pierde sus permisos de operación.',
2905
+ deleteDone: 'Eliminación completada.',
2906
+ deleteError: 'No se pudo eliminar. Inténtalo de nuevo.',
2347
2907
  colExcludable: 'Eliminable',
2348
2908
  excludableYes: 'Sí',
2349
2909
  excludableNo: 'No',
@@ -2351,6 +2911,21 @@ const SPINE_MESSAGES_ES = {
2351
2911
  colDisplay: 'Visible',
2352
2912
  colIcon: 'Ícono',
2353
2913
  colPath: 'Path',
2914
+ reorder: 'Reordenar',
2915
+ reorderTitle: 'Reordenar menú',
2916
+ reorderHint: 'Cambie el orden en que los elementos aparecen en el menú de la app: arrastre por el asa (o, con el teclado, Espacio en el asa y las flechas) o use los botones de subir y bajar. Para ordenar lo que hay dentro de un elemento, entre en él.',
2917
+ reorderPath: 'Nivel del menú',
2918
+ reorderRoot: 'Inicio del menú',
2919
+ reorderListLabel: 'Orden en {name}',
2920
+ reorderEmpty: 'Ningún enrutador registrado para ordenar.',
2921
+ moveUp: 'Mover {name} hacia arriba',
2922
+ moveDown: 'Mover {name} hacia abajo',
2923
+ openLevel: 'Ordenar lo que hay dentro de {name}',
2924
+ childCount: { one: '1 elemento dentro', other: '{count} elementos dentro' },
2925
+ movedTo: '{name}: posición {position} de {total}',
2926
+ reorderLoadError: 'No se pudo cargar el menú. Inténtelo de nuevo.',
2927
+ reorderSaveError: 'No se pudo guardar el orden. No se perdió nada: inténtelo de nuevo.',
2928
+ reorderSave: 'Guardar orden',
2354
2929
  },
2355
2930
  autoServiceAudit: {
2356
2931
  title: 'Auditoría',
@@ -2570,5 +3145,5 @@ function provideSpineMessages(config) {
2570
3145
  * Generated bundle index. Do not edit.
2571
3146
  */
2572
3147
 
2573
- export { APP_PACKAGE_INFO, DensityService, HERMES_DS_IMPORTS, SPINE_ADMIN_API, SPINE_CONFIG, SPINE_DEFAULT_LOGO, SPINE_I18N_CONFIG, SPINE_MESSAGES, SPINE_MESSAGES_EN, SPINE_MESSAGES_ES, SPINE_MESSAGES_PT_BR, SPINE_NEWS, SpinePreferencesService, SpineQuickAccessService, ThemePresetService, ThemeService, applyRuntimeEnvironment, applySpineFavicon, currentSpineMessages, mergeRouteTree, provideSpineMessages, provideSpineNews, provideUi, resolveSpineLogo, routerIdOf, spineRoutesOf };
3148
+ export { APP_PACKAGE_INFO, DensityService, HERMES_DS_IMPORTS, SPINE_ADMIN_API, SPINE_CONFIG, SPINE_DEFAULT_LOGO, SPINE_I18N_CONFIG, SPINE_MESSAGES, SPINE_MESSAGES_EN, SPINE_MESSAGES_ES, SPINE_MESSAGES_PT_BR, SPINE_NEWS, SPINE_USER_STORAGE_KEYS, SpinePreferencesService, SpineQuickAccessService, SpineUserStorage, ThemePresetService, ThemeService, applyRuntimeEnvironment, applySpineFavicon, currentSpineMessages, mergeRouteTree, provideSpineMessages, provideSpineNews, provideUi, resolveSpineLogo, routerIdOf, spineRoutesOf };
2574
3149
  //# sourceMappingURL=trismegisto-spine.mjs.map