@trismegisto/spine 2.0.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 (55) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +207 -0
  3. package/fesm2022/trismegisto-spine-audit.mjs +1299 -0
  4. package/fesm2022/trismegisto-spine-audit.mjs.map +1 -0
  5. package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs +37 -0
  6. package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs.map +1 -0
  7. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs +51 -0
  8. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs.map +1 -0
  9. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs +595 -0
  10. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs.map +1 -0
  11. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs +357 -0
  12. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs.map +1 -0
  13. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs +477 -0
  14. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs.map +1 -0
  15. package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs +238 -0
  16. package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs.map +1 -0
  17. package/fesm2022/trismegisto-spine-auto-service.mjs +154 -0
  18. package/fesm2022/trismegisto-spine-auto-service.mjs.map +1 -0
  19. package/fesm2022/trismegisto-spine-graphql.mjs +347 -0
  20. package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -0
  21. package/fesm2022/trismegisto-spine-layout.mjs +2848 -0
  22. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -0
  23. package/fesm2022/trismegisto-spine-modal.mjs +141 -0
  24. package/fesm2022/trismegisto-spine-modal.mjs.map +1 -0
  25. package/fesm2022/trismegisto-spine-notification.mjs +122 -0
  26. package/fesm2022/trismegisto-spine-notification.mjs.map +1 -0
  27. package/fesm2022/trismegisto-spine-routing.mjs +398 -0
  28. package/fesm2022/trismegisto-spine-routing.mjs.map +1 -0
  29. package/fesm2022/trismegisto-spine-shell.mjs +409 -0
  30. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -0
  31. package/fesm2022/trismegisto-spine-side-panel.mjs +142 -0
  32. package/fesm2022/trismegisto-spine-side-panel.mjs.map +1 -0
  33. package/fesm2022/trismegisto-spine.mjs +2574 -0
  34. package/fesm2022/trismegisto-spine.mjs.map +1 -0
  35. package/package.json +94 -0
  36. package/types/trismegisto-spine-audit.d.ts +948 -0
  37. package/types/trismegisto-spine-audit.d.ts.map +1 -0
  38. package/types/trismegisto-spine-auto-service.d.ts +110 -0
  39. package/types/trismegisto-spine-auto-service.d.ts.map +1 -0
  40. package/types/trismegisto-spine-graphql.d.ts +72 -0
  41. package/types/trismegisto-spine-graphql.d.ts.map +1 -0
  42. package/types/trismegisto-spine-layout.d.ts +1054 -0
  43. package/types/trismegisto-spine-layout.d.ts.map +1 -0
  44. package/types/trismegisto-spine-modal.d.ts +68 -0
  45. package/types/trismegisto-spine-modal.d.ts.map +1 -0
  46. package/types/trismegisto-spine-notification.d.ts +62 -0
  47. package/types/trismegisto-spine-notification.d.ts.map +1 -0
  48. package/types/trismegisto-spine-routing.d.ts +205 -0
  49. package/types/trismegisto-spine-routing.d.ts.map +1 -0
  50. package/types/trismegisto-spine-shell.d.ts +143 -0
  51. package/types/trismegisto-spine-shell.d.ts.map +1 -0
  52. package/types/trismegisto-spine-side-panel.d.ts +66 -0
  53. package/types/trismegisto-spine-side-panel.d.ts.map +1 -0
  54. package/types/trismegisto-spine.d.ts +1161 -0
  55. package/types/trismegisto-spine.d.ts.map +1 -0
