@trismegisto/spine 3.0.4 → 3.0.5

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 (29) hide show
  1. package/fesm2022/{trismegisto-spine-auto-service-apps.usage-DeLfYMeO.mjs → trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs} +21 -22
  2. package/fesm2022/trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs.map +1 -0
  3. package/fesm2022/{trismegisto-spine-auto-service-auto-service-audit.component-BNtNWfiu.mjs → trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs} +2 -2
  4. package/fesm2022/{trismegisto-spine-auto-service-auto-service-audit.component-BNtNWfiu.mjs.map → trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs.map} +1 -1
  5. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs +65 -0
  6. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs.map +1 -0
  7. package/fesm2022/{trismegisto-spine-auto-service-auto-service-client.component-wu2tFGS7.mjs → trismegisto-spine-auto-service-auto-service-client.component-DzmlpLPu.mjs} +136 -87
  8. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-DzmlpLPu.mjs.map +1 -0
  9. package/fesm2022/{trismegisto-spine-auto-service-auto-service-groups.component-DHhbEiL4.mjs → trismegisto-spine-auto-service-auto-service-groups.component-2xCG_wS9.mjs} +2 -2
  10. package/fesm2022/{trismegisto-spine-auto-service-auto-service-groups.component-DHhbEiL4.mjs.map → trismegisto-spine-auto-service-auto-service-groups.component-2xCG_wS9.mjs.map} +1 -1
  11. package/fesm2022/{trismegisto-spine-auto-service-auto-service-login-attempts.component-B87vibNB.mjs → trismegisto-spine-auto-service-auto-service-login-attempts.component-CRvxfSWD.mjs} +2 -2
  12. package/fesm2022/{trismegisto-spine-auto-service-auto-service-login-attempts.component-B87vibNB.mjs.map → trismegisto-spine-auto-service-auto-service-login-attempts.component-CRvxfSWD.mjs.map} +1 -1
  13. package/fesm2022/{trismegisto-spine-auto-service-auto-service.component-D-N-xXPN.mjs → trismegisto-spine-auto-service-auto-service.component-C4FBAefe.mjs} +89 -55
  14. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-C4FBAefe.mjs.map +1 -0
  15. package/fesm2022/{trismegisto-spine-auto-service-client.usage-CcJANb20.mjs → trismegisto-spine-auto-service-client.usage-B16r3IHk.mjs} +16 -12
  16. package/fesm2022/trismegisto-spine-auto-service-client.usage-B16r3IHk.mjs.map +1 -0
  17. package/fesm2022/trismegisto-spine-auto-service.mjs +7 -7
  18. package/fesm2022/trismegisto-spine.mjs +39 -3
  19. package/fesm2022/trismegisto-spine.mjs.map +1 -1
  20. package/package.json +6 -6
  21. package/types/trismegisto-spine-auto-service.d.ts.map +1 -1
  22. package/types/trismegisto-spine.d.ts +22 -0
  23. package/types/trismegisto-spine.d.ts.map +1 -1
  24. package/fesm2022/trismegisto-spine-auto-service-apps.usage-DeLfYMeO.mjs.map +0 -1
  25. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-DdtDk_xl.mjs +0 -51
  26. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-DdtDk_xl.mjs.map +0 -1
  27. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-wu2tFGS7.mjs.map +0 -1
  28. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-D-N-xXPN.mjs.map +0 -1
  29. package/fesm2022/trismegisto-spine-auto-service-client.usage-CcJANb20.mjs.map +0 -1
@@ -2,9 +2,9 @@ import * as i0 from '@angular/core';
2
2
  import { inject, ChangeDetectorRef, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, signal, computed } from '@angular/core';
3
3
  import * as i2 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import { A as AutoServiceClientPickerComponent } from './trismegisto-spine-auto-service-auto-service-client-picker.component-DdtDk_xl.mjs';
5
+ import { A as AutoServiceClientPickerComponent } from './trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs';
6
6
  import { HttpErrorResponse } from '@angular/common/http';
7
- import { ButtonComponent, CheckboxComponent, InputComponent, ModalComponent, ComboboxComponent, HermesToastService, DrawerComponent, IconComponent, TagComponent, TreeComponent, TreeNodeTemplateDirective, DataGridComponent, DataGridCellDirective, AlertComponent, CopyButtonComponent, DatePickerComponent, TextareaComponent, HermesDialogService, CardComponent, TabsComponent, TabComponent, TabContentDirective } from '@trismegisto/angular';
7
+ import { ButtonComponent, CheckboxComponent, InputComponent, ModalComponent, ComboboxComponent, HermesToastService, DataGridActionBarComponent, DrawerComponent, IconComponent, TagComponent, TreeComponent, TreeNodeTemplateDirective, DataGridComponent, DataGridCellDirective, AlertComponent, CopyButtonComponent, DatePickerComponent, TextareaComponent, HermesDialogService, CardComponent, TabsComponent, TabComponent, TabContentDirective } from '@trismegisto/angular';
8
8
  import { formatMessage, pluralMessage } from '@trismegisto/primitives';
9
9
  import { SPINE_MESSAGES } from '@trismegisto/spine';
10
10
  import { a as autoServiceErrorText, A as AutoServiceDeleteFeedback } from './trismegisto-spine-auto-service-auto-service-delete-CV_t9vxm.mjs';
