@trismegisto/spine 3.3.0 → 3.3.1

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 (92) hide show
  1. package/README.md +19 -11
  2. package/fesm2022/trismegisto-spine-audit.mjs +16 -12
  3. package/fesm2022/trismegisto-spine-audit.mjs.map +1 -1
  4. package/fesm2022/{trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs → trismegisto-spine-auto-service-auto-service-audit.component-D8HUpZtA.mjs} +4 -4
  5. package/fesm2022/{trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs.map → trismegisto-spine-auto-service-auto-service-audit.component-D8HUpZtA.mjs.map} +1 -1
  6. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-NawbfdLW.mjs +65 -0
  7. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-NawbfdLW.mjs.map +1 -0
  8. package/fesm2022/{trismegisto-spine-auto-service-auto-service-client.component-IATeedbr.mjs → trismegisto-spine-auto-service-auto-service-client.component-BAfeLyTB.mjs} +27 -19
  9. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BAfeLyTB.mjs.map +1 -0
  10. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-BYjIQ9ID.mjs +635 -0
  11. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-BYjIQ9ID.mjs.map +1 -0
  12. package/fesm2022/{trismegisto-spine-auto-service-auto-service-login-attempts.component-CRvxfSWD.mjs → trismegisto-spine-auto-service-auto-service-login-attempts.component-DoyhkSYc.mjs} +4 -4
  13. package/fesm2022/{trismegisto-spine-auto-service-auto-service-login-attempts.component-CRvxfSWD.mjs.map → trismegisto-spine-auto-service-auto-service-login-attempts.component-DoyhkSYc.mjs.map} +1 -1
  14. package/fesm2022/trismegisto-spine-auto-service-auto-service-news-page.component-CBemH4hr.mjs +432 -0
  15. package/fesm2022/trismegisto-spine-auto-service-auto-service-news-page.component-CBemH4hr.mjs.map +1 -0
  16. package/fesm2022/trismegisto-spine-auto-service-auto-service-ratings-page.component-C_THGTkw.mjs +769 -0
  17. package/fesm2022/trismegisto-spine-auto-service-auto-service-ratings-page.component-C_THGTkw.mjs.map +1 -0
  18. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs +2123 -0
  19. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs.map +1 -0
  20. package/fesm2022/{trismegisto-spine-auto-service-auto-service.component-DGrs_Jvw.mjs → trismegisto-spine-auto-service-auto-service.component-QsIQ61w2.mjs} +31 -23
  21. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-QsIQ61w2.mjs.map +1 -0
  22. package/fesm2022/{trismegisto-spine-auto-service-client.usage-C_2zBCRN.mjs → trismegisto-spine-auto-service-client.usage-CJxn9Ysz.mjs} +5 -3
  23. package/fesm2022/trismegisto-spine-auto-service-client.usage-CJxn9Ysz.mjs.map +1 -0
  24. package/fesm2022/{trismegisto-spine-auto-service-groups.technical-9aPPulhy.mjs → trismegisto-spine-auto-service-groups.technical-_jQrg1Qh.mjs} +7 -5
  25. package/fesm2022/trismegisto-spine-auto-service-groups.technical-_jQrg1Qh.mjs.map +1 -0
  26. package/fesm2022/{trismegisto-spine-auto-service-groups.usage-CYh61LFL.mjs → trismegisto-spine-auto-service-groups.usage-OvWjNeeT.mjs} +7 -6
  27. package/fesm2022/{trismegisto-spine-auto-service-groups.usage-CYh61LFL.mjs.map → trismegisto-spine-auto-service-groups.usage-OvWjNeeT.mjs.map} +1 -1
  28. package/fesm2022/trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs +315 -0
  29. package/fesm2022/trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs.map +1 -0
  30. package/fesm2022/trismegisto-spine-auto-service-home.technical-Ce7oYRdg.mjs +46 -0
  31. package/fesm2022/trismegisto-spine-auto-service-home.technical-Ce7oYRdg.mjs.map +1 -0
  32. package/fesm2022/trismegisto-spine-auto-service-home.usage-D9R_ZMuU.mjs +48 -0
  33. package/fesm2022/trismegisto-spine-auto-service-home.usage-D9R_ZMuU.mjs.map +1 -0
  34. package/fesm2022/trismegisto-spine-auto-service-news.technical-DV9UpobG.mjs +38 -0
  35. package/fesm2022/trismegisto-spine-auto-service-news.technical-DV9UpobG.mjs.map +1 -0
  36. package/fesm2022/trismegisto-spine-auto-service-news.usage-CeuZnG0V.mjs +48 -0
  37. package/fesm2022/trismegisto-spine-auto-service-news.usage-CeuZnG0V.mjs.map +1 -0
  38. package/fesm2022/trismegisto-spine-auto-service-ratings.technical-QIVj6HBU.mjs +52 -0
  39. package/fesm2022/trismegisto-spine-auto-service-ratings.technical-QIVj6HBU.mjs.map +1 -0
  40. package/fesm2022/trismegisto-spine-auto-service-ratings.usage-BkteY8lz.mjs +45 -0
  41. package/fesm2022/trismegisto-spine-auto-service-ratings.usage-BkteY8lz.mjs.map +1 -0
  42. package/fesm2022/trismegisto-spine-auto-service-suggestions.technical-BtUK6sKD.mjs +69 -0
  43. package/fesm2022/trismegisto-spine-auto-service-suggestions.technical-BtUK6sKD.mjs.map +1 -0
  44. package/fesm2022/trismegisto-spine-auto-service-suggestions.usage-BwO9Hjsx.mjs +72 -0
  45. package/fesm2022/trismegisto-spine-auto-service-suggestions.usage-BwO9Hjsx.mjs.map +1 -0
  46. package/fesm2022/trismegisto-spine-auto-service.mjs +49 -19
  47. package/fesm2022/trismegisto-spine-auto-service.mjs.map +1 -1
  48. package/fesm2022/trismegisto-spine-graphql.mjs +11 -2
  49. package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -1
  50. package/fesm2022/trismegisto-spine-layout.mjs +3160 -1279
  51. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -1
  52. package/fesm2022/trismegisto-spine-modal.mjs +7 -5
  53. package/fesm2022/trismegisto-spine-modal.mjs.map +1 -1
  54. package/fesm2022/trismegisto-spine-routing.mjs +12 -20
  55. package/fesm2022/trismegisto-spine-routing.mjs.map +1 -1
  56. package/fesm2022/trismegisto-spine-shell.mjs +15 -39
  57. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -1
  58. package/fesm2022/trismegisto-spine-side-panel.mjs +7 -5
  59. package/fesm2022/trismegisto-spine-side-panel.mjs.map +1 -1
  60. package/fesm2022/trismegisto-spine.mjs +1969 -279
  61. package/fesm2022/trismegisto-spine.mjs.map +1 -1
  62. package/package.json +6 -6
  63. package/types/trismegisto-spine-audit.d.ts +2 -12
  64. package/types/trismegisto-spine-audit.d.ts.map +1 -1
  65. package/types/trismegisto-spine-auto-service.d.ts +22 -5
  66. package/types/trismegisto-spine-auto-service.d.ts.map +1 -1
  67. package/types/trismegisto-spine-layout.d.ts +1086 -283
  68. package/types/trismegisto-spine-layout.d.ts.map +1 -1
  69. package/types/trismegisto-spine-modal.d.ts +1 -0
  70. package/types/trismegisto-spine-modal.d.ts.map +1 -1
  71. package/types/trismegisto-spine-routing.d.ts +3 -12
  72. package/types/trismegisto-spine-routing.d.ts.map +1 -1
  73. package/types/trismegisto-spine-shell.d.ts +2 -15
  74. package/types/trismegisto-spine-shell.d.ts.map +1 -1
  75. package/types/trismegisto-spine-side-panel.d.ts +1 -0
  76. package/types/trismegisto-spine-side-panel.d.ts.map +1 -1
  77. package/types/trismegisto-spine.d.ts +739 -165
  78. package/types/trismegisto-spine.d.ts.map +1 -1
  79. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs +0 -65
  80. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs.map +0 -1
  81. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-IATeedbr.mjs.map +0 -1
  82. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-D6L0gTmd.mjs +0 -605
  83. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-D6L0gTmd.mjs.map +0 -1
  84. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-DGrs_Jvw.mjs.map +0 -1
  85. package/fesm2022/trismegisto-spine-auto-service-client.usage-C_2zBCRN.mjs.map +0 -1
  86. package/fesm2022/trismegisto-spine-auto-service-groups.technical-9aPPulhy.mjs.map +0 -1
  87. package/fesm2022/trismegisto-spine-auto-service-home.component-5_aji1hf.mjs +0 -239
  88. package/fesm2022/trismegisto-spine-auto-service-home.component-5_aji1hf.mjs.map +0 -1
  89. package/fesm2022/trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs +0 -35
  90. package/fesm2022/trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs.map +0 -1
  91. package/fesm2022/trismegisto-spine-auto-service-home.usage-DWYGtngX.mjs +0 -43
  92. package/fesm2022/trismegisto-spine-auto-service-home.usage-DWYGtngX.mjs.map +0 -1