@@ -0,0 +1,409 @@
1
+ import { SPINE_MESSAGES, APP_PACKAGE_INFO, spineRoutesOf } from '@trismegisto/spine';
2
+ export { APP_PACKAGE_INFO } from '@trismegisto/spine';
3
+ import * as i2 from '@orfeu/angular/core';
4
+ import { AuthorizationService, PrivateGuard, ViewService } from '@orfeu/angular/core';
5
+ import { LayoutComponent } from '@trismegisto/spine/layout';
6
+ import { ViewGuard, componentRouterId, COMPONENT_ROUTES, RouteIdInterceptor, findFirstNavigable } from '@trismegisto/spine/routing';
7
+ import * as i0 from '@angular/core';
8
+ import { ChangeDetectionStrategy, Component, inject, signal, makeEnvironmentProviders, DestroyRef } from '@angular/core';
9
+ import * as i1 from '@angular/router';
10
+ import { ActivatedRoute, Router } from '@angular/router';
11
+ import { StatePageComponent } from '@trismegisto/angular';
12
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
13
+
14
+ // Movido para o pacote raiz (ver package-info.token.ts) — reexportado aqui para não quebrar
15
+ // quem importa `APP_PACKAGE_INFO`/`PackageInfo` de '@trismegisto/spine/shell'.
16
+
17
+ /**
18
+ * Componente vazio pra rota `**` (ver `private.routes.ts`) — o Angular Router EXIGE
19
+ * `component`/`loadComponent`/`redirectTo`/`children`/`loadChildren` em toda rota (`NG04014` se
20
+ * nenhum for dado), mas quem desenha o conteúdo aqui é o `hm-workspace`
21
+ * (`SpinePagePanelComponent`, resolvido por `resolveSpineRoute`, sem passar pelo `Router`), não um
22
+ * `<router-outlet>`. Este componente só satisfaz a validação do Router — nunca renderiza nada de
23
+ * visível (o `<router-outlet>` real que sobra em `LayoutComponent` fica escondido via `[hidden]`
24
+ * sempre que a rota ativa não é `/no-permission`, a única com conteúdo de verdade).
25
+ */
26
+ class EmptyRouteComponent {
27
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: EmptyRouteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: EmptyRouteComponent, isStandalone: true, selector: "spine-empty-route", ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
29
+ }
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: EmptyRouteComponent, decorators: [{
31
+ type: Component,
32
+ args: [{
33
+ selector: 'spine-empty-route',
34
+ template: '',
35
+ changeDetection: ChangeDetectionStrategy.OnPush,
36
+ }]
37
+ }] });
38
+
39
+ /**
40
+ * Quem desenha o conteúdo agora é o `hm-workspace` (ver `LayoutComponent`/
41
+ * `layout/src/workspace/`), nunca um `<router-outlet>` aninhado — a árvore de 6 níveis
42
+ * (header/navigation/menu/item/submenu/page) que existia aqui foi substituída por
43
+ * `resolveSpineRoute`, chamada por painel. Estas rotas só precisam existir pro `Router` real
44
+ * "reconhecer" a URL (deep link, F5, `router.navigateByUrl` do painel focado) e pro `ViewGuard`
45
+ * confirmar que ela resolve contra a view atual antes do painel tentar renderizá-la — `component`
46
+ * é só `EmptyRouteComponent` (o Angular exige um dos cinco em toda rota, `NG04014` senão; o
47
+ * `<router-outlet>` que o recebe fica escondido, ver `LayoutComponent`).
48
+ */
49
+ const PRIVATE_ROUTES = [
50
+ {
51
+ path: 'no-permission',
52
+ loadComponent: () => Promise.resolve().then(function () { return noRights_component; }).then(m => m.NoRightsComponent),
53
+ },
54
+ { path: '', pathMatch: 'full', redirectTo: 'home' },
55
+ { path: '**', canActivate: [ViewGuard], component: EmptyRouteComponent },
56
+ ];
57
+
58
+ /** Chave do `@orfeu/angular` com a URL pedida antes do login (documentada no MIGRATION da lib). */
59
+ const RETURN_URL_KEY = 'orfeu_return_url';
60
+ /**
61
+ * Rota de retorno do Argos (`/callback?code&state` ou `?error`). Tudo passa pelo `handleCallback()` do
62
+ * `@orfeu/angular`, que confere state e verifier, troca o code e navega para a URL pedida antes do login
63
+ * (ou para a 1ª rota do `/view`).
64
+ *
65
+ * - `?error=login_required` (e afins) da reautorização silenciosa (`prompt=none`): o próprio
66
+ * `handleCallback()` segue para o login interativo, mantendo a URL de retorno — a pessoa não fica parada aqui.
67
+ * - Callback inválido (state/nonce divergente, `?error`, sem code): NUNCA desloga. Com uma sessão viva
68
+ * (callback repetido, voltar do navegador), segue para a URL de retorno; sem sessão, mostra a página de
69
+ * erro com "Entrar novamente".
70
+ */
71
+ class CallbackComponent {
72
+ constructor() {
73
+ this.text = inject(SPINE_MESSAGES).session;
74
+ this.route = inject(ActivatedRoute);
75
+ this.router = inject(Router);
76
+ this.auth = inject(AuthorizationService);
77
+ /** `true` quando o callback falhou e não há sessão para onde voltar. */
78
+ this.failed = signal(false, ...(ngDevMode ? [{ debugName: "failed" }] : /* istanbul ignore next */ []));
79
+ this.done = this.handle();
80
+ }
81
+ async handle() {
82
+ const q = this.route.snapshot.queryParamMap;
83
+ const returnUrl = readReturnUrl();
84
+ try {
85
+ await this.auth.handleCallback({
86
+ code: q.get('code') ?? undefined,
87
+ state: q.get('state') ?? undefined,
88
+ error: q.get('error') ?? undefined,
89
+ error_description: q.get('error_description') ?? undefined,
90
+ });
91
+ }
92
+ catch (e) {
93
+ console.warn('[hermes-spine] callback de login recusado:', e);
94
+ if (this.auth.authenticated) {
95
+ // Sessão viva (de outra aba ou anterior): segue para onde a pessoa ia, sem tocar na sessão.
96
+ await this.router.navigateByUrl(returnUrl ?? '/');
97
+ return;
98
+ }
99
+ this.failed.set(true);
100
+ }
101
+ }
102
+ signIn() {
103
+ void this.auth.authorize(readReturnUrl() ?? undefined);
104
+ }
105
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CallbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
106
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: CallbackComponent, isStandalone: true, selector: "app-callback", ngImport: i0, template: `
107
+ @if (failed()) {
108
+ <main class="callback">
109
+ <hm-state-page
110
+ kind="error"
111
+ [heading]="text.callbackFailedHeading"
112
+ [description]="text.callbackFailedText"
113
+ [action]="text.signInAgain"
114
+ actionIcon="login"
115
+ (actionTriggered)="signIn()"
116
+ />
117
+ </main>
118
+ }
119
+ `, isInline: true, styles: [".callback{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"], dependencies: [{ kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
120
+ }
121
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CallbackComponent, decorators: [{
122
+ type: Component,
123
+ args: [{ selector: 'app-callback', imports: [StatePageComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
124
+ @if (failed()) {
125
+ <main class="callback">
126
+ <hm-state-page
127
+ kind="error"
128
+ [heading]="text.callbackFailedHeading"
129
+ [description]="text.callbackFailedText"
130
+ [action]="text.signInAgain"
131
+ actionIcon="login"
132
+ (actionTriggered)="signIn()"
133
+ />
134
+ </main>
135
+ }
136
+ `, styles: [".callback{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"] }]
137
+ }], ctorParameters: () => [] });
138
+ function readReturnUrl() {
139
+ try {
140
+ const url = globalThis.sessionStorage?.getItem(RETURN_URL_KEY) ?? null;
141
+ return url && url.startsWith('/') && !url.startsWith('//') ? url : null;
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+
148
+ class LoggedOutComponent {
149
+ constructor(authorizationService) {
150
+ this.authorizationService = authorizationService;
151
+ }
152
+ goToLogin() { this.authorizationService.authorize(); }
153
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoggedOutComponent, deps: [{ token: i2.AuthorizationService }], target: i0.ɵɵFactoryTarget.Component }); }
154
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: LoggedOutComponent, isStandalone: true, selector: "loggedout", ngImport: i0, template: "<!-- Tela p\u00FAblica (fora do layout): ocupa a janela inteira. P\u00E1gina pronta do hermes, tipo \"logged-out\". -->\n<main class=\"loggedout\">\n <hm-state-page kind=\"logged-out\" (actionTriggered)=\"goToLogin()\" />\n</main>\n", styles: ["@charset \"UTF-8\";.loggedout{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"], dependencies: [{ kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
155
+ }
156
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoggedOutComponent, decorators: [{
157
+ type: Component,
158
+ args: [{ selector: 'loggedout', imports: [StatePageComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<!-- Tela p\u00FAblica (fora do layout): ocupa a janela inteira. P\u00E1gina pronta do hermes, tipo \"logged-out\". -->\n<main class=\"loggedout\">\n <hm-state-page kind=\"logged-out\" (actionTriggered)=\"goToLogin()\" />\n</main>\n", styles: ["@charset \"UTF-8\";.loggedout{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"] }]
159
+ }], ctorParameters: () => [{ type: i2.AuthorizationService }] });
160
+
161
+ class LoginComponent {
162
+ constructor(router, auth, view) {
163
+ this.router = router;
164
+ this.auth = auth;
165
+ this.view = view;
166
+ }
167
+ ngOnInit() { this.bootstrap(); }
168
+ async bootstrap() {
169
+ await this.auth.reauthorize();
170
+ if (this.auth.authenticated) {
171
+ const views = await this.view.update(this.auth.getToken());
172
+ const firstRoute = this.findFirstNavigable(views?.routes || []);
173
+ // Sem grupo nenhum no app (token sem crachá) vence "sem rota": ver ViewGuard.
174
+ if (!this.auth.badges.length)
175
+ this.router.navigate(['/blocked']);
176
+ else
177
+ this.router.navigate([firstRoute ?? '/no-permission']);
178
+ }
179
+ }
180
+ /** Primeira rota navegável (DFS), atravessando grupos "transparentes" sem route_redirect. */
181
+ findFirstNavigable(routes) {
182
+ for (const r of routes || []) {
183
+ if (!r)
184
+ continue;
185
+ if (r.route_redirect)
186
+ return r.route_redirect;
187
+ if (r.routes?.length) {
188
+ const found = this.findFirstNavigable(r.routes);
189
+ if (found)
190
+ return found;
191
+ }
192
+ }
193
+ return null;
194
+ }
195
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoginComponent, deps: [{ token: i1.Router }, { token: i2.AuthorizationService }, { token: i2.ViewService }], target: i0.ɵɵFactoryTarget.Component }); }
196
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: LoginComponent, isStandalone: true, selector: "app-login", ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.Eager }); }
197
+ }
198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoginComponent, decorators: [{
199
+ type: Component,
200
+ args: [{
201
+ selector: 'app-login',
202
+ imports: [],
203
+ changeDetection: ChangeDetectionStrategy.Eager,
204
+ template: ``
205
+ }]
206
+ }], ctorParameters: () => [{ type: i1.Router }, { type: i2.AuthorizationService }, { type: i2.ViewService }] });
207
+
208
+ const PUBLIC_ROUTES = [
209
+ { path: 'login', component: LoginComponent },
210
+ { path: 'callback', component: CallbackComponent },
211
+ { path: 'logoff', component: LoggedOutComponent },
212
+ // Sem nenhum grupo vinculado ao app (ver `ViewGuard`): tela cheia, FORA do layout — sem
213
+ // header nem sidebar, só a informação. Aqui (e não nas privadas) justamente pra não montar o
214
+ // `LayoutComponent`; o `PrivateGuard` garante que só chega quem está autenticado.
215
+ {
216
+ path: 'blocked',
217
+ canActivate: [PrivateGuard],
218
+ loadComponent: () => Promise.resolve().then(function () { return blocked_component; }).then(m => m.BlockedComponent),
219
+ },
220
+ { path: '', redirectTo: 'login', pathMatch: 'full' },
221
+ ];
222
+
223
+ const APP_ROUTES = [
224
+ ...PUBLIC_ROUTES,
225
+ {
226
+ path: '',
227
+ component: LayoutComponent,
228
+ canActivate: [PrivateGuard],
229
+ canActivateChild: [PrivateGuard],
230
+ children: PRIVATE_ROUTES,
231
+ },
232
+ { path: '**', redirectTo: '' },
233
+ ];
234
+
235
+ /**
236
+ * Componentes que o próprio shell traz, ligados pelo `router_id` (web.router) da árvore de rotas do argos.
237
+ *
238
+ * As telas do antigo módulo "Sistema" (Sobre › Recursos/Informações; Preferências › Geral,
239
+ * Autenticação, Exibição, Notificações) saíram em 2026-09-29: viraram o painel de configurações
240
+ * (`@trismegisto/spine/layout` › `SettingsPanelComponent`, menu do perfil ou Ctrl+,). Os router_ids delas
241
+ * (d6a30f9c, 86b87583, 2d71fb9b, 48ebca20, 662a7a61, e7d9982b, bf8a9f69) não têm mais componente —
242
+ * o módulo precisa sair da árvore de rotas no seed do argos.
243
+ *
244
+ * O Início (`HomeComponent`) mudou pra `@trismegisto/spine/auto-service` -- ver a entrada legada abaixo.
245
+ */
246
+ const BASE_COMPONENTS = [
247
+ {
248
+ // LEGADO: o Início agora vem do template Auto-Serviço (`provideAutoService`, casando por
249
+ // source_template_router_id). Esta entrada só cobre o Início do Hefesto em banco cujo router
250
+ // (b06c2784) ainda não aponta pro template -- remover quando todos os ambientes tiverem.
251
+ id: 'b06c2784-eb29-4747-b118-53687c382cf7',
252
+ load: async () => (await import('@trismegisto/spine/auto-service')).AUTO_SERVICE_SCREENS.home(),
253
+ },
254
+ ];
255
+
256
+ function provideShell(options = {}) {
257
+ const appComponents = options.appComponents ?? [];
258
+ const baseIds = new Set(BASE_COMPONENTS.map(componentRouterId));
259
+ const conflicts = appComponents.filter(c => componentRouterId(c) && baseIds.has(componentRouterId(c)));
260
+ if (conflicts.length > 0) {
261
+ throw new Error(`[hermes-spine] provideShell: router_ids em conflito com BASE_COMPONENTS: ${conflicts.map(componentRouterId).join(', ')}`);
262
+ }
263
+ // multi: true -- este provider é só UMA das fontes de COMPONENT_ROUTES (a do próprio
264
+ // app + os componentes base do shell). Pacotes plugáveis (ex.: provideAutoService)
265
+ // contribuem com os deles via outro provider do mesmo token, combinados no
266
+ // ComponentDistributorService -- nunca use { provide: COMPONENT_ROUTES, useValue: ... }
267
+ // sem multi: true em outro lugar, ou o Angular lança erro de provider inconsistente.
268
+ return makeEnvironmentProviders([
269
+ { provide: COMPONENT_ROUTES, useValue: [...BASE_COMPONENTS, ...appComponents], multi: true },
270
+ { provide: HTTP_INTERCEPTORS, useClass: RouteIdInterceptor, multi: true },
271
+ ...(options.packageInfo ? [{ provide: APP_PACKAGE_INFO, useValue: options.packageInfo }] : []),
272
+ ]);
273
+ }
274
+
275
+ /**
276
+ * As telas de acesso (`/blocked` e `/no-permission`) saem sozinhas quando a situação muda — no F5
277
+ * (o token e a view são refeitos na inicialização) ou com a tela aberta (renovação do token, troca
278
+ * de crachá): quem ganhou grupo/permissão não fica preso numa tela que já não vale.
279
+ *
280
+ * Mesma decisão do `ViewGuard`/login, na mesma ordem:
281
+ * - sem crachá nenhum no app (token sem `badges`) → `/blocked`;
282
+ * - com crachá, mas a view sem rota → `/no-permission`;
283
+ * - com rota → a primeira navegável.
284
+ *
285
+ * Só redireciona quando o destino é OUTRO que a tela atual, e com `replaceUrl`: voltar no navegador
286
+ * não devolve pra tela de bloqueio que já não se aplica.
287
+ *
288
+ * Chamar no construtor (contexto de injeção) da tela.
289
+ */
290
+ function watchAccessRecovery(current) {
291
+ const router = inject(Router);
292
+ const auth = inject(AuthorizationService);
293
+ const viewService = inject(ViewService);
294
+ const check = (view) => {
295
+ // Sem sessão (ainda) não há o que decidir: quem cuida disso é o PrivateGuard/login.
296
+ if (!auth.authenticated || !view)
297
+ return;
298
+ const target = !auth.badges.length
299
+ ? '/blocked'
300
+ : (findFirstNavigable(spineRoutesOf(view)) ?? '/no-permission');
301
+ if (target !== current)
302
+ void router.navigateByUrl(target, { replaceUrl: true });
303
+ };
304
+ // O valor atual primeiro (F5 com o token já renovado pelo initialize()) e depois cada atualização
305
+ // da view — ela é sempre refeita depois do token (`view.update`), então o crachá lido aqui já é o novo.
306
+ check(viewService.currentView);
307
+ const sub = viewService.currentView$.subscribe((view) => check(view));
308
+ inject(DestroyRef).onDestroy(() => sub.unsubscribe());
309
+ }
310
+
311
+ class NoRightsComponent {
312
+ constructor(viewService) {
313
+ this.viewService = viewService;
314
+ this.text = inject(SPINE_MESSAGES).access;
315
+ // F5 (ou token renovado) com rota liberada → sai daqui pra primeira rota; sem crachá → /blocked.
316
+ watchAccessRecovery('/no-permission');
317
+ }
318
+ ngOnInit() {
319
+ // /no-permission fica fora da árvore guardada pelo ViewGuard (não tem
320
+ // canActivate), então logControl$/breadCrumb$ nunca são atualizados ao
321
+ // chegar aqui — sem isso, sidebar e breadcrumb continuam mostrando o
322
+ // menu/trilha da última rota válida por baixo da tela de sem-permissão.
323
+ this.viewService.updateBreadcrumb([{}]);
324
+ }
325
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: NoRightsComponent, deps: [{ token: i2.ViewService }], target: i0.ɵɵFactoryTarget.Component }); }
326
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: NoRightsComponent, isStandalone: true, selector: "no-rights", ngImport: i0, template: "<!-- P\u00E1gina pronta do hermes (`hm-state-page`, tipo \"no-rights\"). Sem bot\u00E3o: quem chega aqui n\u00E3o tem\n nenhuma p\u00E1gina liberada, ent\u00E3o \"ir para o in\u00EDcio\" s\u00F3 voltaria pra c\u00E1. -->\n<hm-state-page\n kind=\"no-rights\"\n [description]=\"text.noRightsText\"\n action=\"\"\n/>\n", styles: ["@charset \"UTF-8\";:host{display:flex;min-block-size:100%;flex:1;flex-direction:column}\n"], dependencies: [{ kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
327
+ }
328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: NoRightsComponent, decorators: [{
329
+ type: Component,
330
+ args: [{ selector: 'no-rights', imports: [StatePageComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<!-- P\u00E1gina pronta do hermes (`hm-state-page`, tipo \"no-rights\"). Sem bot\u00E3o: quem chega aqui n\u00E3o tem\n nenhuma p\u00E1gina liberada, ent\u00E3o \"ir para o in\u00EDcio\" s\u00F3 voltaria pra c\u00E1. -->\n<hm-state-page\n kind=\"no-rights\"\n [description]=\"text.noRightsText\"\n action=\"\"\n/>\n", styles: ["@charset \"UTF-8\";:host{display:flex;min-block-size:100%;flex:1;flex-direction:column}\n"] }]
331
+ }], ctorParameters: () => [{ type: i2.ViewService }] });
332
+
333
+ var noRights_component = /*#__PURE__*/Object.freeze({
334
+ __proto__: null,
335
+ NoRightsComponent: NoRightsComponent
336
+ });
337
+
338
+ /**
339
+ * "Acesso bloqueado" (`/blocked`): a pessoa entrou, mas não faz parte de nenhum grupo vinculado a
340
+ * esta aplicação — o `ViewGuard` manda pra cá quando o token vem sem nenhum crachá (`badges`
341
+ * vazio), mesmo que o app tenha rotas públicas.
342
+ *
343
+ * Diferente de `/no-permission` (tem grupo, mas nenhuma rota liberada). A única ação útil aqui é
344
+ * sair — pra entrar com outra conta, ou depois que o administrador incluir a pessoa num grupo.
345
+ */
346
+ class BlockedComponent {
347
+ constructor() {
348
+ this.text = inject(SPINE_MESSAGES).access;
349
+ this.auth = inject(AuthorizationService);
350
+ this.viewService = inject(ViewService);
351
+ // F5 (ou token renovado) já com grupo no app → sai daqui pra primeira rota (ou /no-permission).
352
+ watchAccessRecovery('/blocked');
353
+ }
354
+ ngOnInit() {
355
+ // Zera a trilha da última rota válida (mesmo motivo do NoRightsComponent), pra quem voltar ao
356
+ // layout depois não herdar o breadcrumb de antes do bloqueio.
357
+ this.viewService.updateBreadcrumb([{}]);
358
+ }
359
+ logout() {
360
+ this.auth.logout();
361
+ }
362
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: BlockedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
363
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: BlockedComponent, isStandalone: true, selector: "blocked", ngImport: i0, template: `
364
+ <main class="blocked">
365
+ <hm-state-page
366
+ kind="blocked"
367
+ [description]="text.blockedText"
368
+ [action]="text.blockedAction"
369
+ actionIcon="logout"
370
+ (actionTriggered)="logout()"
371
+ />
372
+ </main>
373
+ `, isInline: true, styles: [".blocked{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"], dependencies: [{ kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
374
+ }
375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: BlockedComponent, decorators: [{
376
+ type: Component,
377
+ args: [{ selector: 'blocked', imports: [StatePageComponent], template: `
378
+ <main class="blocked">
379
+ <hm-state-page
380
+ kind="blocked"
381
+ [description]="text.blockedText"
382
+ [action]="text.blockedAction"
383
+ actionIcon="logout"
384
+ (actionTriggered)="logout()"
385
+ />
386
+ </main>
387
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".blocked{display:flex;min-block-size:100dvh;flex-direction:column;background:var(--hm-surface)}\n"] }]
388
+ }], ctorParameters: () => [] });
389
+
390
+ var blocked_component = /*#__PURE__*/Object.freeze({
391
+ __proto__: null,
392
+ BlockedComponent: BlockedComponent
393
+ });
394
+
395
+ class LoadingPageComponent {
396
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoadingPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
397
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: LoadingPageComponent, isStandalone: true, selector: "loading-page", ngImport: i0, template: "<p>loading-page works!</p>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
398
+ }
399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: LoadingPageComponent, decorators: [{
400
+ type: Component,
401
+ args: [{ selector: 'loading-page', imports: [], changeDetection: ChangeDetectionStrategy.Eager, template: "<p>loading-page works!</p>\n" }]
402
+ }] });
403
+
404
+ /**
405
+ * Generated bundle index. Do not edit.
406
+ */
407
+
408
+ export { APP_ROUTES, BASE_COMPONENTS, BlockedComponent, CallbackComponent, LoadingPageComponent, LoggedOutComponent, LoginComponent, NoRightsComponent, PRIVATE_ROUTES, PUBLIC_ROUTES, provideShell };
409
+ //# sourceMappingURL=trismegisto-spine-shell.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trismegisto-spine-shell.mjs","sources":["../../../projects/ui/shell/src/tokens.ts","../../../projects/ui/shell/src/empty-route.component.ts","../../../projects/ui/shell/src/private.routes.ts","../../../projects/ui/shell/src/public/callback.component.ts","../../../projects/ui/shell/src/public/loggedout/loggedout.component.ts","../../../projects/ui/shell/src/public/loggedout/loggedout.component.html","../../../projects/ui/shell/src/public/login.component.ts","../../../projects/ui/shell/src/public.routes.ts","../../../projects/ui/shell/src/app.routes.ts","../../../projects/ui/shell/src/base-components.ts","../../../projects/ui/shell/src/provide-shell.ts","../../../projects/ui/shell/src/templates/access-recovery.ts","../../../projects/ui/shell/src/templates/no-rights/no-rights.component.ts","../../../projects/ui/shell/src/templates/no-rights/no-rights.component.html","../../../projects/ui/shell/src/templates/blocked/blocked.component.ts","../../../projects/ui/shell/src/templates/loading-page/loading-page.component.ts","../../../projects/ui/shell/src/templates/loading-page/loading-page.component.html","../../../projects/ui/shell/src/trismegisto-spine-shell.ts"],"sourcesContent":["// Movido para o pacote raiz (ver package-info.token.ts) — reexportado aqui para não quebrar\n// quem importa `APP_PACKAGE_INFO`/`PackageInfo` de '@trismegisto/spine/shell'.\nexport { APP_PACKAGE_INFO, type PackageInfo } from '@trismegisto/spine';\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n/**\n * Componente vazio pra rota `**` (ver `private.routes.ts`) — o Angular Router EXIGE\n * `component`/`loadComponent`/`redirectTo`/`children`/`loadChildren` em toda rota (`NG04014` se\n * nenhum for dado), mas quem desenha o conteúdo aqui é o `hm-workspace`\n * (`SpinePagePanelComponent`, resolvido por `resolveSpineRoute`, sem passar pelo `Router`), não um\n * `<router-outlet>`. Este componente só satisfaz a validação do Router — nunca renderiza nada de\n * visível (o `<router-outlet>` real que sobra em `LayoutComponent` fica escondido via `[hidden]`\n * sempre que a rota ativa não é `/no-permission`, a única com conteúdo de verdade).\n */\n@Component({\n selector: 'spine-empty-route',\n template: '',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class EmptyRouteComponent {}\n","import { Routes } from '@angular/router';\nimport { ViewGuard } from '@trismegisto/spine/routing';\nimport { EmptyRouteComponent } from './empty-route.component';\n\n/**\n * Quem desenha o conteúdo agora é o `hm-workspace` (ver `LayoutComponent`/\n * `layout/src/workspace/`), nunca um `<router-outlet>` aninhado — a árvore de 6 níveis\n * (header/navigation/menu/item/submenu/page) que existia aqui foi substituída por\n * `resolveSpineRoute`, chamada por painel. Estas rotas só precisam existir pro `Router` real\n * \"reconhecer\" a URL (deep link, F5, `router.navigateByUrl` do painel focado) e pro `ViewGuard`\n * confirmar que ela resolve contra a view atual antes do painel tentar renderizá-la — `component`\n * é só `EmptyRouteComponent` (o Angular exige um dos cinco em toda rota, `NG04014` senão; o\n * `<router-outlet>` que o recebe fica escondido, ver `LayoutComponent`).\n */\nexport const PRIVATE_ROUTES: Routes = [\n {\n path: 'no-permission',\n loadComponent: () => import('./templates/no-rights/no-rights.component').then(m => m.NoRightsComponent),\n },\n { path: '', pathMatch: 'full', redirectTo: 'home' },\n { path: '**', canActivate: [ViewGuard], component: EmptyRouteComponent },\n];\n","import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { StatePageComponent } from '@trismegisto/angular';\nimport { SPINE_MESSAGES } from '@trismegisto/spine';\n\n/** Chave do `@orfeu/angular` com a URL pedida antes do login (documentada no MIGRATION da lib). */\nconst RETURN_URL_KEY = 'orfeu_return_url';\n\n/**\n * Rota de retorno do Argos (`/callback?code&state` ou `?error`). Tudo passa pelo `handleCallback()` do\n * `@orfeu/angular`, que confere state e verifier, troca o code e navega para a URL pedida antes do login\n * (ou para a 1ª rota do `/view`).\n *\n * - `?error=login_required` (e afins) da reautorização silenciosa (`prompt=none`): o próprio\n * `handleCallback()` segue para o login interativo, mantendo a URL de retorno — a pessoa não fica parada aqui.\n * - Callback inválido (state/nonce divergente, `?error`, sem code): NUNCA desloga. Com uma sessão viva\n * (callback repetido, voltar do navegador), segue para a URL de retorno; sem sessão, mostra a página de\n * erro com \"Entrar novamente\".\n */\n@Component({\n selector: 'app-callback',\n imports: [StatePageComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (failed()) {\n <main class=\"callback\">\n <hm-state-page\n kind=\"error\"\n [heading]=\"text.callbackFailedHeading\"\n [description]=\"text.callbackFailedText\"\n [action]=\"text.signInAgain\"\n actionIcon=\"login\"\n (actionTriggered)=\"signIn()\"\n />\n </main>\n }\n `,\n styles: [`.callback { display: flex; min-block-size: 100dvh; flex-direction: column; background: var(--hm-surface); }`],\n})\nexport class CallbackComponent {\n protected readonly text = inject(SPINE_MESSAGES).session;\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly auth = inject(AuthorizationService);\n\n /** `true` quando o callback falhou e não há sessão para onde voltar. */\n protected readonly failed = signal(false);\n /** Promessa do tratamento em andamento (exposta para os testes aguardarem). */\n readonly done: Promise<void>;\n\n constructor() {\n this.done = this.handle();\n }\n\n private async handle(): Promise<void> {\n const q = this.route.snapshot.queryParamMap;\n const returnUrl = readReturnUrl();\n try {\n await this.auth.handleCallback({\n code: q.get('code') ?? undefined,\n state: q.get('state') ?? undefined,\n error: q.get('error') ?? undefined,\n error_description: q.get('error_description') ?? undefined,\n });\n } catch (e) {\n console.warn('[hermes-spine] callback de login recusado:', e);\n if (this.auth.authenticated) {\n // Sessão viva (de outra aba ou anterior): segue para onde a pessoa ia, sem tocar na sessão.\n await this.router.navigateByUrl(returnUrl ?? '/');\n return;\n }\n this.failed.set(true);\n }\n }\n\n protected signIn(): void {\n void this.auth.authorize(readReturnUrl() ?? undefined);\n }\n}\n\nfunction readReturnUrl(): string | null {\n try {\n const url = globalThis.sessionStorage?.getItem(RETURN_URL_KEY) ?? null;\n return url && url.startsWith('/') && !url.startsWith('//') ? url : null;\n } catch {\n return null;\n }\n}\n","import { Component, ChangeDetectionStrategy } from '@angular/core';\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { StatePageComponent } from '@trismegisto/angular';\n\n@Component({\n selector: 'loggedout',\n imports: [StatePageComponent],\n templateUrl: './loggedout.component.html',\n changeDetection: ChangeDetectionStrategy.Eager,\n styleUrl: './loggedout.component.scss'\n})\nexport class LoggedOutComponent {\n constructor(private authorizationService: AuthorizationService) {}\n goToLogin() { this.authorizationService.authorize(); }\n}\n","<!-- Tela pública (fora do layout): ocupa a janela inteira. Página pronta do hermes, tipo \"logged-out\". -->\n<main class=\"loggedout\">\n <hm-state-page kind=\"logged-out\" (actionTriggered)=\"goToLogin()\" />\n</main>\n","import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { AuthorizationService, ViewService } from '@orfeu/angular/core';\n\n@Component({\n selector: 'app-login',\n imports: [],\n changeDetection: ChangeDetectionStrategy.Eager,\n template: ``\n})\nexport class LoginComponent implements OnInit {\n constructor(\n private router: Router,\n private auth: AuthorizationService,\n private view: ViewService\n ) {}\n\n ngOnInit(): void { this.bootstrap(); }\n\n async bootstrap() {\n await this.auth.reauthorize();\n if (this.auth.authenticated) {\n const views = await this.view.update(this.auth.getToken());\n const firstRoute = this.findFirstNavigable(views?.routes || []);\n // Sem grupo nenhum no app (token sem crachá) vence \"sem rota\": ver ViewGuard.\n if (!this.auth.badges.length) this.router.navigate(['/blocked']);\n else this.router.navigate([firstRoute ?? '/no-permission']);\n }\n }\n\n /** Primeira rota navegável (DFS), atravessando grupos \"transparentes\" sem route_redirect. */\n private findFirstNavigable(routes: any[]): string | null {\n for (const r of routes || []) {\n if (!r) continue;\n if (r.route_redirect) return r.route_redirect;\n if (r.routes?.length) {\n const found = this.findFirstNavigable(r.routes);\n if (found) return found;\n }\n }\n return null;\n }\n}\n","import { Routes } from '@angular/router';\nimport { PrivateGuard } from '@orfeu/angular/core';\nimport { CallbackComponent } from './public/callback.component';\nimport { LoggedOutComponent } from './public/loggedout/loggedout.component';\nimport { LoginComponent } from './public/login.component';\n\nexport const PUBLIC_ROUTES: Routes = [\n { path: 'login', component: LoginComponent },\n { path: 'callback', component: CallbackComponent },\n { path: 'logoff', component: LoggedOutComponent },\n // Sem nenhum grupo vinculado ao app (ver `ViewGuard`): tela cheia, FORA do layout — sem\n // header nem sidebar, só a informação. Aqui (e não nas privadas) justamente pra não montar o\n // `LayoutComponent`; o `PrivateGuard` garante que só chega quem está autenticado.\n {\n path: 'blocked',\n canActivate: [PrivateGuard],\n loadComponent: () => import('./templates/blocked/blocked.component').then(m => m.BlockedComponent),\n },\n { path: '', redirectTo: 'login', pathMatch: 'full' },\n];\n","import { Routes } from '@angular/router';\nimport { PrivateGuard } from '@orfeu/angular/core';\nimport { LayoutComponent } from '@trismegisto/spine/layout';\nimport { PRIVATE_ROUTES } from './private.routes';\nimport { PUBLIC_ROUTES } from './public.routes';\n\nexport const APP_ROUTES: Routes = [\n ...PUBLIC_ROUTES,\n {\n path: '',\n component: LayoutComponent,\n canActivate: [PrivateGuard],\n canActivateChild: [PrivateGuard],\n children: PRIVATE_ROUTES,\n },\n { path: '**', redirectTo: '' },\n];\n","import { ComponentRoute } from '@trismegisto/spine/routing';\n\n/**\n * Componentes que o próprio shell traz, ligados pelo `router_id` (web.router) da árvore de rotas do argos.\n *\n * As telas do antigo módulo \"Sistema\" (Sobre › Recursos/Informações; Preferências › Geral,\n * Autenticação, Exibição, Notificações) saíram em 2026-09-29: viraram o painel de configurações\n * (`@trismegisto/spine/layout` › `SettingsPanelComponent`, menu do perfil ou Ctrl+,). Os router_ids delas\n * (d6a30f9c, 86b87583, 2d71fb9b, 48ebca20, 662a7a61, e7d9982b, bf8a9f69) não têm mais componente —\n * o módulo precisa sair da árvore de rotas no seed do argos.\n *\n * O Início (`HomeComponent`) mudou pra `@trismegisto/spine/auto-service` -- ver a entrada legada abaixo.\n */\nexport const BASE_COMPONENTS: ComponentRoute[] = [\n {\n // LEGADO: o Início agora vem do template Auto-Serviço (`provideAutoService`, casando por\n // source_template_router_id). Esta entrada só cobre o Início do Hefesto em banco cujo router\n // (b06c2784) ainda não aponta pro template -- remover quando todos os ambientes tiverem.\n id: 'b06c2784-eb29-4747-b118-53687c382cf7',\n load: async () => (await import('@trismegisto/spine/auto-service')).AUTO_SERVICE_SCREENS.home(),\n },\n];\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { COMPONENT_ROUTES, ComponentRoute, RouteIdInterceptor, componentRouterId } from '@trismegisto/spine/routing';\nimport { BASE_COMPONENTS } from './base-components';\nimport { APP_PACKAGE_INFO, PackageInfo } from './tokens';\n\nexport interface ShellOptions {\n appComponents?: ComponentRoute[];\n packageInfo?: PackageInfo;\n}\n\nexport function provideShell(options: ShellOptions = {}): EnvironmentProviders {\n const appComponents = options.appComponents ?? [];\n const baseIds = new Set(BASE_COMPONENTS.map(componentRouterId));\n const conflicts = appComponents.filter(c => componentRouterId(c) && baseIds.has(componentRouterId(c)));\n\n if (conflicts.length > 0) {\n throw new Error(\n `[hermes-spine] provideShell: router_ids em conflito com BASE_COMPONENTS: ${conflicts.map(componentRouterId).join(', ')}`\n );\n }\n\n // multi: true -- este provider é só UMA das fontes de COMPONENT_ROUTES (a do próprio\n // app + os componentes base do shell). Pacotes plugáveis (ex.: provideAutoService)\n // contribuem com os deles via outro provider do mesmo token, combinados no\n // ComponentDistributorService -- nunca use { provide: COMPONENT_ROUTES, useValue: ... }\n // sem multi: true em outro lugar, ou o Angular lança erro de provider inconsistente.\n return makeEnvironmentProviders([\n { provide: COMPONENT_ROUTES, useValue: [...BASE_COMPONENTS, ...appComponents], multi: true },\n { provide: HTTP_INTERCEPTORS, useClass: RouteIdInterceptor, multi: true },\n ...(options.packageInfo ? [{ provide: APP_PACKAGE_INFO, useValue: options.packageInfo }] : []),\n ]);\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { AuthorizationService, ViewService } from '@orfeu/angular/core';\nimport { Route, spineRoutesOf } from '@trismegisto/spine';\nimport { findFirstNavigable } from '@trismegisto/spine/routing';\n\n/**\n * As telas de acesso (`/blocked` e `/no-permission`) saem sozinhas quando a situação muda — no F5\n * (o token e a view são refeitos na inicialização) ou com a tela aberta (renovação do token, troca\n * de crachá): quem ganhou grupo/permissão não fica preso numa tela que já não vale.\n *\n * Mesma decisão do `ViewGuard`/login, na mesma ordem:\n * - sem crachá nenhum no app (token sem `badges`) → `/blocked`;\n * - com crachá, mas a view sem rota → `/no-permission`;\n * - com rota → a primeira navegável.\n *\n * Só redireciona quando o destino é OUTRO que a tela atual, e com `replaceUrl`: voltar no navegador\n * não devolve pra tela de bloqueio que já não se aplica.\n *\n * Chamar no construtor (contexto de injeção) da tela.\n */\nexport function watchAccessRecovery(current: '/blocked' | '/no-permission'): void {\n const router = inject(Router);\n const auth = inject(AuthorizationService);\n const viewService = inject(ViewService);\n\n const check = (view: { routes?: Route[] | null } | null | undefined): void => {\n // Sem sessão (ainda) não há o que decidir: quem cuida disso é o PrivateGuard/login.\n if (!auth.authenticated || !view) return;\n const target = !auth.badges.length\n ? '/blocked'\n : (findFirstNavigable(spineRoutesOf(view)) ?? '/no-permission');\n if (target !== current) void router.navigateByUrl(target, { replaceUrl: true });\n };\n\n // O valor atual primeiro (F5 com o token já renovado pelo initialize()) e depois cada atualização\n // da view — ela é sempre refeita depois do token (`view.update`), então o crachá lido aqui já é o novo.\n check(viewService.currentView as any);\n const sub = viewService.currentView$.subscribe((view: any) => check(view));\n inject(DestroyRef).onDestroy(() => sub.unsubscribe());\n}\n","import { Component, OnInit, ChangeDetectionStrategy, inject } from '@angular/core';\nimport { ViewService } from '@orfeu/angular/core';\nimport { StatePageComponent } from '@trismegisto/angular';\nimport { SPINE_MESSAGES } from '@trismegisto/spine';\nimport { watchAccessRecovery } from '../access-recovery';\n\n@Component({\n selector: 'no-rights',\n imports: [StatePageComponent],\n templateUrl: './no-rights.component.html',\n changeDetection: ChangeDetectionStrategy.Eager,\n styleUrl: './no-rights.component.scss'\n})\nexport class NoRightsComponent implements OnInit {\n protected readonly text = inject(SPINE_MESSAGES).access;\n\n constructor(private viewService: ViewService) {\n // F5 (ou token renovado) com rota liberada → sai daqui pra primeira rota; sem crachá → /blocked.\n watchAccessRecovery('/no-permission');\n }\n\n ngOnInit(): void {\n // /no-permission fica fora da árvore guardada pelo ViewGuard (não tem\n // canActivate), então logControl$/breadCrumb$ nunca são atualizados ao\n // chegar aqui — sem isso, sidebar e breadcrumb continuam mostrando o\n // menu/trilha da última rota válida por baixo da tela de sem-permissão.\n this.viewService.updateBreadcrumb([{}]);\n }\n}\n","<!-- Página pronta do hermes (`hm-state-page`, tipo \"no-rights\"). Sem botão: quem chega aqui não tem\n nenhuma página liberada, então \"ir para o início\" só voltaria pra cá. -->\n<hm-state-page\n kind=\"no-rights\"\n [description]=\"text.noRightsText\"\n action=\"\"\n/>\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { AuthorizationService, ViewService } from '@orfeu/angular/core';\nimport { StatePageComponent } from '@trismegisto/angular';\nimport { SPINE_MESSAGES } from '@trismegisto/spine';\nimport { watchAccessRecovery } from '../access-recovery';\n\n/**\n * \"Acesso bloqueado\" (`/blocked`): a pessoa entrou, mas não faz parte de nenhum grupo vinculado a\n * esta aplicação — o `ViewGuard` manda pra cá quando o token vem sem nenhum crachá (`badges`\n * vazio), mesmo que o app tenha rotas públicas.\n *\n * Diferente de `/no-permission` (tem grupo, mas nenhuma rota liberada). A única ação útil aqui é\n * sair — pra entrar com outra conta, ou depois que o administrador incluir a pessoa num grupo.\n */\n@Component({\n selector: 'blocked',\n imports: [StatePageComponent],\n template: `\n <main class=\"blocked\">\n <hm-state-page\n kind=\"blocked\"\n [description]=\"text.blockedText\"\n [action]=\"text.blockedAction\"\n actionIcon=\"logout\"\n (actionTriggered)=\"logout()\"\n />\n </main>\n `,\n // Tela cheia, fora do layout (rota pública com PrivateGuard): ocupa a janela, como o /logoff.\n styles: [`.blocked { display: flex; min-block-size: 100dvh; flex-direction: column; background: var(--hm-surface); }`],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class BlockedComponent implements OnInit {\n protected readonly text = inject(SPINE_MESSAGES).access;\n private readonly auth = inject(AuthorizationService);\n private readonly viewService = inject(ViewService);\n\n constructor() {\n // F5 (ou token renovado) já com grupo no app → sai daqui pra primeira rota (ou /no-permission).\n watchAccessRecovery('/blocked');\n }\n\n ngOnInit(): void {\n // Zera a trilha da última rota válida (mesmo motivo do NoRightsComponent), pra quem voltar ao\n // layout depois não herdar o breadcrumb de antes do bloqueio.\n this.viewService.updateBreadcrumb([{}]);\n }\n\n protected logout(): void {\n this.auth.logout();\n }\n}\n","import { Component, ChangeDetectionStrategy } from '@angular/core';\n\n@Component({\n selector: 'loading-page',\n imports: [],\n templateUrl: './loading-page.component.html',\n changeDetection: ChangeDetectionStrategy.Eager,\n styleUrl: './loading-page.component.scss'\n})\nexport class LoadingPageComponent {}\n","<p>loading-page works!</p>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, ViewContainerRef, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { HermesLoadingState, HERMES_MESSAGES, DrawerComponent, ButtonComponent } from '@trismegisto/angular';
4
+ import { BehaviorSubject, Subject } from 'rxjs';
5
+ import { take } from 'rxjs/operators';
6
+ import * as i2 from '@angular/common';
7
+ import { CommonModule } from '@angular/common';
8
+
9
+ class SidePanelService {
10
+ constructor() {
11
+ this._visible = new BehaviorSubject(false);
12
+ this.visible$ = this._visible.asObservable();
13
+ this._state = new BehaviorSubject(HermesLoadingState.DEFAULT);
14
+ this.state$ = this._state.asObservable();
15
+ this._config = null;
16
+ this._result$ = null;
17
+ }
18
+ get config() {
19
+ return this._config;
20
+ }
21
+ open(config) {
22
+ // Abrir outro antes de responder o anterior cancela o anterior: quem o abriu recebe `null` (como no
23
+ // `close`) e o observable completa, em vez de ficar pendurado para sempre.
24
+ this._result$?.next(null);
25
+ this._result$?.complete();
26
+ this._config = config;
27
+ this._state.next(HermesLoadingState.DEFAULT);
28
+ this._result$ = new Subject();
29
+ this._visible.next(true);
30
+ return this._result$.asObservable().pipe(take(1));
31
+ }
32
+ confirm(result) {
33
+ this._result$?.next(result);
34
+ this._result$?.complete();
35
+ this.dismiss();
36
+ }
37
+ close() {
38
+ this._result$?.next(null);
39
+ this._result$?.complete();
40
+ this.dismiss();
41
+ }
42
+ setState(state) {
43
+ this._state.next(state);
44
+ }
45
+ dismiss() {
46
+ this._visible.next(false);
47
+ this._config = null;
48
+ this._result$ = null;
49
+ this._state.next(HermesLoadingState.DEFAULT);
50
+ }
51
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SidePanelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
52
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SidePanelService, providedIn: 'root' }); }
53
+ }
54
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SidePanelService, decorators: [{
55
+ type: Injectable,
56
+ args: [{ providedIn: 'root' }]
57
+ }] });
58
+
59
+ /** `SidePanelConfig.size` manteve os valores do spine antigo (sm/md/lg/xl/full) por
60
+ * compatibilidade de API; o `hm-drawer` novo só tem 3 tamanhos. */
61
+ function toHermesSize(size) {
62
+ switch (size) {
63
+ case 'sm': return 'small';
64
+ case 'lg':
65
+ case 'xl':
66
+ case 'full': return 'large';
67
+ default: return 'medium';
68
+ }
69
+ }
70
+ class SidePanelComponent {
71
+ constructor(sidePanelService, cdr) {
72
+ this.sidePanelService = sidePanelService;
73
+ this.cdr = cdr;
74
+ /** Rótulos dos botões padrão, do catálogo do Hermes (pt-BR/en/es). */
75
+ this.dialogText = inject(HERMES_MESSAGES).dialog;
76
+ this.visible = false;
77
+ this.config = null;
78
+ this.state = HermesLoadingState.DEFAULT;
79
+ this.HermesLoadingState = HermesLoadingState;
80
+ this.toHermesSize = toHermesSize;
81
+ this.contentRef = null;
82
+ }
83
+ ngOnInit() {
84
+ this.sidePanelService.visible$.subscribe((visible) => {
85
+ this.visible = visible;
86
+ this.config = this.sidePanelService.config;
87
+ if (visible) {
88
+ this.loadComponent();
89
+ }
90
+ else {
91
+ this.content?.clear();
92
+ this.contentRef = null;
93
+ }
94
+ this.cdr.markForCheck();
95
+ });
96
+ this.sidePanelService.state$.subscribe((state) => {
97
+ this.state = state;
98
+ this.cdr.markForCheck();
99
+ });
100
+ }
101
+ get canConfirm() {
102
+ const instance = this.contentRef?.instance;
103
+ return !instance?.isValid || instance.isValid();
104
+ }
105
+ loadComponent() {
106
+ this.content.clear();
107
+ if (this.config?.component) {
108
+ this.contentRef = this.content.createComponent(this.config.component);
109
+ if (this.config.data !== undefined) {
110
+ this.contentRef.setInput('data', this.config.data);
111
+ }
112
+ }
113
+ }
114
+ confirm() {
115
+ if (!this.canConfirm)
116
+ return;
117
+ const result = this.contentRef?.instance?.getResult ? this.contentRef.instance.getResult() : true;
118
+ this.sidePanelService.confirm(result);
119
+ }
120
+ dismiss() {
121
+ this.sidePanelService.close();
122
+ }
123
+ onLoadingStateChange(state) {
124
+ this.sidePanelService.setState(state);
125
+ }
126
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SidePanelComponent, deps: [{ token: SidePanelService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
127
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: SidePanelComponent, isStandalone: true, selector: "spine-side-panel", viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<hm-drawer\n [open]=\"visible\"\n [heading]=\"config?.title || ''\"\n [size]=\"toHermesSize(config?.size)\"\n [closable]=\"config?.closable ?? true\"\n (closed)=\"dismiss()\"\n>\n <ng-container #content />\n <div *ngIf=\"config?.text && !config?.component\">{{ config?.text }}</div>\n\n <ng-container footer *ngIf=\"config?.showActions !== false\">\n <hm-button emphasis=\"medium\" (clicked)=\"dismiss()\">{{ dialogText.cancel }}</hm-button>\n <hm-button\n intent=\"success\"\n [disabled]=\"!canConfirm\"\n [loadingState]=\"state\"\n (loadingStateChange)=\"onLoadingStateChange($event)\"\n (clicked)=\"confirm()\"\n >{{ dialogText.confirm }}</hm-button>\n </ng-container>\n</hm-drawer>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DrawerComponent, selector: "hm-drawer", inputs: ["open", "heading", "size", "position", "pinned", "closeLabel", "closable", "beforeClose"], outputs: ["openChange", "closed"] }, { kind: "component", type: ButtonComponent, selector: "hm-button", inputs: ["emphasis", "intent", "size", "type", "icon", "iconDirection", "iconEnd", "disabled", "loading", "busy", "loadingState", "block", "link", "newTab", "caret", "inMenu", "toggle", "pressed"], outputs: ["loadingStateChange", "pressedChange", "clicked"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
128
+ }
129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SidePanelComponent, decorators: [{
130
+ type: Component,
131
+ args: [{ selector: 'spine-side-panel', imports: [CommonModule, DrawerComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-drawer\n [open]=\"visible\"\n [heading]=\"config?.title || ''\"\n [size]=\"toHermesSize(config?.size)\"\n [closable]=\"config?.closable ?? true\"\n (closed)=\"dismiss()\"\n>\n <ng-container #content />\n <div *ngIf=\"config?.text && !config?.component\">{{ config?.text }}</div>\n\n <ng-container footer *ngIf=\"config?.showActions !== false\">\n <hm-button emphasis=\"medium\" (clicked)=\"dismiss()\">{{ dialogText.cancel }}</hm-button>\n <hm-button\n intent=\"success\"\n [disabled]=\"!canConfirm\"\n [loadingState]=\"state\"\n (loadingStateChange)=\"onLoadingStateChange($event)\"\n (clicked)=\"confirm()\"\n >{{ dialogText.confirm }}</hm-button>\n </ng-container>\n</hm-drawer>\n" }]
132
+ }], ctorParameters: () => [{ type: SidePanelService }, { type: i0.ChangeDetectorRef }], propDecorators: { content: [{
133
+ type: ViewChild,
134
+ args: ['content', { read: ViewContainerRef }]
135
+ }] } });
136
+
137
+ /**
138
+ * Generated bundle index. Do not edit.
139
+ */
140
+
141
+ export { SidePanelComponent, SidePanelService };
142
+ //# sourceMappingURL=trismegisto-spine-side-panel.mjs.map