@@ -165,10 +165,15 @@ function freeAccessText(level, text, mode = 'group') {
165
165
  function freeChecked(mode) {
166
166
  return mode === 'group';
167
167
  }
168
- /** Cor do selo de nível, a mesma da aba Operações: pública em verde, protegida em amarelo; o resto neutro. */
168
+ /**
169
+ * Cor do selo de nível na aba Operações e no drawer de permissões, a mesma do painel do Argos: pública em verde,
170
+ * privada em azul, protegida em amarelo; o resto (optional) neutro.
171
+ */
169
172
  function levelTagColor(level) {
170
173
  if (level === 'public')
171
174
  return 'success';
175
+ if (level === 'private')
176
+ return 'info';
172
177
  if (level === 'protected')
173
178
  return 'warning';
174
179
  return 'neutral';
@@ -200,40 +205,25 @@ class AutoServiceConsumerPermissionsComponent {
200
205
  this.saving = false;
201
206
  this.modeSig = signal('group', ...(ngDevMode ? [{ debugName: "modeSig" }] : /* istanbul ignore next */ []));
202
207
  this.tree = signal([], ...(ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []));
208
+ /** Termo do filtro no topo do drawer; a árvore mostrada é `visibleTree`. */
209
+ this.filter = signal('', ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
210
+ this.visibleTree = computed(() => filterOperationTree(this.tree(), this.filter()), ...(ngDevMode ? [{ debugName: "visibleTree" }] : /* istanbul ignore next */ []));
211
+ /** Nós visíveis por chave: marcar uma pasta com o filtro ativo só mexe nas operações que aparecem. */
212
+ this.visibleByKey = computed(() => indexByKey(this.visibleTree()), ...(ngDevMode ? [{ debugName: "visibleByKey" }] : /* istanbul ignore next */ []));
203
213
  /** Só operações escolhíveis (não travadas): é o que o consumer pode ganhar ou perder. */
204
214
  this.selectedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedIds" }] : /* istanbul ignore next */ []));
205
215
  this.expandedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
206
216
  this.originalSelectedIds = new Set();
207
217
  /** Todos os nós (pastas e folhas) por chave. */
208
- this.nodesByKey = computed(() => {
209
- const map = new Map();
210
- const walk = (nodes) => { for (const n of nodes) {
211
- map.set(n.key, n);
212
- walk(n.children);
213
- } };
214
- walk(this.tree());
215
- return map;
216
- }, ...(ngDevMode ? [{ debugName: "nodesByKey" }] : /* istanbul ignore next */ []));
218
+ this.nodesByKey = computed(() => indexByKey(this.tree()), ...(ngDevMode ? [{ debugName: "nodesByKey" }] : /* istanbul ignore next */ []));
217
219
  this.leaves = computed(() => this.tree().flatMap(n => collectLeaves(n)), ...(ngDevMode ? [{ debugName: "leaves" }] : /* istanbul ignore next */ []));
218
220
  this.lockedIds = computed(() => new Set(this.leaves().filter(l => l.locked).map(l => l.key)), ...(ngDevMode ? [{ debugName: "lockedIds" }] : /* istanbul ignore next */ []));
219
221
  /** Marcação mostrada na árvore: as escolhidas e, no GRUPO, as travadas (já valem para ele). No token as travadas
220
222
  * (public) aparecem desmarcadas. */
221
223
  this.treeSelected = computed(() => this.modeSig() === 'token' ? this.selectedIds() : new Set([...this.selectedIds(), ...this.lockedIds()]), ...(ngDevMode ? [{ debugName: "treeSelected" }] : /* istanbul ignore next */ []));
222
- /** Linha de resumo no topo: quantas escolhíveis estão liberadas e quantas não dependem de permissão. */
223
- this.summary = computed(() => {
224
- const total = this.leaves().filter(l => !l.locked).length;
225
- const marked = this.selectedIds().size;
226
- return formatMessage(this.modeSig() === 'token' ? this.text.permissionsSummaryToken : this.text.permissionsSummaryGroup, { marked, total });
227
- }, ...(ngDevMode ? [{ debugName: "summary" }] : /* istanbul ignore next */ []));
228
- this.freeSummary = computed(() => {
229
- const n = this.lockedIds().size;
230
- if (!n)
231
- return '';
232
- return pluralMessage(this.modeSig() === 'token' ? this.text.permissionsFreeToken : this.text.permissionsFreeGroup, n, this.messages.meta.locale);
233
- }, ...(ngDevMode ? [{ debugName: "freeSummary" }] : /* istanbul ignore next */ []));
234
224
  /** hm-tree é lista achatada com estado só em `selected`/`expanded`. O label leva o texto completo (nome, método,
235
225
  * nível, descrição e por que está travada, para leitor de tela); o que aparece vem do modelo `hmTreeNode`. */
236
- this.treeNodes = computed(() => this.tree().map(n => this.toTreeNode(n)), ...(ngDevMode ? [{ debugName: "treeNodes" }] : /* istanbul ignore next */ []));
226
+ this.treeNodes = computed(() => this.visibleTree().map(n => this.toTreeNode(n)), ...(ngDevMode ? [{ debugName: "treeNodes" }] : /* istanbul ignore next */ []));
237
227
  this.nodeInfo = computed(() => {
238
228
  const selected = this.selectedIds();
239
229
  const map = new Map();
@@ -277,6 +267,13 @@ class AutoServiceConsumerPermissionsComponent {
277
267
  const label = `${node.name} — ${node.method} · ${node.level}${node.description ? ' · ' + node.description : ''}${free ? ' · ' + free : ''}`;
278
268
  return { id: node.key, label, leaf: true, disabled: !!node.locked };
279
269
  }
270
+ /** Filtrar abre as pastas que sobraram, para as operações encontradas aparecerem sem clique. */
271
+ onFilterChange(term) {
272
+ this.filter.set(term);
273
+ if (!term.trim())
274
+ return;
275
+ this.expandedIds.update(current => new Set([...current, ...folderKeys(this.visibleTree())]));
276
+ }
280
277
  ngOnChanges(changes) { if (changes['open'] && this.open) {
281
278
  this.reset();
282
279
  } }
@@ -320,6 +317,7 @@ class AutoServiceConsumerPermissionsComponent {
320
317
  this.originalSelectedIds = original;
321
318
  this.selectedIds.set(new Set(original));
322
319
  this.expandedIds.set(new Set());
320
+ this.filter.set('');
323
321
  }
324
322
  finally {
325
323
  this.loading = false;
@@ -328,13 +326,13 @@ class AutoServiceConsumerPermissionsComponent {
328
326
  }
329
327
  /**
330
328
  * Mudança do hm-tree: com caixas ele emite só folhas habilitadas (ou o id da pasta sem folhas). Pasta vira as folhas
331
- * escolhíveis dela; folha travada e chave desconhecida são ignoradas.
329
+ * escolhíveis dela que estão à vista (com filtro, só as que casaram); folha travada e chave desconhecida são ignoradas.
332
330
  */
333
331
  onTreeChanged(changes) {
334
332
  this.selectedIds.update(current => {
335
333
  const next = new Set(current);
336
334
  for (const change of changes) {
337
- const node = this.nodesByKey().get(change.id);
335
+ const node = this.visibleByKey().get(change.id);
338
336
  if (!node)
339
337
  continue;
340
338
  for (const leaf of collectLeaves(node)) {
@@ -392,11 +390,13 @@ class AutoServiceConsumerPermissionsComponent {
392
390
  }
393
391
  }
394
392
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceConsumerPermissionsComponent, deps: [{ token: AutoServiceService }], target: i0.ɵɵFactoryTarget.Component }); }
395
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: AutoServiceConsumerPermissionsComponent, isStandalone: true, selector: "spine-auto-service-consumer-permissions", inputs: { clientId: "clientId", appId: "appId", consumer: "consumer", mode: "mode", open: "open" }, outputs: { openChange: "openChange" }, usesOnChanges: true, ngImport: i0, template: "<hm-drawer [open]=\"open\" (openChange)=\"open = $event\" [heading]=\"fmt(text.operationsOf, { group: consumer?.group_name ?? '' })\" (closed)=\"close()\">\n <div *ngIf=\"loading\" class=\"loading-row\">{{ text.loading }}</div>\n\n <ng-container *ngIf=\"!loading && treeNodes().length\">\n <!-- Grupo: s\u00F3 protected depende de permiss\u00E3o; public/private/optional j\u00E1 valem e aparecem marcadas e desabilitadas.\n Token: private/optional/protected s\u00F3 valem liberadas; public aparece desabilitada e desmarcada. -->\n <p class=\"cp-summary\">{{ summary() }} {{ freeSummary() }}</p>\n\n <hm-tree\n [nodes]=\"treeNodes()\"\n [label]=\"text.permissionsTreeLabel\"\n [selected]=\"treeSelected()\"\n [(expanded)]=\"expandedIds\"\n (changed)=\"onTreeChanged($event)\"\n >\n <ng-template hmTreeNode let-node>\n @let item = info(node);\n <span class=\"cp-node\">\n <span class=\"cp-node__name\">{{ item.name }}</span>\n @if (item.isFolder) {\n @if (item.count) {\n <span class=\"cp-node__count\">{{ item.count }}</span>\n }\n } @else {\n <hm-tag [name]=\"item.method ?? ''\" color=\"neutral\" />\n <hm-tag [name]=\"item.level ?? ''\" [color]=\"item.levelColor ?? 'neutral'\" />\n @if (item.description) {\n <span class=\"cp-node__desc\">{{ item.description }}</span>\n }\n }\n </span>\n </ng-template>\n </hm-tree>\n </ng-container>\n\n <div class=\"empty-state\" *ngIf=\"!loading && treeNodes().length === 0\">\n <hm-icon shape=\"filter-grid\" size=\"xl\"></hm-icon>\n <p>{{ text.noOperations }}</p>\n </div>\n\n <ng-container footer>\n <hm-button emphasis=\"medium\" (clicked)=\"close()\">{{ text.cancel }}</hm-button>\n <hm-button [disabled]=\"!hasChanges\" [loading]=\"saving\" (clicked)=\"confirm()\">{{ text.confirmChanges }}</hm-button>\n </ng-container>\n</hm-drawer>\n", styles: ["@charset \"UTF-8\";.as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.loading-row{display:flex;justify-content:center;padding:var(--hm-space-xl);color:var(--hm-muted)}.cp-summary{margin:0 0 var(--hm-space-sm);color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.cp-node{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xxxs) var(--hm-space-xs);min-width:0}.cp-node__count,.cp-node__desc{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.empty-state{display:flex;flex-direction:column;align-items:center;gap:var(--hm-space-xs);padding:var(--hm-space-xl);color:var(--hm-muted);text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { kind: "component", type: DrawerComponent, selector: "hm-drawer", inputs: ["open", "heading", "size", "position", "pinned", "closeLabel", "closable", "beforeClose"], outputs: ["openChange", "closed"] }, { kind: "component", type: IconComponent, selector: "hm-icon", inputs: ["shape", "direction", "size", "solid", "badge", "status", "flip", "inverse", "label"] }, { kind: "component", type: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }, { kind: "component", type: TreeComponent, selector: "hm-tree", inputs: ["nodes", "label", "emptyMessage", "selectable", "selectionMode", "selection", "selected", "expanded", "activeId", "loadChildren", "draggable", "canDrop", "nodeActions"], outputs: ["selectionChange", "expandedChange", "activeIdChange", "changed", "activated", "moved", "nodeAction"] }, { kind: "directive", type: TreeNodeTemplateDirective, selector: "ng-template[hmTreeNode]" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
393
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: AutoServiceConsumerPermissionsComponent, isStandalone: true, selector: "spine-auto-service-consumer-permissions", inputs: { clientId: "clientId", appId: "appId", consumer: "consumer", mode: "mode", open: "open" }, outputs: { openChange: "openChange" }, usesOnChanges: true, ngImport: i0, template: "<hm-drawer [open]=\"open\" (openChange)=\"open = $event\" [heading]=\"fmt(text.operationsOf, { group: consumer?.group_name ?? '' })\" (closed)=\"close()\">\n <div *ngIf=\"loading\" class=\"loading-row\">{{ text.loading }}</div>\n\n <!-- Topo sem mensagens: s\u00F3 o filtro, com o mesmo visual da busca das grades. -->\n <hm-data-grid-action-bar *ngIf=\"!loading && tree().length\"\n [search]=\"filter()\" (searchChange)=\"onFilterChange($event)\"\n [placeholder]=\"text.filterOperations\" [label]=\"text.filterOperations\" />\n\n <ng-container *ngIf=\"!loading && treeNodes().length\">\n <!-- Grupo: s\u00F3 protected depende de permiss\u00E3o; public/private/optional j\u00E1 valem e aparecem marcadas e desabilitadas.\n Token: private/optional/protected s\u00F3 valem liberadas; public aparece desabilitada e desmarcada. -->\n <hm-tree\n [nodes]=\"treeNodes()\"\n [label]=\"text.permissionsTreeLabel\"\n [selected]=\"treeSelected()\"\n [(expanded)]=\"expandedIds\"\n (changed)=\"onTreeChanged($event)\"\n >\n <ng-template hmTreeNode let-node>\n @let item = info(node);\n <span class=\"cp-node\">\n <span class=\"cp-node__name\">{{ item.name }}</span>\n @if (item.isFolder) {\n @if (item.count) {\n <span class=\"cp-node__count\">{{ item.count }}</span>\n }\n } @else {\n <hm-tag [name]=\"item.method ?? ''\" color=\"neutral\" />\n <hm-tag [name]=\"item.level ?? ''\" [color]=\"item.levelColor ?? 'neutral'\" />\n @if (item.description) {\n <span class=\"cp-node__desc\">{{ item.description }}</span>\n }\n }\n </span>\n </ng-template>\n </hm-tree>\n </ng-container>\n\n <div class=\"empty-state\" *ngIf=\"!loading && tree().length > 0 && treeNodes().length === 0\">\n <hm-icon shape=\"search\" size=\"xl\"></hm-icon>\n <p>{{ fmt(text.noFilterMatch, { term: filter() }) }}</p>\n </div>\n\n <div class=\"empty-state\" *ngIf=\"!loading && tree().length === 0\">\n <hm-icon shape=\"filter-grid\" size=\"xl\"></hm-icon>\n <p>{{ text.noOperations }}</p>\n </div>\n\n <ng-container footer>\n <hm-button emphasis=\"medium\" (clicked)=\"close()\">{{ text.cancel }}</hm-button>\n <hm-button [disabled]=\"!hasChanges\" [loading]=\"saving\" (clicked)=\"confirm()\">{{ text.confirmChanges }}</hm-button>\n </ng-container>\n</hm-drawer>\n", styles: ["@charset \"UTF-8\";.as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.loading-row{display:flex;justify-content:center;padding:var(--hm-space-xl);color:var(--hm-muted)}.cp-node{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xxxs) var(--hm-space-xs);min-width:0}.cp-node__count,.cp-node__desc{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.empty-state{display:flex;flex-direction:column;align-items:center;gap:var(--hm-space-xs);padding:var(--hm-space-xl);color:var(--hm-muted);text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { kind: "component", type: DataGridActionBarComponent, selector: "hm-data-grid-action-bar", inputs: ["search", "placeholder", "label"], outputs: ["searchChange"] }, { kind: "component", type: DrawerComponent, selector: "hm-drawer", inputs: ["open", "heading", "size", "position", "pinned", "closeLabel", "closable", "beforeClose"], outputs: ["openChange", "closed"] }, { kind: "component", type: IconComponent, selector: "hm-icon", inputs: ["shape", "direction", "size", "solid", "badge", "status", "flip", "inverse", "label"] }, { kind: "component", type: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }, { kind: "component", type: TreeComponent, selector: "hm-tree", inputs: ["nodes", "label", "emptyMessage", "selectable", "selectionMode", "selection", "selected", "expanded", "activeId", "loadChildren", "draggable", "canDrop", "nodeActions"], outputs: ["selectionChange", "expandedChange", "activeIdChange", "changed", "activated", "moved", "nodeAction"] }, { kind: "directive", type: TreeNodeTemplateDirective, selector: "ng-template[hmTreeNode]" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
396
394
  }
397
395
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceConsumerPermissionsComponent, decorators: [{
398
396
  type: Component,
399
- args: [{ selector: 'spine-auto-service-consumer-permissions', standalone: true, imports: [CommonModule, ButtonComponent, DrawerComponent, IconComponent, TagComponent, TreeComponent, TreeNodeTemplateDirective], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-drawer [open]=\"open\" (openChange)=\"open = $event\" [heading]=\"fmt(text.operationsOf, { group: consumer?.group_name ?? '' })\" (closed)=\"close()\">\n <div *ngIf=\"loading\" class=\"loading-row\">{{ text.loading }}</div>\n\n <ng-container *ngIf=\"!loading && treeNodes().length\">\n <!-- Grupo: s\u00F3 protected depende de permiss\u00E3o; public/private/optional j\u00E1 valem e aparecem marcadas e desabilitadas.\n Token: private/optional/protected s\u00F3 valem liberadas; public aparece desabilitada e desmarcada. -->\n <p class=\"cp-summary\">{{ summary() }} {{ freeSummary() }}</p>\n\n <hm-tree\n [nodes]=\"treeNodes()\"\n [label]=\"text.permissionsTreeLabel\"\n [selected]=\"treeSelected()\"\n [(expanded)]=\"expandedIds\"\n (changed)=\"onTreeChanged($event)\"\n >\n <ng-template hmTreeNode let-node>\n @let item = info(node);\n <span class=\"cp-node\">\n <span class=\"cp-node__name\">{{ item.name }}</span>\n @if (item.isFolder) {\n @if (item.count) {\n <span class=\"cp-node__count\">{{ item.count }}</span>\n }\n } @else {\n <hm-tag [name]=\"item.method ?? ''\" color=\"neutral\" />\n <hm-tag [name]=\"item.level ?? ''\" [color]=\"item.levelColor ?? 'neutral'\" />\n @if (item.description) {\n <span class=\"cp-node__desc\">{{ item.description }}</span>\n }\n }\n </span>\n </ng-template>\n </hm-tree>\n </ng-container>\n\n <div class=\"empty-state\" *ngIf=\"!loading && treeNodes().length === 0\">\n <hm-icon shape=\"filter-grid\" size=\"xl\"></hm-icon>\n <p>{{ text.noOperations }}</p>\n </div>\n\n <ng-container footer>\n <hm-button emphasis=\"medium\" (clicked)=\"close()\">{{ text.cancel }}</hm-button>\n <hm-button [disabled]=\"!hasChanges\" [loading]=\"saving\" (clicked)=\"confirm()\">{{ text.confirmChanges }}</hm-button>\n </ng-container>\n</hm-drawer>\n", styles: ["@charset \"UTF-8\";.as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.loading-row{display:flex;justify-content:center;padding:var(--hm-space-xl);color:var(--hm-muted)}.cp-summary{margin:0 0 var(--hm-space-sm);color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.cp-node{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xxxs) var(--hm-space-xs);min-width:0}.cp-node__count,.cp-node__desc{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.empty-state{display:flex;flex-direction:column;align-items:center;gap:var(--hm-space-xs);padding:var(--hm-space-xl);color:var(--hm-muted);text-align:center}\n"] }]
397
+ args: [{ selector: 'spine-auto-service-consumer-permissions', standalone: true, imports: [
398
+ CommonModule, ButtonComponent, DataGridActionBarComponent, DrawerComponent, IconComponent, TagComponent, TreeComponent, TreeNodeTemplateDirective,
399
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-drawer [open]=\"open\" (openChange)=\"open = $event\" [heading]=\"fmt(text.operationsOf, { group: consumer?.group_name ?? '' })\" (closed)=\"close()\">\n <div *ngIf=\"loading\" class=\"loading-row\">{{ text.loading }}</div>\n\n <!-- Topo sem mensagens: s\u00F3 o filtro, com o mesmo visual da busca das grades. -->\n <hm-data-grid-action-bar *ngIf=\"!loading && tree().length\"\n [search]=\"filter()\" (searchChange)=\"onFilterChange($event)\"\n [placeholder]=\"text.filterOperations\" [label]=\"text.filterOperations\" />\n\n <ng-container *ngIf=\"!loading && treeNodes().length\">\n <!-- Grupo: s\u00F3 protected depende de permiss\u00E3o; public/private/optional j\u00E1 valem e aparecem marcadas e desabilitadas.\n Token: private/optional/protected s\u00F3 valem liberadas; public aparece desabilitada e desmarcada. -->\n <hm-tree\n [nodes]=\"treeNodes()\"\n [label]=\"text.permissionsTreeLabel\"\n [selected]=\"treeSelected()\"\n [(expanded)]=\"expandedIds\"\n (changed)=\"onTreeChanged($event)\"\n >\n <ng-template hmTreeNode let-node>\n @let item = info(node);\n <span class=\"cp-node\">\n <span class=\"cp-node__name\">{{ item.name }}</span>\n @if (item.isFolder) {\n @if (item.count) {\n <span class=\"cp-node__count\">{{ item.count }}</span>\n }\n } @else {\n <hm-tag [name]=\"item.method ?? ''\" color=\"neutral\" />\n <hm-tag [name]=\"item.level ?? ''\" [color]=\"item.levelColor ?? 'neutral'\" />\n @if (item.description) {\n <span class=\"cp-node__desc\">{{ item.description }}</span>\n }\n }\n </span>\n </ng-template>\n </hm-tree>\n </ng-container>\n\n <div class=\"empty-state\" *ngIf=\"!loading && tree().length > 0 && treeNodes().length === 0\">\n <hm-icon shape=\"search\" size=\"xl\"></hm-icon>\n <p>{{ fmt(text.noFilterMatch, { term: filter() }) }}</p>\n </div>\n\n <div class=\"empty-state\" *ngIf=\"!loading && tree().length === 0\">\n <hm-icon shape=\"filter-grid\" size=\"xl\"></hm-icon>\n <p>{{ text.noOperations }}</p>\n </div>\n\n <ng-container footer>\n <hm-button emphasis=\"medium\" (clicked)=\"close()\">{{ text.cancel }}</hm-button>\n <hm-button [disabled]=\"!hasChanges\" [loading]=\"saving\" (clicked)=\"confirm()\">{{ text.confirmChanges }}</hm-button>\n </ng-container>\n</hm-drawer>\n", styles: ["@charset \"UTF-8\";.as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.loading-row{display:flex;justify-content:center;padding:var(--hm-space-xl);color:var(--hm-muted)}.cp-node{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xxxs) var(--hm-space-xs);min-width:0}.cp-node__count,.cp-node__desc{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.empty-state{display:flex;flex-direction:column;align-items:center;gap:var(--hm-space-xs);padding:var(--hm-space-xl);color:var(--hm-muted);text-align:center}\n"] }]
400
400
  }], ctorParameters: () => [{ type: AutoServiceService }], propDecorators: { clientId: [{
401
401
  type: Input
402
402
  }], appId: [{
@@ -416,6 +416,42 @@ function collectLeaves(node) {
416
416
  function collectAll(root) {
417
417
  return root.flatMap(collectLeaves);
418
418
  }
419
+ function indexByKey(root) {
420
+ const map = new Map();
421
+ const walk = (nodes) => { for (const n of nodes) {
422
+ map.set(n.key, n);
423
+ walk(n.children);
424
+ } };
425
+ walk(root);
426
+ return map;
427
+ }
428
+ function folderKeys(root) {
429
+ return [...indexByKey(root).values()].filter(n => n.isFolder).map(n => n.key);
430
+ }
431
+ /** Minúsculo e sem acento: "operacao" casa com "Operação". */
432
+ function normalize(value) {
433
+ return (value ?? '').normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();
434
+ }
435
+ /**
436
+ * A árvore só com o que casa com o termo. A operação casa pelo identificador, método, nível ou descrição; a pasta que
437
+ * casa pelo nome vem inteira. Pasta sem nada que case sai. Termo vazio devolve a árvore como está.
438
+ */
439
+ function filterOperationTree(nodes, term) {
440
+ const needle = normalize(term.trim());
441
+ if (!needle)
442
+ return nodes;
443
+ const walk = (list) => list.flatMap((n) => {
444
+ if (n.isFolder) {
445
+ if (normalize(n.name).includes(needle))
446
+ return [n];
447
+ const children = walk(n.children);
448
+ return children.length ? [{ ...n, children }] : [];
449
+ }
450
+ const haystack = [n.identifier, n.method, n.level, n.description].map(normalize).join(' ');
451
+ return haystack.includes(needle) ? [n] : [];
452
+ });
453
+ return walk(nodes);
454
+ }
419
455
 
420
456
  class AutoServiceAppAccessComponent {
421
457
  constructor(service) {
@@ -436,11 +472,12 @@ class AutoServiceAppAccessComponent {
436
472
  this.columns = computed(() => [
437
473
  { key: 'group_name', title: this.text.colGroup, value: (c) => c.group_name, sortable: true },
438
474
  { key: 'group_type_name', title: this.text.colType, value: (c) => c.group_type_name, sortable: true },
475
+ // Como no painel do Argos: "Gerenciar operações" é um botão na linha, não um item do menu.
476
+ { key: 'operations', title: this.text.colOperations, value: () => '' },
439
477
  ], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
440
478
  this.rowActions = computed(() => [
441
- { id: 'permissions', icon: 'shield', label: this.text.manageOperations },
442
479
  {
443
- id: 'delete', icon: 'trash', label: this.text.remove, danger: true, separatorAbove: true,
480
+ id: 'delete', icon: 'trash', label: this.text.remove, danger: true,
444
481
  confirm: (c) => ({ heading: this.text.confirmRemoveConsumerHeading, message: formatMessage(this.text.confirmRemoveConsumer, { group: c.group_name }) }),
445
482
  },
446
483
  ], ...(ngDevMode ? [{ debugName: "rowActions" }] : /* istanbul ignore next */ []));
@@ -486,17 +523,18 @@ class AutoServiceAppAccessComponent {
486
523
  }
487
524
  openPermissions(consumer) { this.activeConsumer = consumer; this.showPermissions = true; }
488
525
  onAction(e) {
489
- if (e.action === 'permissions')
490
- this.openPermissions(e.row);
491
526
  if (e.action === 'delete')
492
527
  void this.deleteConsumer(e.row.consumer_id);
493
528
  }
494
529
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppAccessComponent, deps: [{ token: AutoServiceService }], target: i0.ɵɵFactoryTarget.Component }); }
495
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppAccessComponent, isStandalone: true, selector: "spine-auto-service-app-access", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"entries\"\n [rowId]=\"rowId\"\n [caption]=\"text.appAccessCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n (actionTriggered)=\"onAction($event)\"\n [emptyMessage]=\"text.noAppAccess\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newAccess }}</hm-button>\n</hm-data-grid>\n\n<spine-auto-service-consumer-create\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [availableGroups]=\"availableGroups\"\n [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\"\n (created)=\"onCreated()\">\n</spine-auto-service-consumer-create>\n\n<spine-auto-service-consumer-permissions\n *ngIf=\"activeConsumer\"\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [consumer]=\"activeConsumer\"\n [open]=\"showPermissions\"\n (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { 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: "component", type: AutoServiceConsumerCreateComponent, selector: "spine-auto-service-consumer-create", inputs: ["clientId", "appId", "availableGroups", "open"], outputs: ["openChange", "created"] }, { kind: "component", type: AutoServiceConsumerPermissionsComponent, selector: "spine-auto-service-consumer-permissions", inputs: ["clientId", "appId", "consumer", "mode", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
530
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppAccessComponent, isStandalone: true, selector: "spine-auto-service-app-access", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"entries\"\n [rowId]=\"rowId\"\n [caption]=\"text.appAccessCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n (actionTriggered)=\"onAction($event)\"\n [emptyMessage]=\"text.noAppAccess\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newAccess }}</hm-button>\n <ng-template hmCell=\"group_type_name\" let-c>\n <hm-tag [name]=\"c.group_type_name\" color=\"neutral\" />\n </ng-template>\n <ng-template hmCell=\"operations\" let-c>\n <hm-button emphasis=\"minimal\" icon=\"shield\" (clicked)=\"openPermissions(c)\">{{ text.manageOperations }}</hm-button>\n </ng-template>\n</hm-data-grid>\n\n<spine-auto-service-consumer-create\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [availableGroups]=\"availableGroups\"\n [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\"\n (created)=\"onCreated()\">\n</spine-auto-service-consumer-create>\n\n<spine-auto-service-consumer-permissions\n *ngIf=\"activeConsumer\"\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [consumer]=\"activeConsumer\"\n [open]=\"showPermissions\"\n (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { 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: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }, { kind: "component", type: AutoServiceConsumerCreateComponent, selector: "spine-auto-service-consumer-create", inputs: ["clientId", "appId", "availableGroups", "open"], outputs: ["openChange", "created"] }, { kind: "component", type: AutoServiceConsumerPermissionsComponent, selector: "spine-auto-service-consumer-permissions", inputs: ["clientId", "appId", "consumer", "mode", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
496
531
  }
497
532
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppAccessComponent, decorators: [{
498
533
  type: Component,
499
- args: [{ selector: 'spine-auto-service-app-access', standalone: true, imports: [CommonModule, ButtonComponent, IconComponent, DataGridComponent, AutoServiceConsumerCreateComponent, AutoServiceConsumerPermissionsComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"entries\"\n [rowId]=\"rowId\"\n [caption]=\"text.appAccessCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n (actionTriggered)=\"onAction($event)\"\n [emptyMessage]=\"text.noAppAccess\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newAccess }}</hm-button>\n</hm-data-grid>\n\n<spine-auto-service-consumer-create\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [availableGroups]=\"availableGroups\"\n [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\"\n (created)=\"onCreated()\">\n</spine-auto-service-consumer-create>\n\n<spine-auto-service-consumer-permissions\n *ngIf=\"activeConsumer\"\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [consumer]=\"activeConsumer\"\n [open]=\"showPermissions\"\n (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"] }]
534
+ args: [{ selector: 'spine-auto-service-app-access', standalone: true, imports: [
535
+ CommonModule, ButtonComponent, IconComponent, DataGridComponent, DataGridCellDirective, TagComponent,
536
+ AutoServiceConsumerCreateComponent, AutoServiceConsumerPermissionsComponent,
537
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"entries\"\n [rowId]=\"rowId\"\n [caption]=\"text.appAccessCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n (actionTriggered)=\"onAction($event)\"\n [emptyMessage]=\"text.noAppAccess\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newAccess }}</hm-button>\n <ng-template hmCell=\"group_type_name\" let-c>\n <hm-tag [name]=\"c.group_type_name\" color=\"neutral\" />\n </ng-template>\n <ng-template hmCell=\"operations\" let-c>\n <hm-button emphasis=\"minimal\" icon=\"shield\" (clicked)=\"openPermissions(c)\">{{ text.manageOperations }}</hm-button>\n </ng-template>\n</hm-data-grid>\n\n<spine-auto-service-consumer-create\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [availableGroups]=\"availableGroups\"\n [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\"\n (created)=\"onCreated()\">\n</spine-auto-service-consumer-create>\n\n<spine-auto-service-consumer-permissions\n *ngIf=\"activeConsumer\"\n [clientId]=\"clientId\"\n [appId]=\"appId\"\n [consumer]=\"activeConsumer\"\n [open]=\"showPermissions\"\n (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"] }]
500
538
  }], ctorParameters: () => [{ type: AutoServiceService }], propDecorators: { clientId: [{
501
539
  type: Input
502
540
  }], appId: [{
@@ -520,12 +558,13 @@ class AutoServiceAppOperationsComponent {
520
558
  { key: 'method', title: this.text.colMethod, value: (op) => op.method, sortable: true },
521
559
  { key: 'level', title: this.text.colLevel, value: (op) => op.level, sortable: true },
522
560
  { key: 'description', title: this.text.colDescription, value: (op) => op.description || '—' },
523
- {
524
- key: 'allowed_groups', title: this.text.colAllowedGroups,
525
- value: (op) => op.allowed_groups?.length ? pluralMessage(this.text.groupCount, op.allowed_groups.length, this.messages.meta.locale) : '—',
526
- },
561
+ { key: 'allowed_groups', title: this.text.colAllowedGroups, value: (op) => (op.allowed_groups?.length ? this.groupCount(op) : '—') },
527
562
  ], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
528
563
  }
564
+ /** "2 grupos": a etiqueta da coluna de grupos com acesso (mesma do painel do Argos). */
565
+ groupCount(op) {
566
+ return pluralMessage(this.text.groupCount, op.allowed_groups?.length ?? 0, this.messages.meta.locale);
567
+ }
529
568
  ngOnChanges(changes) { if (changes['appId']) {
530
569
  this.load();
531
570
  } }
@@ -544,20 +583,16 @@ class AutoServiceAppOperationsComponent {
544
583
  this.cdr.markForCheck();
545
584
  }
546
585
  }
547
- /** Nível da operação no selo: pública em verde, protegida em amarelo; o resto neutro. */
586
+ /** Mesma cor de nível do drawer de permissões e do painel do Argos (`levelTagColor`). */
548
587
  levelTagColor(level) {
549
- if (level === 'public')
550
- return 'success';
551
- if (level === 'protected')
552
- return 'warning';
553
- return 'neutral';
588
+ return levelTagColor(level);
554
589
  }
555
590
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppOperationsComponent, deps: [{ token: AutoServiceService }], target: i0.ɵɵFactoryTarget.Component }); }
556
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppOperationsComponent, isStandalone: true, selector: "spine-auto-service-app-operations", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"operations\"\n [rowId]=\"rowId\"\n [caption]=\"text.operationsCaption\"\n [loading]=\"loading\"\n [emptyMessage]=\"text.noOperations\"\n>\n <ng-template hmCell=\"identifier\" let-op>\n <code>{{ op.identifier }}</code>\n </ng-template>\n\n <ng-template hmCell=\"method\" let-op>\n <hm-tag [name]=\"op.method\" />\n </ng-template>\n\n <ng-template hmCell=\"level\" let-op>\n <hm-tag [name]=\"op.level\" [color]=\"levelTagColor(op.level)\" />\n </ng-template>\n</hm-data-grid>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
591
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppOperationsComponent, isStandalone: true, selector: "spine-auto-service-app-operations", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"operations\"\n [rowId]=\"rowId\"\n [caption]=\"text.operationsCaption\"\n [loading]=\"loading\"\n [emptyMessage]=\"text.noOperations\"\n>\n <ng-template hmCell=\"identifier\" let-op>\n <code>{{ op.identifier }}</code>\n </ng-template>\n\n <ng-template hmCell=\"level\" let-op>\n <hm-tag [name]=\"op.level\" [color]=\"levelTagColor(op.level)\" />\n </ng-template>\n\n <ng-template hmCell=\"allowed_groups\" let-op>\n <hm-tag *ngIf=\"op.allowed_groups?.length; else noGroups\" [name]=\"groupCount(op)\" color=\"info\" />\n <ng-template #noGroups><span class=\"muted\">\u2014</span></ng-template>\n </ng-template>\n</hm-data-grid>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
557
592
  }
558
593
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppOperationsComponent, decorators: [{
559
594
  type: Component,
560
- args: [{ selector: 'spine-auto-service-app-operations', standalone: true, imports: [CommonModule, DataGridComponent, DataGridCellDirective, TagComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"operations\"\n [rowId]=\"rowId\"\n [caption]=\"text.operationsCaption\"\n [loading]=\"loading\"\n [emptyMessage]=\"text.noOperations\"\n>\n <ng-template hmCell=\"identifier\" let-op>\n <code>{{ op.identifier }}</code>\n </ng-template>\n\n <ng-template hmCell=\"method\" let-op>\n <hm-tag [name]=\"op.method\" />\n </ng-template>\n\n <ng-template hmCell=\"level\" let-op>\n <hm-tag [name]=\"op.level\" [color]=\"levelTagColor(op.level)\" />\n </ng-template>\n</hm-data-grid>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"] }]
595
+ args: [{ selector: 'spine-auto-service-app-operations', standalone: true, imports: [CommonModule, DataGridComponent, DataGridCellDirective, TagComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"operations\"\n [rowId]=\"rowId\"\n [caption]=\"text.operationsCaption\"\n [loading]=\"loading\"\n [emptyMessage]=\"text.noOperations\"\n>\n <ng-template hmCell=\"identifier\" let-op>\n <code>{{ op.identifier }}</code>\n </ng-template>\n\n <ng-template hmCell=\"level\" let-op>\n <hm-tag [name]=\"op.level\" [color]=\"levelTagColor(op.level)\" />\n </ng-template>\n\n <ng-template hmCell=\"allowed_groups\" let-op>\n <hm-tag *ngIf=\"op.allowed_groups?.length; else noGroups\" [name]=\"groupCount(op)\" color=\"info\" />\n <ng-template #noGroups><span class=\"muted\">\u2014</span></ng-template>\n </ng-template>\n</hm-data-grid>\n", styles: [".as-stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.as-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--hm-space-xs)}.as-field-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hm-space-sm)}.as-field-row>hm-combobox{flex:1 1 16rem;min-inline-size:0}.as-summary{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}.as-summary__info{display:flex;flex:1 1 16rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.as-summary__title{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs);margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.as-summary__detail{margin:0;color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.muted{color:var(--hm-muted)}.as-empty{margin:var(--hm-space-xs) 0 0;font-size:var(--hm-font-size-sm)}.as-secret{display:grid;gap:var(--hm-space-micro)}.as-secret__label{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.as-secret__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-xs)}.as-secret__value{flex:1 1 240px;min-width:0;border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-control);padding:var(--hm-space-xs) var(--hm-space-sm);background:var(--hm-surface);color:var(--hm-text);font-family:var(--hm-font-mono);font-size:var(--hm-font-size-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}:host{display:block}\n"] }]
561
596
  }], ctorParameters: () => [{ type: AutoServiceService }], propDecorators: { clientId: [{
562
597
  type: Input
563
598
  }], appId: [{
@@ -743,7 +778,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
743
778
 
744
779
  /**
745
780
  * Aba Tokens da aplicação: os tokens de API (`x-api-token`) com situação, validade e último uso; "Novo token" (modal com
746
- * as operações liberadas) e, no menu da linha, "Gerenciar operações" (o token também é um consumer) e "Revogar" (com
781
+ * as operações liberadas), o botão "Gerenciar operações" na linha (o token também é um consumer) e, no menu, "Revogar" (com
747
782
  * confirmação; o token para de valer na hora e fica na lista como revogado).
748
783
  * Mirror de admin/ui/.../apps/tabs/app-tokens (argos-admin), escopado em `/auto-service/:clientId`.
749
784
  */
@@ -770,12 +805,13 @@ class AutoServiceAppTokensComponent {
770
805
  { key: 'status', title: this.text.colStatus, value: (tk) => this.statusLabel(this.status(tk)), sortable: true },
771
806
  { key: 'expires_at', title: this.text.colExpiresAt, value: (tk) => tk.expires_at ?? '', sortable: true },
772
807
  { key: 'last_used_at', title: this.text.colLastUsed, value: (tk) => tk.last_used_at ?? '', sortable: true },
808
+ // Como no painel do Argos: "Gerenciar operações" é um botão na linha (token revogado mostra "—").
809
+ { key: 'operations', title: this.text.colOperations, value: () => '' },
773
810
  ], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
774
811
  // Revogado não tem mais o que fazer: a linha fica sem o menu.
775
812
  this.rowActions = computed(() => [
776
- { id: 'operations', icon: 'shield', label: this.text.manageOperations, available: (tk) => !tk.revoked_at },
777
813
  {
778
- id: 'revoke', icon: 'ban', label: this.text.revokeToken, danger: true, separatorAbove: true,
814
+ id: 'revoke', icon: 'ban', label: this.text.revokeToken, danger: true,
779
815
  available: (tk) => !tk.revoked_at,
780
816
  confirm: (tk) => ({
781
817
  heading: this.text.confirmRevokeTokenHeading,
@@ -858,20 +894,18 @@ class AutoServiceAppTokensComponent {
858
894
  await this.load();
859
895
  }
860
896
  onAction(e) {
861
- if (e.action === 'operations')
862
- this.openPermissions(e.row);
863
897
  if (e.action === 'revoke')
864
898
  void this.revoke(e.row);
865
899
  }
866
900
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppTokensComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
867
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppTokensComponent, isStandalone: true, selector: "spine-auto-service-app-tokens", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"tokens\"\n [rowId]=\"rowId\"\n [caption]=\"text.tokensCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n [emptyMessage]=\"text.noTokens\"\n (actionTriggered)=\"onAction($event)\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newToken }}</hm-button>\n <ng-template hmCell=\"prefix\" let-tk>\n <code *ngIf=\"tk.token_prefix; else noPrefix\">{{ tk.token_prefix }}\u2026</code>\n <ng-template #noPrefix>\u2014</ng-template>\n </ng-template>\n <ng-template hmCell=\"status\" let-tk>\n <hm-tag [name]=\"statusLabel(status(tk))\" [color]=\"statusColor(status(tk))\" />\n </ng-template>\n <ng-template hmCell=\"expires_at\" let-tk>{{ formatDate(tk.expires_at) || '\u2014' }}</ng-template>\n <ng-template hmCell=\"last_used_at\" let-tk>{{ tk.last_used_at ? formatDate(tk.last_used_at) : text.neverUsed }}</ng-template>\n</hm-data-grid>\n\n<spine-auto-service-token-create [clientId]=\"clientId\" [appId]=\"appId\" [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\" (created)=\"load()\">\n</spine-auto-service-token-create>\n\n<spine-auto-service-consumer-permissions *ngIf=\"permissionsConsumer as consumer\" [clientId]=\"clientId\" [appId]=\"appId\"\n [consumer]=\"consumer\" mode=\"token\" [open]=\"showPermissions\" (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { 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: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }, { kind: "component", type: AutoServiceTokenCreateComponent, selector: "spine-auto-service-token-create", inputs: ["clientId", "appId", "open"], outputs: ["openChange", "created"] }, { kind: "component", type: AutoServiceConsumerPermissionsComponent, selector: "spine-auto-service-consumer-permissions", inputs: ["clientId", "appId", "consumer", "mode", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
901
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceAppTokensComponent, isStandalone: true, selector: "spine-auto-service-app-tokens", inputs: { clientId: "clientId", appId: "appId" }, usesOnChanges: true, ngImport: i0, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"tokens\"\n [rowId]=\"rowId\"\n [caption]=\"text.tokensCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n [emptyMessage]=\"text.noTokens\"\n (actionTriggered)=\"onAction($event)\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newToken }}</hm-button>\n <ng-template hmCell=\"prefix\" let-tk>\n <code *ngIf=\"tk.token_prefix; else noPrefix\">{{ tk.token_prefix }}\u2026</code>\n <ng-template #noPrefix>\u2014</ng-template>\n </ng-template>\n <ng-template hmCell=\"status\" let-tk>\n <hm-tag [name]=\"statusLabel(status(tk))\" [color]=\"statusColor(status(tk))\" />\n </ng-template>\n <ng-template hmCell=\"expires_at\" let-tk>{{ formatDate(tk.expires_at) || '\u2014' }}</ng-template>\n <ng-template hmCell=\"last_used_at\" let-tk>{{ tk.last_used_at ? formatDate(tk.last_used_at) : text.neverUsed }}</ng-template>\n <ng-template hmCell=\"operations\" let-tk>\n <hm-button *ngIf=\"!tk.revoked_at; else revokedOps\" emphasis=\"minimal\" icon=\"shield\" (clicked)=\"openPermissions(tk)\">{{ text.manageOperations }}</hm-button>\n <ng-template #revokedOps><span class=\"muted\">\u2014</span></ng-template>\n </ng-template>\n</hm-data-grid>\n\n<spine-auto-service-token-create [clientId]=\"clientId\" [appId]=\"appId\" [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\" (created)=\"load()\">\n</spine-auto-service-token-create>\n\n<spine-auto-service-consumer-permissions *ngIf=\"permissionsConsumer as consumer\" [clientId]=\"clientId\" [appId]=\"appId\"\n [consumer]=\"consumer\" mode=\"token\" [open]=\"showPermissions\" (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { 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: TagComponent, selector: "hm-tag", inputs: ["name", "color", "compact"] }, { kind: "component", type: AutoServiceTokenCreateComponent, selector: "spine-auto-service-token-create", inputs: ["clientId", "appId", "open"], outputs: ["openChange", "created"] }, { kind: "component", type: AutoServiceConsumerPermissionsComponent, selector: "spine-auto-service-consumer-permissions", inputs: ["clientId", "appId", "consumer", "mode", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
868
902
  }
869
903
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceAppTokensComponent, decorators: [{
870
904
  type: Component,
871
905
  args: [{ selector: 'spine-auto-service-app-tokens', standalone: true, imports: [
872
906
  CommonModule, ButtonComponent, DataGridComponent, DataGridCellDirective, TagComponent,
873
907
  AutoServiceTokenCreateComponent, AutoServiceConsumerPermissionsComponent,
874
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"tokens\"\n [rowId]=\"rowId\"\n [caption]=\"text.tokensCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n [emptyMessage]=\"text.noTokens\"\n (actionTriggered)=\"onAction($event)\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newToken }}</hm-button>\n <ng-template hmCell=\"prefix\" let-tk>\n <code *ngIf=\"tk.token_prefix; else noPrefix\">{{ tk.token_prefix }}\u2026</code>\n <ng-template #noPrefix>\u2014</ng-template>\n </ng-template>\n <ng-template hmCell=\"status\" let-tk>\n <hm-tag [name]=\"statusLabel(status(tk))\" [color]=\"statusColor(status(tk))\" />\n </ng-template>\n <ng-template hmCell=\"expires_at\" let-tk>{{ formatDate(tk.expires_at) || '\u2014' }}</ng-template>\n <ng-template hmCell=\"last_used_at\" let-tk>{{ tk.last_used_at ? formatDate(tk.last_used_at) : text.neverUsed }}</ng-template>\n</hm-data-grid>\n\n<spine-auto-service-token-create [clientId]=\"clientId\" [appId]=\"appId\" [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\" (created)=\"load()\">\n</spine-auto-service-token-create>\n\n<spine-auto-service-consumer-permissions *ngIf=\"permissionsConsumer as consumer\" [clientId]=\"clientId\" [appId]=\"appId\"\n [consumer]=\"consumer\" mode=\"token\" [open]=\"showPermissions\" (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [":host{display:block}\n"] }]
908
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-data-grid\n [columns]=\"columns()\"\n [rows]=\"tokens\"\n [rowId]=\"rowId\"\n [caption]=\"text.tokensCaption\"\n [loading]=\"loading\"\n [rowActions]=\"rowActions()\"\n [emptyMessage]=\"text.noTokens\"\n (actionTriggered)=\"onAction($event)\"\n>\n <hm-button dataGridActions icon=\"plus\" (clicked)=\"openCreate()\">{{ text.newToken }}</hm-button>\n <ng-template hmCell=\"prefix\" let-tk>\n <code *ngIf=\"tk.token_prefix; else noPrefix\">{{ tk.token_prefix }}\u2026</code>\n <ng-template #noPrefix>\u2014</ng-template>\n </ng-template>\n <ng-template hmCell=\"status\" let-tk>\n <hm-tag [name]=\"statusLabel(status(tk))\" [color]=\"statusColor(status(tk))\" />\n </ng-template>\n <ng-template hmCell=\"expires_at\" let-tk>{{ formatDate(tk.expires_at) || '\u2014' }}</ng-template>\n <ng-template hmCell=\"last_used_at\" let-tk>{{ tk.last_used_at ? formatDate(tk.last_used_at) : text.neverUsed }}</ng-template>\n <ng-template hmCell=\"operations\" let-tk>\n <hm-button *ngIf=\"!tk.revoked_at; else revokedOps\" emphasis=\"minimal\" icon=\"shield\" (clicked)=\"openPermissions(tk)\">{{ text.manageOperations }}</hm-button>\n <ng-template #revokedOps><span class=\"muted\">\u2014</span></ng-template>\n </ng-template>\n</hm-data-grid>\n\n<spine-auto-service-token-create [clientId]=\"clientId\" [appId]=\"appId\" [open]=\"showCreate\"\n (openChange)=\"showCreate = $event\" (created)=\"load()\">\n</spine-auto-service-token-create>\n\n<spine-auto-service-consumer-permissions *ngIf=\"permissionsConsumer as consumer\" [clientId]=\"clientId\" [appId]=\"appId\"\n [consumer]=\"consumer\" mode=\"token\" [open]=\"showPermissions\" (openChange)=\"showPermissions = $event\">\n</spine-auto-service-consumer-permissions>\n", styles: [":host{display:block}\n"] }]
875
909
  }], propDecorators: { clientId: [{
876
910
  type: Input
877
911
  }], appId: [{
@@ -1078,4 +1112,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
1078
1112
  }] });
1079
1113
 
1080
1114
  export { AutoServiceComponent };
1081
- //# sourceMappingURL=trismegisto-spine-auto-service-auto-service.component-D-N-xXPN.mjs.map
1115
+ //# sourceMappingURL=trismegisto-spine-auto-service-auto-service.component-C4FBAefe.mjs.map