@@ -1,239 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { Injectable, inject, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { NgTemplateOutlet } from '@angular/common';
4
- import { toSignal } from '@angular/core/rxjs-interop';
5
- import { Router } from '@angular/router';
6
- import { ViewService } from '@orfeu/angular/core';
7
- import { DataGridComponent, DataGridCellDirective, IconButtonComponent, IconComponent, StatePageComponent } from '@trismegisto/angular';
8
- import { pluralMessage, formatMessage } from '@trismegisto/primitives';
9
- import { spineRoutesOf, SpineQuickAccessService, SPINE_MESSAGES } from '@trismegisto/spine';
10
- import { SpineDocsService, SpineSettingsService } from '@trismegisto/spine/layout';
11
- import { map } from 'rxjs';
12
- import { AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID } from './trismegisto-spine-auto-service.mjs';
13
-
14
- // Above this many tiles a grid stops being scannable at a glance.
15
- const MAX_TILES = 12;
16
- const ADMIN_TEMPLATES = new Set([
17
- AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID,
18
- AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID,
19
- AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,
20
- AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,
21
- AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID,
22
- ].map((id) => id.toLowerCase()));
23
- const HOME_TEMPLATE = AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID.toLowerCase();
24
- function childrenOf(node) {
25
- return (node.routes ?? []).filter((child) => child != null);
26
- }
27
- function labelOf(node) {
28
- return (node.route_display_name ?? node.route_name ?? '').trim();
29
- }
30
- function identityOf(node) {
31
- return node.route_redirect || `${node.route_type ?? 'node'}:${node.routed_id}`;
32
- }
33
- function templateOf(node) {
34
- return (node.source_template_router_id ?? '').toLowerCase();
35
- }
36
- function isPage(node) {
37
- return !!node.route_redirect && (node.route_type === 'page' || childrenOf(node).length === 0);
38
- }
39
- function isHome(node) {
40
- return templateOf(node) === HOME_TEMPLATE || (isPage(node) && node.route_path === 'home');
41
- }
42
- function modules(tree) {
43
- return tree.filter((node) => node != null && !isHome(node));
44
- }
45
- function systemAreas(tree) {
46
- return tree.filter((node) => node != null && isHome(node));
47
- }
48
- function destinations(tree, trail = []) {
49
- const found = [];
50
- const walk = (nodes, path) => {
51
- for (const node of nodes) {
52
- if (node == null)
53
- continue;
54
- if (isPage(node)) {
55
- found.push({ id: identityOf(node), label: labelOf(node), icon: node.route_icon ?? null, redirect: node.route_redirect, trail: path });
56
- }
57
- const kids = childrenOf(node);
58
- if (kids.length)
59
- walk(kids, [...path, labelOf(node)]);
60
- }
61
- };
62
- walk(tree, trail);
63
- return found;
64
- }
65
- function trailFor(tree, redirect) {
66
- return destinations(tree).find((d) => d.redirect === redirect)?.trail ?? null;
67
- }
68
- function isPrivileged(node) {
69
- return ADMIN_TEMPLATES.has(templateOf(node)) || childrenOf(node).some(isPrivileged);
70
- }
71
- function navigableChildren(node) {
72
- return childrenOf(node).filter((child) => isPage(child) || destinations([child]).length > 0);
73
- }
74
- /** Replaces each candidate by its navigable children; `null` when nobody has any. */
75
- function descend(level) {
76
- let changed = false;
77
- const next = level.flatMap((item) => {
78
- const kids = navigableChildren(item.node);
79
- if (!kids.length)
80
- return [item];
81
- changed = true;
82
- const trail = [...item.trail, labelOf(item.node)];
83
- return kids.map((node) => ({ node, trail, privileged: item.privileged }));
84
- });
85
- return changed ? next : null;
86
- }
87
- function toShortcut({ node, trail, privileged }) {
88
- const below = destinations([node]);
89
- return {
90
- id: identityOf(node),
91
- label: labelOf(node),
92
- icon: node.route_icon ?? null,
93
- redirect: node.route_redirect || below[0]?.redirect || '',
94
- trail,
95
- screens: below.length - (isPage(node) ? 1 : 0),
96
- privileged,
97
- };
98
- }
99
- /**
100
- * Picks the shallowest level of the tree where there is a real choice to make: a single item is
101
- * skipped over, a pair is opened up while the result still fits the grid, three or more stay put.
102
- */
103
- function entryShortcuts(tree) {
104
- let level = modules(tree).map((node) => ({ node, trail: [], privileged: isPrivileged(node) }));
105
- while (level.length > 0 && level.length < 3) {
106
- const next = descend(level);
107
- if (!next)
108
- break;
109
- if (level.length === 2 && next.length > MAX_TILES)
110
- break;
111
- level = next;
112
- }
113
- return level.map(toShortcut);
114
- }
115
-
116
- /** Remembers, for the whole app load, that the home screen already jumped to the only screen. */
117
- class HomeAutoRedirect {
118
- constructor() {
119
- this.done = false;
120
- }
121
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeAutoRedirect, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
122
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeAutoRedirect, providedIn: 'root' }); }
123
- }
124
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeAutoRedirect, decorators: [{
125
- type: Injectable,
126
- args: [{ providedIn: 'root' }]
127
- }] });
128
- const TRAIL_SEPARATOR = ' › ';
129
- const RECENT_ROWS = 4;
130
- let instances = 0;
131
- function cleanTree(view) {
132
- return spineRoutesOf(view).filter((node) => node != null);
133
- }
134
- class HomeComponent {
135
- constructor() {
136
- this.router = inject(Router);
137
- this.quickAccess = inject(SpineQuickAccessService);
138
- this.docs = inject(SpineDocsService);
139
- this.settings = inject(SpineSettingsService);
140
- this.autoRedirect = inject(HomeAutoRedirect);
141
- this.messages = inject(SPINE_MESSAGES);
142
- this.t = this.messages.home;
143
- this.uid = `home-${++instances}`;
144
- this.view = inject(ViewService);
145
- this.tree = toSignal(this.view.currentView$.pipe(map(cleanTree)), {
146
- initialValue: cleanTree(this.view.currentView),
147
- });
148
- this.workDestinations = computed(() => destinations(modules(this.tree())), ...(ngDevMode ? [{ debugName: "workDestinations" }] : /* istanbul ignore next */ []));
149
- this.noAccess = computed(() => this.tree().length > 0 && modules(this.tree()).length === 0, ...(ngDevMode ? [{ debugName: "noAccess" }] : /* istanbul ignore next */ []));
150
- this.areas = computed(() => systemAreas(this.tree()), ...(ngDevMode ? [{ debugName: "areas" }] : /* istanbul ignore next */ []));
151
- this.shortcuts = computed(() => entryShortcuts(this.tree()), ...(ngDevMode ? [{ debugName: "shortcuts" }] : /* istanbul ignore next */ []));
152
- this.workTiles = computed(() => this.shortcuts().filter((s) => !s.privileged), ...(ngDevMode ? [{ debugName: "workTiles" }] : /* istanbul ignore next */ []));
153
- this.adminTiles = computed(() => this.shortcuts().filter((s) => s.privileged), ...(ngDevMode ? [{ debugName: "adminTiles" }] : /* istanbul ignore next */ []));
154
- this.descended = computed(() => this.shortcuts().some((s) => s.trail.length > 0), ...(ngDevMode ? [{ debugName: "descended" }] : /* istanbul ignore next */ []));
155
- this.sideBySide = computed(() => this.shortcuts().length <= 2, ...(ngDevMode ? [{ debugName: "sideBySide" }] : /* istanbul ignore next */ []));
156
- /** Every tile already opens a final screen, so recents/favorites would not save a single click. */
157
- this.everythingInView = computed(() => {
158
- const list = this.shortcuts();
159
- return list.length > 0 && list.every((s) => s.screens === 0);
160
- }, ...(ngDevMode ? [{ debugName: "everythingInView" }] : /* istanbul ignore next */ []));
161
- this.favorites = computed(() => (this.everythingInView() ? [] : this.quickAccess.favorites()), ...(ngDevMode ? [{ debugName: "favorites" }] : /* istanbul ignore next */ []));
162
- this.recentRows = computed(() => {
163
- if (this.everythingInView())
164
- return [];
165
- return this.quickAccess
166
- .recents()
167
- .slice(0, RECENT_ROWS)
168
- .map((item) => ({ ...item, where: this.whereOf(item) }));
169
- }, ...(ngDevMode ? [{ debugName: "recentRows" }] : /* istanbul ignore next */ []));
170
- this.recentColumns = [
171
- { key: 'displayName', title: this.t.colScreen, value: (row) => row.displayName },
172
- { key: 'where', title: this.t.colWhere, value: (row) => row.where },
173
- {
174
- key: 'favorite',
175
- title: this.t.colFavorite,
176
- value: () => '',
177
- filterable: false,
178
- sortable: false,
179
- searchable: false,
180
- initialWidth: '5.5rem',
181
- },
182
- ];
183
- this.rowId = (row) => row.id;
184
- effect(() => {
185
- const only = this.workDestinations();
186
- if (only.length !== 1 || this.autoRedirect.done)
187
- return;
188
- this.autoRedirect.done = true;
189
- void this.router.navigateByUrl(only[0].redirect, { replaceUrl: true });
190
- });
191
- }
192
- caption(tile) {
193
- if (tile.screens > 0)
194
- return pluralMessage(this.t.screenCount, tile.screens, this.messages.meta.locale);
195
- return tile.trail.join(TRAIL_SEPARATOR);
196
- }
197
- whereOf(item) {
198
- const trail = item.trail ?? trailFor(this.tree(), item.redirect);
199
- return trail?.join(TRAIL_SEPARATOR) || this.t.noModule;
200
- }
201
- row(value) {
202
- return value;
203
- }
204
- isFavorite(id) {
205
- return this.quickAccess.isFavorite(id);
206
- }
207
- favoriteLabel(row) {
208
- const template = this.isFavorite(row.id) ? this.t.unfavorite : this.t.favorite;
209
- return formatMessage(template, { name: row.displayName });
210
- }
211
- toggleFavorite(row) {
212
- this.quickAccess.toggleFavorite({
213
- id: row.id,
214
- icon: row.icon,
215
- displayName: row.displayName,
216
- redirect: row.redirect,
217
- trail: row.trail ?? trailFor(this.tree(), row.redirect) ?? [],
218
- });
219
- }
220
- go(redirect) {
221
- if (redirect)
222
- void this.router.navigateByUrl(redirect);
223
- }
224
- openSettings() {
225
- this.settings.open();
226
- }
227
- openDocs() {
228
- this.docs.openIndex();
229
- }
230
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
231
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HomeComponent, isStandalone: true, selector: "home", ngImport: i0, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"hub\" [class.hub--columns]=\"sideBySide()\">\n @if (workTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n\n @if (adminTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n\n @if (recentRows().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <h2 class=\"block__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n <hm-data-grid\n [caption]=\"t.recentCaption\"\n [columns]=\"recentColumns\"\n [rows]=\"recentRows()\"\n [rowId]=\"rowId\"\n [filterable]=\"false\"\n [paginated]=\"false\"\n >\n <ng-template hmCell=\"displayName\" let-value>\n @let item = row(value);\n <button type=\"button\" class=\"link\" (click)=\"go(item.redirect)\">\n <hm-icon [shape]=\"item.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ item.displayName }}</span>\n </button>\n </ng-template>\n <ng-template hmCell=\"favorite\" let-value>\n @let item = row(value);\n <hm-icon-button\n emphasis=\"subtle\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n </ng-template>\n </hm-data-grid>\n </section>\n }\n\n @if (favorites().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n <ul class=\"chips\">\n @for (fav of favorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"chip\" [title]=\"whereOf(fav)\" (click)=\"go(fav.redirect)\">\n <hm-icon [shape]=\"fav.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ fav.displayName }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-nav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-nav'\">{{ t.navigate }}</h2>\n <ul class=\"chips\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"go(area.route_redirect)\">\n <hm-icon [shape]=\"area.route_icon || 'home'\" size=\"sm\" />\n <span>{{ area.route_display_name }}</span>\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openSettings()\">\n <hm-icon shape=\"cog\" size=\"sm\" />\n <span>{{ t.settings }}</span>\n </button>\n </li>\n </ul>\n </section>\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-tools'\">\n <h2 class=\"block__title\" [id]=\"uid + '-tools'\">{{ t.tools }}</h2>\n <ul class=\"chips\">\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openDocs()\">\n <hm-icon shape=\"doc-list\" size=\"sm\" />\n <span>{{ t.systemDocs }}</span>\n </button>\n </li>\n </ul>\n </section>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}.hub{display:flex;flex-direction:column;gap:var(--hm-space-xl);padding:var(--hm-space-lg);min-inline-size:0}.hub--columns{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,20rem),1fr));align-items:start}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold)}ul{margin:0;padding:0;list-style:none}.link,.chip,.tile{display:inline-flex;align-items:center;gap:var(--hm-space-xs);border:1px solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer}.link:hover,.chip:hover,.tile:hover{background:var(--hm-hover)}.link:focus-visible,.chip:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.link,.chip,.tile{border-color:ButtonText}.link:focus-visible,.chip:focus-visible,.tile:focus-visible{outline-color:Highlight}}.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-medium);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-xs)}.chip{padding:var(--hm-space-xs) var(--hm-space-sm);border-color:var(--hm-divider);background:var(--hm-surface)}.link{padding:var(--hm-space-nano) var(--hm-space-xs);margin-inline-start:calc(-1 * var(--hm-space-xs));color:var(--hm-accent)}.heart--on{color:var(--hm-danger)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DataGridComponent, selector: "hm-data-grid", inputs: ["columns", "rows", "rowId", "caption", "rowActions", "loading", "error", "emptyMessage", "noResultsMessage", "filterable", "paginated", "pageState", "pagination", "totalItems", "sort", "selectable", "selectionMode", "selection", "rowSelectable", "rowSelectableReason", "rowDetailDisabled", "rowDetailHidden", "virtual", "rowHeight", "pinnedColumns", "columnState", "pageSizes", "fillHeight", "maxHeight", "bordered", "rowState", "rowClickable", "remoteSearch", "remoteSort", "itemsLabel", "pageSizeLabel", "exportable", "exportFileName", "groupBy", "aggregates", "aggregateFormatter", "persistKey", "persistStorage", "advancedFilter", "filterQuery", "columnManager", "columnOrder", "searchTerm"], outputs: ["pageStateChange", "sortChange", "selectionChange", "pinnedColumnsChange", "columnStateChange", "actionTriggered", "detailToggled", "rowClicked", "clearFiltersRequested", "filteredChange", "searchTermChanged", "groupByChange", "filterQueryChange", "columnOrderChange", "searchTermChange", "detailPaneToggled"] }, { kind: "directive", type: DataGridCellDirective, selector: "ng-template[hmCell]", inputs: ["hmCell"] }, { kind: "component", type: IconButtonComponent, selector: "hm-icon-button", inputs: ["label", "icon", "solid", "iconDirection", "emphasis", "intent", "size", "disabled", "toggle", "pressed", "keyShortcuts"], outputs: ["pressedChange", "clicked"] }, { kind: "component", type: IconComponent, selector: "hm-icon", inputs: ["shape", "direction", "size", "solid", "badge", "status", "flip", "inverse", "label"] }, { kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
232
- }
233
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeComponent, decorators: [{
234
- type: Component,
235
- args: [{ selector: 'home', imports: [NgTemplateOutlet, DataGridComponent, DataGridCellDirective, IconButtonComponent, IconComponent, StatePageComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"hub\" [class.hub--columns]=\"sideBySide()\">\n @if (workTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n\n @if (adminTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n\n @if (recentRows().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <h2 class=\"block__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n <hm-data-grid\n [caption]=\"t.recentCaption\"\n [columns]=\"recentColumns\"\n [rows]=\"recentRows()\"\n [rowId]=\"rowId\"\n [filterable]=\"false\"\n [paginated]=\"false\"\n >\n <ng-template hmCell=\"displayName\" let-value>\n @let item = row(value);\n <button type=\"button\" class=\"link\" (click)=\"go(item.redirect)\">\n <hm-icon [shape]=\"item.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ item.displayName }}</span>\n </button>\n </ng-template>\n <ng-template hmCell=\"favorite\" let-value>\n @let item = row(value);\n <hm-icon-button\n emphasis=\"subtle\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n </ng-template>\n </hm-data-grid>\n </section>\n }\n\n @if (favorites().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n <ul class=\"chips\">\n @for (fav of favorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"chip\" [title]=\"whereOf(fav)\" (click)=\"go(fav.redirect)\">\n <hm-icon [shape]=\"fav.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ fav.displayName }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-nav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-nav'\">{{ t.navigate }}</h2>\n <ul class=\"chips\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"go(area.route_redirect)\">\n <hm-icon [shape]=\"area.route_icon || 'home'\" size=\"sm\" />\n <span>{{ area.route_display_name }}</span>\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openSettings()\">\n <hm-icon shape=\"cog\" size=\"sm\" />\n <span>{{ t.settings }}</span>\n </button>\n </li>\n </ul>\n </section>\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-tools'\">\n <h2 class=\"block__title\" [id]=\"uid + '-tools'\">{{ t.tools }}</h2>\n <ul class=\"chips\">\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openDocs()\">\n <hm-icon shape=\"doc-list\" size=\"sm\" />\n <span>{{ t.systemDocs }}</span>\n </button>\n </li>\n </ul>\n </section>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}.hub{display:flex;flex-direction:column;gap:var(--hm-space-xl);padding:var(--hm-space-lg);min-inline-size:0}.hub--columns{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,20rem),1fr));align-items:start}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold)}ul{margin:0;padding:0;list-style:none}.link,.chip,.tile{display:inline-flex;align-items:center;gap:var(--hm-space-xs);border:1px solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer}.link:hover,.chip:hover,.tile:hover{background:var(--hm-hover)}.link:focus-visible,.chip:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.link,.chip,.tile{border-color:ButtonText}.link:focus-visible,.chip:focus-visible,.tile:focus-visible{outline-color:Highlight}}.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-medium);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-xs)}.chip{padding:var(--hm-space-xs) var(--hm-space-sm);border-color:var(--hm-divider);background:var(--hm-surface)}.link{padding:var(--hm-space-nano) var(--hm-space-xs);margin-inline-start:calc(-1 * var(--hm-space-xs));color:var(--hm-accent)}.heart--on{color:var(--hm-danger)}\n"] }]
236
- }], ctorParameters: () => [] });
237
-
238
- export { HomeAutoRedirect, HomeComponent };
239
- //# sourceMappingURL=trismegisto-spine-auto-service-home.component-5_aji1hf.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trismegisto-spine-auto-service-home.component-5_aji1hf.mjs","sources":["../../../projects/ui/auto-service/src/home/home-shortcuts.ts","../../../projects/ui/auto-service/src/home/home.component.ts","../../../projects/ui/auto-service/src/home/home.component.html"],"sourcesContent":["import { Route } from '@trismegisto/spine';\nimport {\n AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID,\n} from '../auto-service.tokens';\n\n/** A page the person can open, with the labels of the menus above it. */\nexport interface HomeDestination {\n readonly id: string;\n readonly label: string;\n readonly icon: string | null;\n readonly redirect: string;\n readonly trail: readonly string[];\n}\n\n/** A large entry tile on the home screen. */\nexport interface HomeShortcut extends HomeDestination {\n readonly screens: number;\n readonly privileged: boolean;\n}\n\n// Above this many tiles a grid stops being scannable at a glance.\nconst MAX_TILES = 12;\n\nconst ADMIN_TEMPLATES = new Set(\n [\n AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID,\n ].map((id) => id.toLowerCase()),\n);\nconst HOME_TEMPLATE = AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID.toLowerCase();\n\nfunction childrenOf(node: Route): Route[] {\n return (node.routes ?? []).filter((child): child is Route => child != null);\n}\n\nfunction labelOf(node: Route): string {\n return (node.route_display_name ?? node.route_name ?? '').trim();\n}\n\nfunction identityOf(node: Route): string {\n return node.route_redirect || `${node.route_type ?? 'node'}:${node.routed_id}`;\n}\n\nfunction templateOf(node: Route): string {\n return (node.source_template_router_id ?? '').toLowerCase();\n}\n\nexport function isPage(node: Route): boolean {\n return !!node.route_redirect && (node.route_type === 'page' || childrenOf(node).length === 0);\n}\n\nexport function isHome(node: Route): boolean {\n return templateOf(node) === HOME_TEMPLATE || (isPage(node) && node.route_path === 'home');\n}\n\nexport function modules(tree: readonly Route[]): readonly Route[] {\n return tree.filter((node) => node != null && !isHome(node));\n}\n\nexport function systemAreas(tree: readonly Route[]): readonly Route[] {\n return tree.filter((node) => node != null && isHome(node));\n}\n\nexport function destinations(tree: readonly Route[], trail: readonly string[] = []): readonly HomeDestination[] {\n const found: HomeDestination[] = [];\n const walk = (nodes: readonly Route[], path: readonly string[]) => {\n for (const node of nodes) {\n if (node == null) continue;\n if (isPage(node)) {\n found.push({ id: identityOf(node), label: labelOf(node), icon: node.route_icon ?? null, redirect: node.route_redirect!, trail: path });\n }\n const kids = childrenOf(node);\n if (kids.length) walk(kids, [...path, labelOf(node)]);\n }\n };\n walk(tree, trail);\n return found;\n}\n\nexport function trailFor(tree: readonly Route[], redirect: string): readonly string[] | null {\n return destinations(tree).find((d) => d.redirect === redirect)?.trail ?? null;\n}\n\nfunction isPrivileged(node: Route): boolean {\n return ADMIN_TEMPLATES.has(templateOf(node)) || childrenOf(node).some(isPrivileged);\n}\n\ninterface Candidate {\n readonly node: Route;\n readonly trail: readonly string[];\n readonly privileged: boolean;\n}\n\nfunction navigableChildren(node: Route): Route[] {\n return childrenOf(node).filter((child) => isPage(child) || destinations([child]).length > 0);\n}\n\n/** Replaces each candidate by its navigable children; `null` when nobody has any. */\nfunction descend(level: readonly Candidate[]): Candidate[] | null {\n let changed = false;\n const next = level.flatMap((item) => {\n const kids = navigableChildren(item.node);\n if (!kids.length) return [item];\n changed = true;\n const trail = [...item.trail, labelOf(item.node)];\n return kids.map((node) => ({ node, trail, privileged: item.privileged }));\n });\n return changed ? next : null;\n}\n\nfunction toShortcut({ node, trail, privileged }: Candidate): HomeShortcut {\n const below = destinations([node]);\n return {\n id: identityOf(node),\n label: labelOf(node),\n icon: node.route_icon ?? null,\n redirect: node.route_redirect || below[0]?.redirect || '',\n trail,\n screens: below.length - (isPage(node) ? 1 : 0),\n privileged,\n };\n}\n\n/**\n * Picks the shallowest level of the tree where there is a real choice to make: a single item is\n * skipped over, a pair is opened up while the result still fits the grid, three or more stay put.\n */\nexport function entryShortcuts(tree: readonly Route[]): readonly HomeShortcut[] {\n let level: readonly Candidate[] = modules(tree).map((node) => ({ node, trail: [], privileged: isPrivileged(node) }));\n while (level.length > 0 && level.length < 3) {\n const next = descend(level);\n if (!next) break;\n if (level.length === 2 && next.length > MAX_TILES) break;\n level = next;\n }\n return level.map(toShortcut);\n}\n","import { ChangeDetectionStrategy, Component, Injectable, computed, effect, inject } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { ViewService } from '@orfeu/angular/core';\nimport {\n DataGridCellDirective,\n DataGridColumn,\n DataGridComponent,\n IconButtonComponent,\n IconComponent,\n StatePageComponent,\n} from '@trismegisto/angular';\nimport { formatMessage, pluralMessage } from '@trismegisto/primitives';\nimport { QuickAccessItem, Route, SPINE_MESSAGES, SpineQuickAccessService, spineRoutesOf } from '@trismegisto/spine';\nimport { SpineDocsService, SpineSettingsService } from '@trismegisto/spine/layout';\nimport { map } from 'rxjs';\nimport { HomeShortcut, destinations, entryShortcuts, modules, systemAreas, trailFor } from './home-shortcuts';\n\n/** Remembers, for the whole app load, that the home screen already jumped to the only screen. */\n@Injectable({ providedIn: 'root' })\nexport class HomeAutoRedirect {\n done = false;\n}\n\ninterface RecentRow extends QuickAccessItem {\n readonly where: string;\n}\n\nconst TRAIL_SEPARATOR = ' › ';\nconst RECENT_ROWS = 4;\n\nlet instances = 0;\n\nfunction cleanTree(view: Parameters<typeof spineRoutesOf>[0]): Route[] {\n return spineRoutesOf(view).filter((node): node is Route => node != null);\n}\n\n@Component({\n selector: 'home',\n imports: [NgTemplateOutlet, DataGridComponent, DataGridCellDirective, IconButtonComponent, IconComponent, StatePageComponent],\n templateUrl: './home.component.html',\n styleUrl: './home.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class HomeComponent {\n private readonly router = inject(Router);\n private readonly quickAccess = inject(SpineQuickAccessService);\n private readonly docs = inject(SpineDocsService);\n private readonly settings = inject(SpineSettingsService);\n private readonly autoRedirect = inject(HomeAutoRedirect);\n private readonly messages = inject(SPINE_MESSAGES);\n protected readonly t = this.messages.home;\n protected readonly uid = `home-${++instances}`;\n\n private readonly view = inject(ViewService);\n private readonly tree = toSignal(this.view.currentView$.pipe(map(cleanTree)), {\n initialValue: cleanTree(this.view.currentView),\n });\n\n private readonly workDestinations = computed(() => destinations(modules(this.tree())));\n protected readonly noAccess = computed(() => this.tree().length > 0 && modules(this.tree()).length === 0);\n protected readonly areas = computed(() => systemAreas(this.tree()));\n\n private readonly shortcuts = computed(() => entryShortcuts(this.tree()));\n protected readonly workTiles = computed(() => this.shortcuts().filter((s) => !s.privileged));\n protected readonly adminTiles = computed(() => this.shortcuts().filter((s) => s.privileged));\n protected readonly descended = computed(() => this.shortcuts().some((s) => s.trail.length > 0));\n protected readonly sideBySide = computed(() => this.shortcuts().length <= 2);\n\n /** Every tile already opens a final screen, so recents/favorites would not save a single click. */\n private readonly everythingInView = computed(() => {\n const list = this.shortcuts();\n return list.length > 0 && list.every((s) => s.screens === 0);\n });\n\n protected readonly favorites = computed(() => (this.everythingInView() ? [] : this.quickAccess.favorites()));\n protected readonly recentRows = computed<readonly RecentRow[]>(() => {\n if (this.everythingInView()) return [];\n return this.quickAccess\n .recents()\n .slice(0, RECENT_ROWS)\n .map((item) => ({ ...item, where: this.whereOf(item) }));\n });\n\n protected readonly recentColumns: readonly DataGridColumn<RecentRow>[] = [\n { key: 'displayName', title: this.t.colScreen, value: (row) => row.displayName },\n { key: 'where', title: this.t.colWhere, value: (row) => row.where },\n {\n key: 'favorite',\n title: this.t.colFavorite,\n value: () => '',\n filterable: false,\n sortable: false,\n searchable: false,\n initialWidth: '5.5rem',\n },\n ];\n protected readonly rowId = (row: RecentRow) => row.id;\n\n constructor() {\n effect(() => {\n const only = this.workDestinations();\n if (only.length !== 1 || this.autoRedirect.done) return;\n this.autoRedirect.done = true;\n void this.router.navigateByUrl(only[0].redirect, { replaceUrl: true });\n });\n }\n\n protected caption(tile: HomeShortcut): string {\n if (tile.screens > 0) return pluralMessage(this.t.screenCount, tile.screens, this.messages.meta.locale);\n return tile.trail.join(TRAIL_SEPARATOR);\n }\n\n protected whereOf(item: QuickAccessItem): string {\n const trail = item.trail ?? trailFor(this.tree(), item.redirect);\n return trail?.join(TRAIL_SEPARATOR) || this.t.noModule;\n }\n\n protected row(value: unknown): RecentRow {\n return value as RecentRow;\n }\n\n protected isFavorite(id: string): boolean {\n return this.quickAccess.isFavorite(id);\n }\n\n protected favoriteLabel(row: RecentRow): string {\n const template = this.isFavorite(row.id) ? this.t.unfavorite : this.t.favorite;\n return formatMessage(template, { name: row.displayName });\n }\n\n protected toggleFavorite(row: RecentRow): void {\n this.quickAccess.toggleFavorite({\n id: row.id,\n icon: row.icon,\n displayName: row.displayName,\n redirect: row.redirect,\n trail: row.trail ?? trailFor(this.tree(), row.redirect) ?? [],\n });\n }\n\n protected go(redirect: string | null | undefined): void {\n if (redirect) void this.router.navigateByUrl(redirect);\n }\n\n protected openSettings(): void {\n this.settings.open();\n }\n\n protected openDocs(): void {\n this.docs.openIndex();\n }\n}\n","@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"hub\" [class.hub--columns]=\"sideBySide()\">\n @if (workTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n\n @if (adminTiles().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n\n @if (recentRows().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <h2 class=\"block__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n <hm-data-grid\n [caption]=\"t.recentCaption\"\n [columns]=\"recentColumns\"\n [rows]=\"recentRows()\"\n [rowId]=\"rowId\"\n [filterable]=\"false\"\n [paginated]=\"false\"\n >\n <ng-template hmCell=\"displayName\" let-value>\n @let item = row(value);\n <button type=\"button\" class=\"link\" (click)=\"go(item.redirect)\">\n <hm-icon [shape]=\"item.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ item.displayName }}</span>\n </button>\n </ng-template>\n <ng-template hmCell=\"favorite\" let-value>\n @let item = row(value);\n <hm-icon-button\n emphasis=\"subtle\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n </ng-template>\n </hm-data-grid>\n </section>\n }\n\n @if (favorites().length) {\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n <ul class=\"chips\">\n @for (fav of favorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"chip\" [title]=\"whereOf(fav)\" (click)=\"go(fav.redirect)\">\n <hm-icon [shape]=\"fav.icon || 'grid-layout'\" size=\"sm\" />\n <span>{{ fav.displayName }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-nav'\">\n <h2 class=\"block__title\" [id]=\"uid + '-nav'\">{{ t.navigate }}</h2>\n <ul class=\"chips\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"go(area.route_redirect)\">\n <hm-icon [shape]=\"area.route_icon || 'home'\" size=\"sm\" />\n <span>{{ area.route_display_name }}</span>\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openSettings()\">\n <hm-icon shape=\"cog\" size=\"sm\" />\n <span>{{ t.settings }}</span>\n </button>\n </li>\n </ul>\n </section>\n\n <section class=\"block\" [attr.aria-labelledby]=\"uid + '-tools'\">\n <h2 class=\"block__title\" [id]=\"uid + '-tools'\">{{ t.tools }}</h2>\n <ul class=\"chips\">\n <li>\n <button type=\"button\" class=\"chip\" (click)=\"openDocs()\">\n <hm-icon shape=\"doc-list\" size=\"sm\" />\n <span>{{ t.systemDocs }}</span>\n </button>\n </li>\n </ul>\n </section>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n </button>\n </li>\n }\n </ul>\n</ng-template>\n"],"names":[],"mappings":"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"}
@@ -1,35 +0,0 @@
1
- // Especificação técnica da tela Início do auto-serviço (`RouteDocument.loadTechnical`), em Markdown. Módulo próprio,
2
- // carregado só pelo `import()` de `AUTO_SERVICE_DOCUMENTS`: vira um chunk à parte no FESM e fica fora do
3
- // bundle inicial. Não importe estaticamente nem reexporte no `public-api.ts`.
4
- var home_technical = `# Início — especificação técnica
5
-
6
- Tela \`HomeComponent\` do \`@trismegisto/spine/auto-service\`, ligada ao router de template
7
- \`AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID\` (\`6a9a13db-…\`, página de topo e pública do template \`auto-service\`).
8
-
9
- ## Origem dos dados
10
-
11
- | Dado | Fonte |
12
- | --- | --- |
13
- | Atalhos, áreas e "Onde fica" | Árvore da view do Orfeu (\`ViewService.currentView$\`, via \`spineRoutesOf\`); nenhuma chamada HTTP própria |
14
- | Abertos recentemente e favoritos | \`SpineQuickAccessService\` (\`localStorage\` por usuário: \`SpineUserStorage\`, chave \`<clientId>_nav_*_<sub>\`; recentes apagados no logout) |
15
- | Configurações | \`SpineSettingsService.open()\` |
16
- | Documentação do sistema | \`SpineDocsService.openIndex()\` |
17
-
18
- ## Regras
19
-
20
- - **Módulos × áreas:** nó de topo que é o próprio Início (template \`6a9a13db-…\` ou página com \`route_path\` \`home\`)
21
- vai para **Navegar**; os demais são módulos.
22
- - **Atalhos** (\`entryShortcuts\`): parte dos módulos e desce um nível enquanto houver menos de 3 candidatos e algum
23
- deles tiver filhos navegáveis; com 2 candidatos, não desce se o próximo nível passar de 12 atalhos.
24
- - **Acesso privilegiado:** atalho cujo nó (ou algum descendente) vem dos templates de Grupos, Aplicações, Cliente
25
- ou Auditoria (\`ad100001…\` a \`ad100004…\`).
26
- - **Recentes:** os 4 primeiros do \`SpineQuickAccessService\`. Recentes e favoritos somem quando todo atalho já é uma
27
- tela final (nenhum agrupa telas).
28
- - **Redirecionamento:** com exatamente 1 destino de trabalho, navega para ele com \`replaceUrl\`, uma vez por
29
- carregamento do app (\`HomeAutoRedirect\`, \`providedIn: 'root'\`).
30
- - **Sem acesso:** árvore com nós, mas nenhum módulo → \`hm-state-page\` \`no-rights\`.
31
- - Textos em \`SpineMessages.home\` (pt-BR/en/es).
32
- `;
33
-
34
- export { home_technical as default };
35
- //# sourceMappingURL=trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trismegisto-spine-auto-service-home.technical-BrVhcgDO.mjs","sources":["../../../projects/ui/auto-service/src/docs/home.technical.ts"],"sourcesContent":["// Especificação técnica da tela Início do auto-serviço (`RouteDocument.loadTechnical`), em Markdown. Módulo próprio,\n// carregado só pelo `import()` de `AUTO_SERVICE_DOCUMENTS`: vira um chunk à parte no FESM e fica fora do\n// bundle inicial. Não importe estaticamente nem reexporte no `public-api.ts`.\nexport default `# Início — especificação técnica\n\nTela \\`HomeComponent\\` do \\`@trismegisto/spine/auto-service\\`, ligada ao router de template\n\\`AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID\\` (\\`6a9a13db-…\\`, página de topo e pública do template \\`auto-service\\`).\n\n## Origem dos dados\n\n| Dado | Fonte |\n| --- | --- |\n| Atalhos, áreas e \"Onde fica\" | Árvore da view do Orfeu (\\`ViewService.currentView$\\`, via \\`spineRoutesOf\\`); nenhuma chamada HTTP própria |\n| Abertos recentemente e favoritos | \\`SpineQuickAccessService\\` (\\`localStorage\\` por usuário: \\`SpineUserStorage\\`, chave \\`<clientId>_nav_*_<sub>\\`; recentes apagados no logout) |\n| Configurações | \\`SpineSettingsService.open()\\` |\n| Documentação do sistema | \\`SpineDocsService.openIndex()\\` |\n\n## Regras\n\n- **Módulos × áreas:** nó de topo que é o próprio Início (template \\`6a9a13db-…\\` ou página com \\`route_path\\` \\`home\\`)\n vai para **Navegar**; os demais são módulos.\n- **Atalhos** (\\`entryShortcuts\\`): parte dos módulos e desce um nível enquanto houver menos de 3 candidatos e algum\n deles tiver filhos navegáveis; com 2 candidatos, não desce se o próximo nível passar de 12 atalhos.\n- **Acesso privilegiado:** atalho cujo nó (ou algum descendente) vem dos templates de Grupos, Aplicações, Cliente\n ou Auditoria (\\`ad100001…\\` a \\`ad100004…\\`).\n- **Recentes:** os 4 primeiros do \\`SpineQuickAccessService\\`. Recentes e favoritos somem quando todo atalho já é uma\n tela final (nenhum agrupa telas).\n- **Redirecionamento:** com exatamente 1 destino de trabalho, navega para ele com \\`replaceUrl\\`, uma vez por\n carregamento do app (\\`HomeAutoRedirect\\`, \\`providedIn: 'root'\\`).\n- **Sem acesso:** árvore com nós, mas nenhum módulo → \\`hm-state-page\\` \\`no-rights\\`.\n- Textos em \\`SpineMessages.home\\` (pt-BR/en/es).\n`;\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA,qBAAe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Bd;;"}
@@ -1,43 +0,0 @@
1
- // Manual de uso da tela Início do auto-serviço (`RouteDocument.load`), em Markdown. Módulo próprio,
2
- // carregado só pelo `import()` de `AUTO_SERVICE_DOCUMENTS`: vira um chunk à parte no FESM e fica fora do
3
- // bundle inicial. Não importe estaticamente nem reexporte no `public-api.ts`.
4
- var home_usage = `# Início
5
-
6
- Ponto de partida do sistema: atalhos para as telas que você pode abrir, as que você abriu por último, os seus
7
- favoritos e o caminho para as configurações e para a documentação.
8
-
9
- ## Como usar
10
-
11
- 1. Os blocos grandes levam às telas. O título do bloco é **Módulos** quando os atalhos são os módulos do menu e
12
- **Suas telas** quando o Início já desceu para as telas de dentro deles (isso acontece quando há só um ou dois
13
- módulos: em vez de um bloco que só abre outro menu, você vê direto as telas). Abaixo do nome, o atalho mostra
14
- quantas telas reúne (por exemplo, "3 telas") ou o caminho no menu onde a tela fica.
15
- 2. **Acesso privilegiado** reúne, à parte, os atalhos das telas de administração do auto-serviço (**Grupos**,
16
- **Aplicações**, **Cliente** e **Auditoria**), para não se misturarem às telas de trabalho do dia a dia.
17
- 3. **Abertos recentemente** lista as últimas telas abertas (até 4), da mais recente para a mais antiga, com a
18
- coluna **Onde fica** (o caminho no menu). Clique no nome para abrir; o coração da coluna **Favoritar** adiciona ou
19
- remove a tela dos favoritos.
20
- 4. **Favoritos** mostra as telas favoritadas como botões. Passe o mouse sobre um deles para ver onde a tela fica.
21
- 5. **Navegar** traz as áreas de topo do sistema (como o próprio Início) e **Configurações**, que abre o painel de
22
- configurações (tema, densidade, atalhos e o resto das preferências).
23
- 6. **Ferramentas › Documentação do sistema** abre o índice da documentação: o manual de cada tela que você pode
24
- abrir e que tem documentação.
25
-
26
- Recentes e favoritos ficam guardados neste navegador, separados por pessoa: quem entrar depois no mesmo computador
27
- não vê os seus. Ao sair do sistema, os abertos recentemente são apagados; os favoritos ficam para a próxima vez. Quando todos os atalhos já abrem uma tela final, as seções
28
- **Abertos recentemente** e **Favoritos** não aparecem: elas não poupariam nenhum clique.
29
-
30
- ## Situações especiais
31
-
32
- - **Uma tela só:** se você tem acesso a uma única tela de trabalho, o Início abre essa tela direto. Isso acontece uma
33
- vez por carregamento do sistema; se você voltar ao Início depois, ele aparece normalmente.
34
- - **Sem acesso:** se a sua conta ainda não tem nenhuma tela liberada, aparece o aviso "Você ainda não tem acesso a
35
- nenhuma tela". O acesso é liberado pelo administrador da aplicação ou pelo administrador de um grupo com acesso a
36
- ela; se ele já liberou, saia e entre de novo.
37
-
38
- > O que aparece no Início vem da sua árvore de navegação (as telas que os seus grupos e o seu crachá ativo
39
- > liberam). Trocar de crachá no menu do perfil pode mudar os atalhos.
40
- `;
41
-
42
- export { home_usage as default };
43
- //# sourceMappingURL=trismegisto-spine-auto-service-home.usage-DWYGtngX.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trismegisto-spine-auto-service-home.usage-DWYGtngX.mjs","sources":["../../../projects/ui/auto-service/src/docs/home.usage.ts"],"sourcesContent":["// Manual de uso da tela Início do auto-serviço (`RouteDocument.load`), em Markdown. Módulo próprio,\n// carregado só pelo `import()` de `AUTO_SERVICE_DOCUMENTS`: vira um chunk à parte no FESM e fica fora do\n// bundle inicial. Não importe estaticamente nem reexporte no `public-api.ts`.\nexport default `# Início\n\nPonto de partida do sistema: atalhos para as telas que você pode abrir, as que você abriu por último, os seus\nfavoritos e o caminho para as configurações e para a documentação.\n\n## Como usar\n\n1. Os blocos grandes levam às telas. O título do bloco é **Módulos** quando os atalhos são os módulos do menu e\n **Suas telas** quando o Início já desceu para as telas de dentro deles (isso acontece quando há só um ou dois\n módulos: em vez de um bloco que só abre outro menu, você vê direto as telas). Abaixo do nome, o atalho mostra\n quantas telas reúne (por exemplo, \"3 telas\") ou o caminho no menu onde a tela fica.\n2. **Acesso privilegiado** reúne, à parte, os atalhos das telas de administração do auto-serviço (**Grupos**,\n **Aplicações**, **Cliente** e **Auditoria**), para não se misturarem às telas de trabalho do dia a dia.\n3. **Abertos recentemente** lista as últimas telas abertas (até 4), da mais recente para a mais antiga, com a\n coluna **Onde fica** (o caminho no menu). Clique no nome para abrir; o coração da coluna **Favoritar** adiciona ou\n remove a tela dos favoritos.\n4. **Favoritos** mostra as telas favoritadas como botões. Passe o mouse sobre um deles para ver onde a tela fica.\n5. **Navegar** traz as áreas de topo do sistema (como o próprio Início) e **Configurações**, que abre o painel de\n configurações (tema, densidade, atalhos e o resto das preferências).\n6. **Ferramentas › Documentação do sistema** abre o índice da documentação: o manual de cada tela que você pode\n abrir e que tem documentação.\n\nRecentes e favoritos ficam guardados neste navegador, separados por pessoa: quem entrar depois no mesmo computador\nnão vê os seus. Ao sair do sistema, os abertos recentemente são apagados; os favoritos ficam para a próxima vez. Quando todos os atalhos já abrem uma tela final, as seções\n**Abertos recentemente** e **Favoritos** não aparecem: elas não poupariam nenhum clique.\n\n## Situações especiais\n\n- **Uma tela só:** se você tem acesso a uma única tela de trabalho, o Início abre essa tela direto. Isso acontece uma\n vez por carregamento do sistema; se você voltar ao Início depois, ele aparece normalmente.\n- **Sem acesso:** se a sua conta ainda não tem nenhuma tela liberada, aparece o aviso \"Você ainda não tem acesso a\n nenhuma tela\". O acesso é liberado pelo administrador da aplicação ou pelo administrador de um grupo com acesso a\n ela; se ele já liberou, saia e entre de novo.\n\n> O que aparece no Início vem da sua árvore de navegação (as telas que os seus grupos e o seu crachá ativo\n> liberam). Trocar de crachá no menu do perfil pode mudar os atalhos.\n`;\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA,iBAAe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCd;;"}