@trismegisto/spine 3.3.2 → 3.3.3

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 (31) hide show
  1. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-mMjE3JOL.mjs +2179 -0
  2. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-mMjE3JOL.mjs.map +1 -0
  3. package/fesm2022/{trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs → trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs} +7 -4
  4. package/fesm2022/trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs.map +1 -0
  5. package/fesm2022/trismegisto-spine-auto-service.mjs +2 -2
  6. package/fesm2022/trismegisto-spine-graphql.mjs +3 -1
  7. package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -1
  8. package/fesm2022/trismegisto-spine-layout-suggestions-page.component-xI2gDMok.mjs +532 -0
  9. package/fesm2022/trismegisto-spine-layout-suggestions-page.component-xI2gDMok.mjs.map +1 -0
  10. package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-Clphrsgc.mjs +8429 -0
  11. package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-Clphrsgc.mjs.map +1 -0
  12. package/fesm2022/trismegisto-spine-layout.mjs +1 -7662
  13. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -1
  14. package/fesm2022/trismegisto-spine-notification.mjs +1 -1
  15. package/fesm2022/trismegisto-spine-notification.mjs.map +1 -1
  16. package/fesm2022/trismegisto-spine-routing.mjs +16 -3
  17. package/fesm2022/trismegisto-spine-routing.mjs.map +1 -1
  18. package/fesm2022/trismegisto-spine-shell.mjs +4 -2
  19. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -1
  20. package/fesm2022/trismegisto-spine.mjs +286 -29
  21. package/fesm2022/trismegisto-spine.mjs.map +1 -1
  22. package/package.json +6 -6
  23. package/types/trismegisto-spine-layout.d.ts +879 -17
  24. package/types/trismegisto-spine-layout.d.ts.map +1 -1
  25. package/types/trismegisto-spine-routing.d.ts.map +1 -1
  26. package/types/trismegisto-spine-shell.d.ts.map +1 -1
  27. package/types/trismegisto-spine.d.ts +130 -12
  28. package/types/trismegisto-spine.d.ts.map +1 -1
  29. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs +0 -2123
  30. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs.map +0 -1
  31. package/fesm2022/trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnDestroy, OnInit, InjectionToken, Type, Provider, TemplateRef } from '@angular/core';
2
+ import { OnDestroy, InjectionToken, Signal, OnInit, Type, Provider, TemplateRef, DestroyRef, EnvironmentProviders } from '@angular/core';
3
3
  import { Router } from '@angular/router';
4
4
  import * as _trismegisto_spine from '@trismegisto/spine';
5
5
  import { Route, ThemeService, ThemePresetService, DensityService, SpineConfig, SpinePreferencesService, SpineHourCyclePreference, SpineStartPagePreference, SpineNoticeType, SpineMcpServer, SpineFeatures } from '@trismegisto/spine';
@@ -239,12 +239,85 @@ declare class ShortcutService implements OnDestroy {
239
239
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShortcutService>;
240
240
  }
241
241
 
242
+ /** Query de uma aba, como objeto (o último valor de cada nome). */
243
+ type SpineTabParams = Readonly<Record<string, string>>;
244
+ /**
245
+ * A aba do workspace em que a tela está montada (`inject(SPINE_TAB)` na tela). Com o keepAlive, várias abas da MESMA
246
+ * tela ficam vivas ao mesmo tempo (um registro por aba); `window.location`/`ActivatedRoute` só refletem a aba do
247
+ * painel focado. Aqui cada tela lê e escreve a SUA.
248
+ *
249
+ * ```ts
250
+ * private readonly tab = inject(SPINE_TAB, { optional: true });
251
+ * readonly pedido = computed(() => this.tab?.params()['pedido'] ?? null);
252
+ * // trocar a seção: a mesma aba, sem recriar a tela (e o endereço do navegador acompanha, se a aba está à vista)
253
+ * this.tab?.navigate({ queryParams: { secao: 'itens' } });
254
+ * // o nome do registro no lugar do nome da rota
255
+ * this.tab?.setLabel('Pedido 123');
256
+ * ```
257
+ */
258
+ interface SpineTab {
259
+ /** Identidade estável da aba (o caminho, ou o caminho com os parâmetros que a identificam). */
260
+ readonly id: Signal<string>;
261
+ /** O painel em que a aba está agora. */
262
+ readonly panelId: Signal<string>;
263
+ /** O endereço atual da aba, com a query. */
264
+ readonly url: Signal<string>;
265
+ /** A query da aba. */
266
+ readonly params: Signal<SpineTabParams>;
267
+ /** A aba é a visível do painel focado (é a que o endereço do navegador mostra). */
268
+ readonly focused: Signal<boolean>;
269
+ /** Troca o nome (e, se vier, o ícone) da aba; persiste no F5 nas abas com parâmetros. */
270
+ setLabel(label: string, icon?: string): void;
271
+ /**
272
+ * Muda o endereço da própria aba. Com `queryParams`, mescla na query atual (`merge`, padrão) ou troca a query
273
+ * inteira (`merge: false`); `null`/`undefined` tira o parâmetro. Mesma tela: só a query muda, a tela não é recriada.
274
+ * Outra tela (um caminho diferente): é a navegação no lugar da aba, como um link dentro do painel.
275
+ */
276
+ navigate(target: string | {
277
+ queryParams: Readonly<Record<string, string | number | boolean | null | undefined>>;
278
+ merge?: boolean;
279
+ }): void;
280
+ }
281
+ declare const SPINE_TAB: InjectionToken<SpineTab>;
282
+
283
+ /** O caminho de um endereço (sem query nem fragmento). */
284
+ declare function spinePathOf(url: string): string;
285
+ /** A query de um endereço, como objeto. */
286
+ declare function spineParamsOf(url: string): SpineTabParams;
287
+ /** Caminho + query com os nomes em ordem: o mesmo endereço escrito de dois jeitos vira um só (sem o fragmento). */
288
+ declare function spineNormalizeUrl(url: string): string;
289
+ /** Como abrir uma aba pelo app (`openTab`). */
290
+ interface SpineOpenTabOptions {
291
+ /** Nome da aba (senão, o da rota). A tela pode trocar depois (`SPINE_TAB.setLabel`). */
292
+ label?: string;
293
+ icon?: string;
294
+ /**
295
+ * Os parâmetros que IDENTIFICAM a aba: com `['dispositivo']`, o mesmo dispositivo em outra seção reaproveita a aba
296
+ * aberta, e trocar a seção dentro dela não abre outra. Sem `match`, todos os parâmetros do endereço identificam.
297
+ */
298
+ match?: readonly string[];
299
+ /** Abre num painel novo ao lado do focado (para comparar), em vez de no próprio painel focado. */
300
+ beside?: boolean;
301
+ }
242
302
  /**
243
303
  * Dono do `WorkspaceStore` do shell — mesmo padrão do `WorkspaceNavService` do docs/website
244
304
  * (`packages/hermes-ui/docs/website/src/app/workspace-nav.service.ts`), adaptado pra ler a
245
305
  * árvore de rotas do BACKEND (`ViewService.currentView`) em vez de um `page-registry.ts`
246
306
  * estático. Cada página visitada vira uma aba, pertencente a um painel; a navegação real do
247
307
  * `Router` (routerLink, busca, sidebar) sempre atualiza a aba ativa do painel FOCADO.
308
+ *
309
+ * **Dois jeitos de ter aba, que convivem.** A navegação de sempre (menu, links, busca) mantém UMA aba por tela, com o
310
+ * caminho como `id` — como antes; a query que a tela usa fica guardada no `url` da aba e volta junto quando a pessoa
311
+ * retorna a ela. E o app pode abrir **abas com parâmetros** (`openTab`): a mesma tela várias vezes, uma por registro
312
+ * (um pedido, um dispositivo...). Nelas o `id` é a identidade (o caminho com os parâmetros que a identificam) e o `url`
313
+ * é o endereço atual (com a query que a tela vai mudando).
314
+ * O keepAlive do workspace acompanha o `id`, então mudar a query da aba não recria a tela. Uma navegação real cai
315
+ * numa destas, em ordem:
316
+ * 1. o endereço já é o da aba ativa → nada;
317
+ * 2. a mesma tela da aba ativa, mantendo os parâmetros que a identificam → só o `url` da aba muda (mesma aba);
318
+ * 3. outra aba do painel já está nesse endereço → ela é ativada;
319
+ * 4. senão → a aba ativa passa a ser a da tela nova (o comportamento de sempre).
320
+ * `openTab` abre (ou foca, em qualquer painel) a aba de um endereço com parâmetros.
248
321
  */
249
322
  declare class SpineWorkspaceNavService {
250
323
  private readonly router;
@@ -258,22 +331,51 @@ declare class SpineWorkspaceNavService {
258
331
  * `viewService.logControl$`/`breadCrumb$` globais (que só existiam porque havia uma página
259
332
  * "atual" só; agora cada painel tem a sua). */
260
333
  readonly focusedChain: _angular_core.Signal<Route[] | null>;
261
- private lastKnownPath;
334
+ /** O último endereço que o `Router` mostrou (normalizado, com a query): o `effect` abaixo não navega para ele de novo. */
335
+ private lastKnownUrl;
262
336
  constructor();
337
+ private activeTab;
338
+ /** Uma navegação real no painel focado: as quatro regras do comentário da classe. */
339
+ private followNavigation;
263
340
  /**
264
341
  * As abas abertas passam a obedecer à view atual: aba de tela que a pessoa não pode mais abrir fecha (e o
265
342
  * conteúdo dela é destruído junto); painel que ficaria sem aba nenhuma mostra o Início no lugar; a aba ativa
266
- * de cada painel recebe o nome e o ícone da view nova. View vazia (ainda carregando) não fecha nada.
343
+ * de cada painel recebe o nome e o ícone da view nova (a aba com parâmetros guarda o nome que a tela deu). View
344
+ * vazia (ainda carregando) não fecha nada.
267
345
  */
268
346
  reconcileWithView(): void;
269
347
  /** Resolve a cadeia de rotas pra uma URL, direto na view atual — sem `Router`, sem `async`
270
348
  * (o componente da folha só é carregado por quem for de fato desenhar o painel). Desce sozinho
271
349
  * por nós organizacionais (com filhos, sem conteúdo próprio) — o rótulo/ícone da aba e o que a
272
- * sidebar/breadcrumb mostram refletem o destino DE VERDADE, não a rota-container clicada. */
350
+ * sidebar/breadcrumb mostram refletem o destino DE VERDADE, não a rota-container clicada. A query não
351
+ * conta: `ViewService.routePath` a tira. */
273
352
  private chainFor;
353
+ /** A aba de uma tela pelo endereço: o `id` é o caminho; com query, o endereço vai no `url` (a mesma aba da tela). */
274
354
  tabFor(url: string): TabItem;
355
+ /**
356
+ * Restaura uma aba salva (F5): a rota precisa continuar valendo para a pessoa. A aba com parâmetros volta com o
357
+ * endereço e o nome que tinha (o nome é o que a tela deu — "RT-MPLS-3046-0001" —, a rota não sabe); as outras
358
+ * voltam com o nome da rota (que acompanha o idioma).
359
+ */
360
+ private restoreTab;
275
361
  /** O `+` de um painel: abre a home ali, como um navegador. */
276
362
  openNewTab(panelId: string): void;
363
+ /**
364
+ * Abre (ou foca) a aba de um endereço com parâmetros — um registro por aba na mesma tela:
365
+ * `openTab('/vendas/pedidos?pedido=123&secao=itens', { label: 'Pedido 123', match: ['pedido'] })`.
366
+ * Se alguma aba (em qualquer painel) já tem essa identidade, ela é focada e passa a esse endereço; senão abre uma
367
+ * no painel focado (ou num painel novo ao lado, com `beside`). Só abre o que a view da pessoa permite (a mesma
368
+ * regra do menu e do `ViewGuard`); fora dela, não faz nada.
369
+ */
370
+ openTab(url: string, options?: SpineOpenTabOptions): void;
371
+ /** O nome (e o ícone) de uma aba, dado pela tela (`SPINE_TAB.setLabel`). */
372
+ setTabLabel(panelId: string, tabId: string, label: string, icon?: string): void;
373
+ /**
374
+ * A tela muda o endereço da própria aba (`SPINE_TAB.navigate`). A mesma tela, mantendo a identidade: só o `url` da
375
+ * aba muda (sem recriar a tela) e, se ela é a visível do painel focado, o endereço do navegador acompanha (sem
376
+ * empilhar histórico). Outra tela: navegação local no painel, como um link dentro dele.
377
+ */
378
+ navigateTab(panelId: string, tabId: string, url: string): void;
277
379
  /** Navegação LOCAL a um painel específico (usada pelo `PanelLocalLinkDirective`) — troca o
278
380
  * ASSUNTO da aba ativa daquele painel, não empilha uma aba nova. */
279
381
  navigateLocally(panelId: string, href: string): void;
@@ -2779,6 +2881,132 @@ declare class SpinePageActionsDirective implements OnDestroy {
2779
2881
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SpinePageActionsDirective, "ng-template[spinePageActions]", never, {}, {}, never, never, true, never>;
2780
2882
  }
2781
2883
 
2884
+ /** Uma novidade na central de notificações (o sino do cabeçalho). */
2885
+ interface SpineInboxItem {
2886
+ /** Único dentro da fonte. */
2887
+ readonly id: string;
2888
+ readonly title: string;
2889
+ /** A novidade em uma linha ("Ana: pode mandar um exemplo?"). */
2890
+ readonly body?: string;
2891
+ /** Quando aconteceu (a novidade mais recente do item): ordena a lista e vira "há 5 min". */
2892
+ readonly at: string | Date;
2893
+ /** Quantas novidades o item junta (mostra "+N" a partir de 2). */
2894
+ readonly count?: number;
2895
+ /** Quem fez: a foto (ou as iniciais) na linha; sem pessoa, o ícone da fonte. */
2896
+ readonly person?: {
2897
+ readonly name: string;
2898
+ readonly picture?: string | null;
2899
+ } | null;
2900
+ }
2901
+ /**
2902
+ * Uma fonte da central de notificações: o que há de novo PARA a pessoa num recurso (sugestões, aprovações, chamados…).
2903
+ * Não são os toasts (`HermesToastService`/`NotificationService`), que passam: aqui fica até a pessoa ver. Registre com
2904
+ * `provideSpineInboxSource`; o sino só aparece com alguma fonte.
2905
+ */
2906
+ interface SpineInboxSource {
2907
+ readonly id: string;
2908
+ /** O nome da fonte ("Sugestões"), acima dos itens dela. */
2909
+ readonly label: string;
2910
+ /** Ícone da fonte (@trismegisto/icons), nos itens sem pessoa. */
2911
+ readonly icon?: string;
2912
+ /** As novidades (as mais recentes, até umas 20) e o total de itens com novidade (o número do sino). */
2913
+ load(): Promise<{
2914
+ readonly items: readonly SpineInboxItem[];
2915
+ readonly total: number;
2916
+ }>;
2917
+ /** A pessoa escolheu o item: marque como visto e abra onde ele está. A central relê depois. */
2918
+ open(item: SpineInboxItem): void | Promise<void>;
2919
+ }
2920
+ /** As fontes registradas (multi). Uma fábrica pode devolver `null` (recurso desligado): fica de fora. */
2921
+ declare const SPINE_INBOX_SOURCES: InjectionToken<readonly (SpineInboxSource | null)[]>;
2922
+ /**
2923
+ * Registra uma fonte na central de notificações. A fábrica roda num contexto de injeção (`inject()` vale) e pode
2924
+ * devolver `null` para não registrar nada.
2925
+ *
2926
+ * ```ts
2927
+ * provideSpineInboxSource(() => {
2928
+ * const api = inject(AprovacoesApi);
2929
+ * const router = inject(Router);
2930
+ * return {
2931
+ * id: 'aprovacoes', label: 'Aprovações', icon: 'check-circle',
2932
+ * load: async () => { const r = await api.pendentes(); return { total: r.total, items: r.itens.map(toItem) }; },
2933
+ * open: (item) => void router.navigateByUrl(`/aprovacoes/${item.id}`),
2934
+ * };
2935
+ * })
2936
+ * ```
2937
+ */
2938
+ declare function provideSpineInboxSource(factory: () => SpineInboxSource | null): Provider;
2939
+
2940
+ /** Um item na lista do sino, com a fonte dele. */
2941
+ interface SpineInboxEntry {
2942
+ /** `fonte:item`, único na lista. */
2943
+ readonly key: string;
2944
+ readonly source: SpineInboxSource;
2945
+ readonly item: SpineInboxItem;
2946
+ }
2947
+ /** De quanto em quanto tempo a central relê, com a aba do navegador à vista. */
2948
+ declare const SPINE_INBOX_POLL_MS = 60000;
2949
+ /**
2950
+ * A central de notificações (o sino do cabeçalho): junta as novidades das fontes registradas
2951
+ * (`provideSpineInboxSource`), a mais recente primeiro. Relê enquanto alguém acompanha (`watch`): de minuto em minuto
2952
+ * com a aba à vista e ao voltar para ela. Quem muda o que conta como novidade (ler uma conversa, por exemplo) chama
2953
+ * `refresh()`.
2954
+ */
2955
+ declare class SpineInboxService {
2956
+ private readonly browser;
2957
+ private readonly sources;
2958
+ /** Alguma fonte registrada: sem nenhuma, o sino não aparece. */
2959
+ readonly enabled: boolean;
2960
+ readonly entries: _angular_core.WritableSignal<readonly SpineInboxEntry[]>;
2961
+ /** Itens com novidade, somando as fontes (o número do sino). */
2962
+ readonly total: _angular_core.WritableSignal<number>;
2963
+ readonly loading: _angular_core.WritableSignal<boolean>;
2964
+ /** Nenhuma fonte respondeu na última leitura. */
2965
+ readonly failed: _angular_core.WritableSignal<boolean>;
2966
+ private request;
2967
+ private watchers;
2968
+ private timer;
2969
+ private readonly onVisible;
2970
+ /** Relê todas as fontes. Uma fonte que falha não derruba as outras. */
2971
+ refresh(): Promise<void>;
2972
+ /** A pessoa escolheu um item: a fonte abre (e marca como visto); depois a central relê. */
2973
+ open(entry: SpineInboxEntry): Promise<void>;
2974
+ /**
2975
+ * Passa a reler sozinha enquanto `destroyRef` viver (o sino no cabeçalho): lê agora, de minuto em minuto com a aba à
2976
+ * vista e ao voltar para a aba. Vários acompanhando dividem o mesmo relógio.
2977
+ */
2978
+ watch(destroyRef: DestroyRef): void;
2979
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SpineInboxService, never>;
2980
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<SpineInboxService>;
2981
+ }
2982
+
2983
+ /**
2984
+ * O sino do cabeçalho: a central de notificações (`SpineInboxService`). O número é quantos itens têm novidade; o
2985
+ * painel lista as novidades das fontes, a mais recente primeiro, e escolher uma abre onde ela está. Sem fonte
2986
+ * registrada, não desenha nada.
2987
+ */
2988
+ declare class SpineInboxButtonComponent {
2989
+ protected readonly inbox: SpineInboxService;
2990
+ private readonly messages;
2991
+ protected readonly text: {
2992
+ title: string;
2993
+ button: _trismegisto_primitives.PluralMessage;
2994
+ empty: string;
2995
+ error: string;
2996
+ retry: string;
2997
+ news: _trismegisto_primitives.PluralMessage;
2998
+ };
2999
+ protected readonly buttonLabel: _angular_core.Signal<string>;
3000
+ constructor();
3001
+ protected choose(entry: SpineInboxEntry): void;
3002
+ protected newsText(count: number): string;
3003
+ protected iso(entry: SpineInboxEntry): string;
3004
+ /** "há 5 min", "ontem", "há 3 dias" (Intl, no idioma do catálogo). */
3005
+ protected ago(entry: SpineInboxEntry): string;
3006
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SpineInboxButtonComponent, never>;
3007
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SpineInboxButtonComponent, "spine-inbox-button", never, {}, {}, never, never, true, never>;
3008
+ }
3009
+
2782
3010
  /** Tipos de sugestão, como o Argos guarda (`web.app_suggestions.kind`). */
2783
3011
  declare const SPINE_SUGGESTION_KINDS: readonly ["melhoria", "nova_funcionalidade", "problema", "outro"];
2784
3012
  type SpineSuggestionKind = (typeof SPINE_SUGGESTION_KINDS)[number];
@@ -2822,10 +3050,7 @@ interface SpineSuggestion {
2822
3050
  kind: SpineSuggestionKind;
2823
3051
  title: string;
2824
3052
  description: string;
2825
- screen: {
2826
- path: string | null;
2827
- label: string | null;
2828
- };
3053
+ screen: SpineSuggestionScreen;
2829
3054
  status: SpineSuggestionStatus;
2830
3055
  position: number;
2831
3056
  votes: number;
@@ -2838,6 +3063,9 @@ interface SpineSuggestion {
2838
3063
  } | null;
2839
3064
  /** Desde quando está no status atual (o último evento para ele; sem evento, a criação). */
2840
3065
  status_at?: string;
3066
+ /** Com quem está a vez na conversa (null = em dia). */
3067
+ waiting_on?: SpineSuggestionWaiting | null;
3068
+ waiting_since?: string | null;
2841
3069
  created_at: string;
2842
3070
  updated_at: string;
2843
3071
  /** Só no auto-serviço: quem pediu, com a foto (null = pessoa removida). */
@@ -2864,10 +3092,7 @@ interface SpineAppSuggestion {
2864
3092
  title: string;
2865
3093
  /** Texto puro (a descrição inteira, até 4000). */
2866
3094
  description: string;
2867
- screen: {
2868
- path: string | null;
2869
- label: string | null;
2870
- };
3095
+ screen: SpineSuggestionScreen;
2871
3096
  status: SpineSuggestionStatus;
2872
3097
  votes: number;
2873
3098
  /** Quem consulta apoia. */
@@ -2904,17 +3129,124 @@ interface SpineAppSuggestionsQuery {
2904
3129
  interface SpineSuggestionDraft {
2905
3130
  kind: SpineSuggestionKind;
2906
3131
  title: string;
2907
- description: string;
3132
+ /** Texto puro (o formato antigo; o servidor ainda aceita). */
3133
+ description?: string;
3134
+ /** A descrição em rich text (o editor do modal); o servidor saneia e deriva o texto puro. */
3135
+ description_html?: string;
3136
+ /** Tela do menu (`router_id` e a rota) ou `new: true` com o nome da tela que ainda não existe em `label`. */
2908
3137
  screen: {
2909
3138
  path: string | null;
2910
3139
  label: string | null;
3140
+ router_id?: string | null;
3141
+ new?: boolean;
2911
3142
  };
2912
3143
  }
3144
+ /** Por que a pessoa vê a sugestão (o servidor decide; uma sugestão pode ter vários). */
3145
+ declare const SPINE_SUGGESTION_REASONS: readonly ["autor", "relator", "envolvido", "responsavel", "grupo"];
3146
+ type SpineSuggestionReason = (typeof SPINE_SUGGESTION_REASONS)[number];
3147
+ /** Com quem está a vez na conversa: quem pediu (a equipe respondeu) ou a equipe (quem pediu escreveu). */
3148
+ declare const SPINE_SUGGESTION_WAITING: readonly ["solicitante", "responsaveis"];
3149
+ type SpineSuggestionWaiting = (typeof SPINE_SUGGESTION_WAITING)[number];
3150
+ /** Cor do selo "Aguardando…": a vez de quem pede chama atenção; a da equipe, não. */
3151
+ declare const SPINE_SUGGESTION_WAITING_COLORS: Record<SpineSuggestionWaiting, TagColor>;
3152
+ declare const SPINE_SUGGESTION_VISIBLE_SORTS: readonly ["activity", "recent", "votes"];
3153
+ type SpineSuggestionVisibleSort = (typeof SPINE_SUGGESTION_VISIBLE_SORTS)[number];
3154
+ /** A tela de uma sugestão: a do menu (`router_id`, rota e o caminho legível) ou uma nova (`new`, o nome no `label`). */
3155
+ interface SpineSuggestionScreen {
3156
+ path: string | null;
3157
+ label: string | null;
3158
+ router_id?: string | null;
3159
+ new?: boolean;
3160
+ }
3161
+ /**
3162
+ * Uma sugestão que a pessoa VÊ (`/me/suggestions/visible` e o detalhe): as dela, as do grupo dela e as em que ela está
3163
+ * envolvida, com os motivos (`reasons`), se ela pode conversar (`can_comment`, quem tem motivo pessoal) e com quem está
3164
+ * a vez (`waiting_on`).
3165
+ */
3166
+ interface SpineVisibleSuggestion {
3167
+ id: string;
3168
+ key: string;
3169
+ kind: SpineSuggestionKind;
3170
+ title: string;
3171
+ description: string;
3172
+ /** A descrição em rich text (saneada pelo servidor); vazia sem descrição. */
3173
+ description_html?: string;
3174
+ screen: SpineSuggestionScreen;
3175
+ status: SpineSuggestionStatus;
3176
+ status_at?: string;
3177
+ votes: number;
3178
+ voted: boolean;
3179
+ mine: boolean;
3180
+ reasons: SpineSuggestionReason[];
3181
+ can_comment: boolean;
3182
+ waiting_on: SpineSuggestionWaiting | null;
3183
+ waiting_since: string | null;
3184
+ comments_count: number;
3185
+ last_comment: {
3186
+ comment: string;
3187
+ created_at: string;
3188
+ } | null;
3189
+ /** Mensagens de outras pessoas que quem consulta ainda não leu. */
3190
+ unread: number;
3191
+ archived: boolean;
3192
+ merged_from: Array<{
3193
+ id: string;
3194
+ key: string;
3195
+ title: string;
3196
+ }>;
3197
+ groups: Array<{
3198
+ id: string;
3199
+ name: string;
3200
+ }>;
3201
+ author: SpineSuggestionPerson | null;
3202
+ assignees: SpineSuggestionPerson[];
3203
+ created_at: string;
3204
+ updated_at: string;
3205
+ last_activity_at?: string;
3206
+ }
3207
+ /** Contagens do conjunto visível inteiro (sem os filtros), para os filtros rápidos da página. */
3208
+ type SpineVisibleCounts = Record<SpineSuggestionReason, number> & {
3209
+ waiting_me: number;
3210
+ unread: number;
3211
+ };
3212
+ interface SpineVisibleQuery {
3213
+ limit: number;
3214
+ offset: number;
3215
+ reason?: SpineSuggestionReason | '';
3216
+ status?: SpineSuggestionStatus | '';
3217
+ kind?: SpineSuggestionKind | '';
3218
+ waiting?: SpineSuggestionWaiting | '';
3219
+ screen?: string;
3220
+ newScreen?: boolean;
3221
+ q?: string;
3222
+ sort?: SpineSuggestionVisibleSort;
3223
+ }
3224
+ /** Mensagem da conversa (comentário público): `from_requester` = escrita por quem pediu ou um envolvido. */
3225
+ interface SpineSuggestionMessage extends SpineSuggestionComment {
3226
+ from_requester?: boolean;
3227
+ }
2913
3228
  /**
2914
3229
  * Sugestões de melhoria da pessoa — `argos-admin /me/suggestions`. Sempre da aplicação LOGADA (o servidor tira o client
2915
3230
  * do access-token da sessão) e com o token da sessão (o servidor recusa x-app-token). Sem `SPINE_ADMIN_API` não há
2916
3231
  * para onde mandar: o botão da barra da página nem aparece (`SpineSuggestButtonComponent`).
2917
3232
  */
3233
+ /** Uma sugestão acompanhada com novidade (`/me/suggestions/updates`): a central de notificações. */
3234
+ interface SpineSuggestionUpdate {
3235
+ id: string;
3236
+ key: string;
3237
+ title: string;
3238
+ status: SpineSuggestionStatus;
3239
+ /** Quantas novidades desde a última leitura (comentários públicos e mudanças de status de outras pessoas). */
3240
+ count: number;
3241
+ /** A mais recente: o comentário (até 200) ou o status novo, e quem fez. */
3242
+ last: {
3243
+ kind: 'comment' | 'status';
3244
+ status: SpineSuggestionStatus | null;
3245
+ comment: string | null;
3246
+ at: string;
3247
+ author: SpineSuggestionPerson | null;
3248
+ };
3249
+ }
2918
3250
  declare class SpineSuggestionsService {
2919
3251
  private readonly http;
2920
3252
  private readonly auth;
@@ -2935,14 +3267,36 @@ declare class SpineSuggestionsService {
2935
3267
  suggestions: SpineAppSuggestion[];
2936
3268
  total: number;
2937
3269
  }>;
2938
- /** Os comentários públicos de uma sugestão (o detalhe só de leitura), do mais novo. */
3270
+ /** Os comentários públicos de uma sugestão (a conversa), do mais novo. */
2939
3271
  comments(id: string, page: {
2940
3272
  limit: number;
2941
3273
  offset: number;
2942
3274
  }): Promise<{
2943
- comments: SpineSuggestionComment[];
3275
+ comments: SpineSuggestionMessage[];
3276
+ total: number;
3277
+ }>;
3278
+ /**
3279
+ * As que a pessoa vê (página "Sugestões do app"): as dela, as agrupadas, as em que está envolvida e as do grupo dela,
3280
+ * com filtros e paginação no servidor; `counts` é do conjunto inteiro (os números dos filtros rápidos).
3281
+ */
3282
+ visible(query: SpineVisibleQuery): Promise<{
3283
+ suggestions: SpineVisibleSuggestion[];
2944
3284
  total: number;
3285
+ counts: SpineVisibleCounts | null;
2945
3286
  }>;
3287
+ /** Uma que a pessoa vê, pelo id (404 se não vê). */
3288
+ get(id: string): Promise<SpineVisibleSuggestion>;
3289
+ /** Pela chave ("SUG-12"): o link "?sugestao=SUG-12" abre a sugestão na página. */
3290
+ lookup(key: string): Promise<SpineVisibleSuggestion>;
3291
+ /** Escreve na conversa (quem pediu ou um envolvido): a vez passa para os responsáveis. */
3292
+ reply(id: string, comment: string): Promise<SpineSuggestionMessage>;
3293
+ /** As que a pessoa acompanha com novidade, a mais recente primeiro; `total` = quantas têm novidade. */
3294
+ updates(limit?: number): Promise<{
3295
+ updates: SpineSuggestionUpdate[];
3296
+ total: number;
3297
+ }>;
3298
+ /** Marca a conversa como lida por quem consulta (zera o `unread`). */
3299
+ markRead(id: string): Promise<void>;
2946
3300
  /** As ainda abertas da tela, de qualquer pessoa: o modal oferece apoiar em vez de repetir. */
2947
3301
  byScreen(path: string): Promise<SpineSuggestion[]>;
2948
3302
  vote(id: string): Promise<void>;
@@ -2951,6 +3305,514 @@ declare class SpineSuggestionsService {
2951
3305
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<SpineSuggestionsService>;
2952
3306
  }
2953
3307
 
3308
+ /**
3309
+ * A página "Sugestões do app" de quem pede: uma página do PRÓPRIO spine (ver `registerSpineBuiltinPage`), em todo app
3310
+ * com sugestões ligadas, sem cadastro de rota por client. Abre como qualquer tela do workspace (aba, painel, F5, link).
3311
+ */
3312
+ declare const SPINE_SUGGESTIONS_PAGE_PATH = "/sugestoes";
3313
+ /** Chave sintética da página no distribuidor de telas (não é UUID: não colide com router do banco). */
3314
+ declare const SPINE_SUGGESTIONS_PAGE_ID = "spine:sugestoes";
3315
+ /** "?sugestao=SUG-12": abrir a página com ela abre a sugestão no painel (o mesmo parâmetro do quadro da equipe). */
3316
+ declare const SPINE_SUGGESTION_PAGE_PARAM = "sugestao";
3317
+ /** "&aba=conversa": junto com `sugestao`, abre a gaveta na Conversa (sem ele, em Detalhes). */
3318
+ declare const SPINE_SUGGESTION_TAB_PARAM = "aba";
3319
+ declare const SPINE_SUGGESTION_TAB_CONVERSATION = "conversa";
3320
+ /** Sugestões ligadas: o recurso não foi desligado (`SpineFeatures.suggestions`) e há para onde mandar (`SPINE_ADMIN_API`). */
3321
+ declare function spineSuggestionsEnabled(): boolean;
3322
+ /**
3323
+ * Registra a página no bootstrap (antes da primeira navegação: o F5 em /sugestoes passa pelo `ViewGuard`). Vai no
3324
+ * `provideShell`; com as sugestões desligadas, não registra nada e o endereço cai no fallback de sempre.
3325
+ */
3326
+ declare function provideSpineSuggestionsPage(): EnvironmentProviders;
3327
+
3328
+ /** Uma tela que dá para escolher no "Sugerir melhoria": a rota, o `router_id` e o caminho legível ("Módulo › Tela"). */
3329
+ interface SuggestionScreenOption {
3330
+ path: string;
3331
+ routerId: string | null;
3332
+ /** O nome da tela (o último nível). */
3333
+ name: string;
3334
+ /** O caminho inteiro, como a barra da página mostra ("Vendas › Pedidos › Consulta"): é o que vai para o `screen.label`. */
3335
+ label: string;
3336
+ icon: string;
3337
+ }
3338
+ /** Valor da opção "Nova tela" no seletor (não é rota: nenhuma rota começa sem "/"). */
3339
+ declare const NEW_SCREEN_VALUE = "nova-tela";
3340
+ /**
3341
+ * As telas que a pessoa alcança, da árvore de rotas que ela já recebe (`spineRoutesOf(view)`), na ordem do menu: cada
3342
+ * nó com endereço e nome, com o caminho dos ancestrais com endereço (o mesmo "Módulo › … › Tela" da barra da página).
3343
+ * Um endereço aparece uma vez só (o primeiro). Nó com endereço e filhos (módulo que também é página) entra.
3344
+ */
3345
+ declare function suggestionScreens(routes: readonly Route[] | null | undefined): SuggestionScreenOption[];
3346
+ /** O módulo (primeiro nível) de um caminho legível: "Vendas › Pedidos" → "Vendas". */
3347
+ declare function screenModule(label: string | null | undefined): string;
3348
+ /** O nome da tela (último nível) de um caminho legível: "Vendas › Pedidos › Consulta" → "Consulta". */
3349
+ declare function screenName(label: string | null | undefined): string;
3350
+
3351
+ /** De que lado da conversa a tela está: a de quem pede (página) ou a da equipe (detalhe da tarefa). */
3352
+ type SpineChatSide = 'solicitante' | 'equipe';
3353
+ /** Uma mensagem da conversa de uma sugestão, do jeito que o chat desenha (a página e o detalhe convertem para isto). */
3354
+ interface SpineChatMessage {
3355
+ id: string;
3356
+ text: string;
3357
+ created_at: string;
3358
+ author: SpineSuggestionPerson | null;
3359
+ /** Escrita como quem pede (pela página); `false` = como equipe (pelo detalhe da tarefa). */
3360
+ from_requester: boolean;
3361
+ /** Comentário interno da equipe (só aparece do lado da equipe). */
3362
+ internal?: boolean;
3363
+ /** A mudança de status que o comentário acompanha. */
3364
+ status?: SpineSuggestionStatus | null;
3365
+ }
3366
+ /** Uma linha do chat já resolvida: lado, cabeçalho, agrupamento e o divisor de dia antes dela. */
3367
+ interface ChatRow {
3368
+ message: SpineChatMessage;
3369
+ mine: boolean;
3370
+ author: string;
3371
+ grouped: boolean;
3372
+ day: string | null;
3373
+ }
3374
+ /**
3375
+ * A conversa de uma sugestão como chat (`hm-message-scroller` + `hm-message` + `hm-bubble`), com o campo de resposta
3376
+ * embaixo. Usado nos dois lados: a página de quem pede (`side="solicitante"`) e o detalhe da tarefa da equipe
3377
+ * (`side="equipe"`).
3378
+ *
3379
+ * **Quem fica à direita** é quem está com a tela aberta, no papel desta tela: a mensagem é da pessoa (`me`) E foi
3380
+ * escrita do mesmo lado (`from_requester` casa com `side`). A mesma pessoa no outro papel (quem administra e também
3381
+ * pediu, por exemplo) aparece à esquerda, como qualquer outro participante, com o papel no cabeçalho — a conversa
3382
+ * mostra de que lado cada mensagem foi escrita, não só quem a escreveu.
3383
+ *
3384
+ * - Mensagens do mais ANTIGO ao mais novo; o histórico mais antigo carrega pelo topo (`loadHistory`) sem tirar a
3385
+ * pessoa do lugar. Divisor de dia ("Hoje", "Ontem", a data) antes da primeira de cada dia.
3386
+ * - Mensagens seguidas da mesma pessoa, no mesmo papel e em poucos minutos se agrupam (sem repetir o cabeçalho).
3387
+ * - Comentário interno (só a equipe vê) em balão de destaque, com um cadeado pequeno no começo (sem selo embaixo: não
3388
+ * gasta uma linha); a mudança de status que o comentário acompanha, com o selo do status.
3389
+ * - O campo, numa linha só: Enter envia, Shift+Enter quebra a linha. Conteúdo extra do campo (o "Só para a equipe" do detalhe) entra
3390
+ * por projeção com o atributo `spineChatComposer`. Sem `canWrite`, no lugar do campo vai o conteúdo projetado com
3391
+ * `spineChatReadOnly`.
3392
+ */
3393
+ declare class SpineSuggestionChatComponent {
3394
+ private readonly messages;
3395
+ protected readonly text: {
3396
+ button: string;
3397
+ buttonHint: string;
3398
+ modalTitle: string;
3399
+ intro: string;
3400
+ kind: string;
3401
+ kinds: Record<"melhoria" | "nova_funcionalidade" | "problema" | "outro", string>;
3402
+ statuses: Record<"em_analise" | "planejada" | "em_desenvolvimento" | "concluida" | "recusada", string>;
3403
+ legacyStatuses: Record<"nova", string>;
3404
+ title: string;
3405
+ titlePlaceholder: string;
3406
+ titleRequired: string;
3407
+ description: string;
3408
+ descriptionHint: string;
3409
+ screen: string;
3410
+ screenHint: string;
3411
+ send: string;
3412
+ cancel: string;
3413
+ sent: string;
3414
+ sendError: string;
3415
+ similarHeading: string;
3416
+ similarHint: string;
3417
+ vote: string;
3418
+ voted: string;
3419
+ votes: _trismegisto_primitives.PluralMessage;
3420
+ voteError: string;
3421
+ yours: string;
3422
+ mine: string;
3423
+ mineEmpty: string;
3424
+ mineError: string;
3425
+ loadMore: string;
3426
+ statusFilter: string;
3427
+ allStatuses: string;
3428
+ adminReply: string;
3429
+ sentAt: string;
3430
+ boardLabel: string;
3431
+ search: string;
3432
+ kindFilter: string;
3433
+ allKinds: string;
3434
+ refresh: string;
3435
+ boardEmpty: string;
3436
+ boardEmptyHint: string;
3437
+ boardFiltered: string;
3438
+ loadError: string;
3439
+ moveError: string;
3440
+ removedAuthor: string;
3441
+ noScreen: string;
3442
+ noDescription: string;
3443
+ requestedBy: string;
3444
+ requestedAt: string;
3445
+ status: string;
3446
+ statusSaved: string;
3447
+ statusError: string;
3448
+ history: string;
3449
+ historyEmpty: string;
3450
+ eventStatus: string;
3451
+ eventComment: string;
3452
+ someone: string;
3453
+ comment: string;
3454
+ commentHint: string;
3455
+ commentSend: string;
3456
+ commentSent: string;
3457
+ commentError: string;
3458
+ commentRequired: string;
3459
+ viewLabel: string;
3460
+ viewBoard: string;
3461
+ viewArchive: string;
3462
+ kpis: string;
3463
+ kpiOpen: string;
3464
+ kpiStatusCount: string;
3465
+ kpiDone: string;
3466
+ kpiDoneToday: string;
3467
+ kpiDoneNoneToday: string;
3468
+ kpiOverdueTrend: string;
3469
+ kpiOverdueSteady: string;
3470
+ kpiSoon: string;
3471
+ kpiMineHint: string;
3472
+ kpiPriority: string;
3473
+ kpiPriorityNone: string;
3474
+ kpiPriorityPart: string;
3475
+ filters: string;
3476
+ moreFilters: string;
3477
+ moreFiltersActive: string;
3478
+ allBoardStatuses: string;
3479
+ newTaskIn: string;
3480
+ newTaskOptions: string;
3481
+ columnOldest: string;
3482
+ columnOverdue: _trismegisto_primitives.PluralMessage;
3483
+ columnEmpty: string;
3484
+ columnEmptyFiltered: string;
3485
+ columnEmptyHints: Record<"em_analise" | "planejada" | "em_desenvolvimento" | "concluida", string>;
3486
+ duration: Record<"days" | "hours" | "minutes", string>;
3487
+ createdOn: string;
3488
+ dueWithin: string;
3489
+ dueLateDays: _trismegisto_primitives.PluralMessage;
3490
+ screenFilter: string;
3491
+ allScreens: string;
3492
+ authorFilter: string;
3493
+ allAuthors: string;
3494
+ sort: string;
3495
+ sorts: Record<"position" | "votes" | "recent", string>;
3496
+ sortHint: string;
3497
+ clearFilters: string;
3498
+ topVoted: string;
3499
+ comments: _trismegisto_primitives.PluralMessage;
3500
+ statusSince: string;
3501
+ openScreen: string;
3502
+ statusChange: string;
3503
+ statusComment: string;
3504
+ statusCommentHint: string;
3505
+ statusApply: string;
3506
+ archiveLabel: string;
3507
+ archiveSearch: string;
3508
+ archiveEmpty: string;
3509
+ archiveEmptyHint: string;
3510
+ archiveCount: _trismegisto_primitives.PluralMessage;
3511
+ closedOn: Record<"concluida" | "recusada", string>;
3512
+ pagination: string;
3513
+ reopen: string;
3514
+ reopened: string;
3515
+ reopenError: string;
3516
+ newTask: string;
3517
+ addTaskPlaceholder: string;
3518
+ taskCreated: string;
3519
+ createError: string;
3520
+ saveError: string;
3521
+ kpiMine: string;
3522
+ kpiOverdue: string;
3523
+ assigneeFilter: string;
3524
+ allAssignees: string;
3525
+ assigneeMine: string;
3526
+ assigneeNone: string;
3527
+ labelFilter: string;
3528
+ allLabels: string;
3529
+ priorityFilter: string;
3530
+ allPriorities: string;
3531
+ dueFilter: string;
3532
+ dueAny: string;
3533
+ dueOverdueFilter: string;
3534
+ dueSoonFilter: string;
3535
+ priority: string;
3536
+ priorities: Record<"urgente" | "alta" | "media" | "baixa", string>;
3537
+ dueOn: string;
3538
+ dueToday: string;
3539
+ dueTomorrow: string;
3540
+ dueLate: string;
3541
+ checklistSpoken: string;
3542
+ moreAssignees: string;
3543
+ cardMenu: string;
3544
+ menuStatus: string;
3545
+ menuAssignMe: string;
3546
+ menuCopyLink: string;
3547
+ menuCopyKey: string;
3548
+ menuLabel: string;
3549
+ menuNoLabels: string;
3550
+ menuPriority: string;
3551
+ menuArchive: string;
3552
+ menuRestore: string;
3553
+ menuDelete: string;
3554
+ labelColorName: string;
3555
+ linkCopied: string;
3556
+ keyCopied: string;
3557
+ copyError: string;
3558
+ deleteHeading: string;
3559
+ deleteMessage: string;
3560
+ deleteConfirm: string;
3561
+ deleted: string;
3562
+ archivedToast: string;
3563
+ restoredToast: string;
3564
+ assignedToMe: string;
3565
+ archivedTag: string;
3566
+ taskLabel: string;
3567
+ close: string;
3568
+ editTitle: string;
3569
+ editDescription: string;
3570
+ save: string;
3571
+ checklist: string;
3572
+ checklistAdd: string;
3573
+ checklistPlaceholder: string;
3574
+ checklistOnCard: string;
3575
+ checklistEmpty: string;
3576
+ checklistRemove: string;
3577
+ checklistUp: string;
3578
+ checklistDown: string;
3579
+ tabComments: string;
3580
+ tabActivity: string;
3581
+ commentsEmpty: string;
3582
+ activityEmpty: string;
3583
+ commentInternal: string;
3584
+ internalTag: string;
3585
+ activity: Record<"created" | "title" | "description" | "kind" | "priority" | "start_date" | "start_date_removed" | "due_date" | "due_date_removed" | "cover" | "cover_removed" | "checklist_on_card" | "screen" | "assignee_added" | "assignee_removed" | "watcher_added" | "watcher_removed" | "label_added" | "label_removed" | "checklist_added" | "checklist_done" | "checklist_undone" | "checklist_renamed" | "checklist_removed" | "archived" | "restored" | "merged" | "merged_here" | "unmerged" | "unmerged_here" | "other", string>;
3586
+ assignees: string;
3587
+ assignMe: string;
3588
+ addAssignee: string;
3589
+ watchers: string;
3590
+ addWatcher: string;
3591
+ removePerson: string;
3592
+ peopleSearch: string;
3593
+ peopleEmpty: string;
3594
+ nobody: string;
3595
+ reporter: string;
3596
+ originUser: string;
3597
+ originTeam: string;
3598
+ startDate: string;
3599
+ dueDate: string;
3600
+ labels: string;
3601
+ addLabel: string;
3602
+ createLabel: string;
3603
+ labelColor: string;
3604
+ noLabels: string;
3605
+ screenOrigin: string;
3606
+ votesField: string;
3607
+ createdAt: string;
3608
+ updatedAt: string;
3609
+ lastChange: string;
3610
+ lastChangeNoActor: string;
3611
+ key: string;
3612
+ copyKey: string;
3613
+ newTaskHeading: string;
3614
+ createTask: string;
3615
+ draftHint: string;
3616
+ assignMeOnCreate: string;
3617
+ appSuggestions: string;
3618
+ listView: string;
3619
+ tabAll: string;
3620
+ tabMine: string;
3621
+ appSearch: string;
3622
+ thisScreen: string;
3623
+ appSorts: Record<"votes" | "recent", string>;
3624
+ appEmpty: string;
3625
+ appEmptyHint: string;
3626
+ appEmptyFiltered: string;
3627
+ appError: string;
3628
+ support: string;
3629
+ supported: string;
3630
+ ownSupportHint: string;
3631
+ publicComments: string;
3632
+ publicCommentsEmpty: string;
3633
+ commentsError: string;
3634
+ moreComments: string;
3635
+ appPagination: string;
3636
+ menuMerge: string;
3637
+ mergeHeading: string;
3638
+ mergeIntro: string;
3639
+ mergeSearch: string;
3640
+ mergeNone: string;
3641
+ mergeHasMerged: string;
3642
+ mergePreview: string;
3643
+ mergeCalculating: string;
3644
+ mergePreviewError: string;
3645
+ reportersCount: _trismegisto_primitives.PluralMessage;
3646
+ mergeConfirmHeading: string;
3647
+ mergeConfirmMessage: string;
3648
+ mergeConfirm: string;
3649
+ mergedToast: string;
3650
+ mergeError: string;
3651
+ mergedTag: string;
3652
+ mergedInto: string;
3653
+ mergedIntoHint: string;
3654
+ openMerged: string;
3655
+ unmerge: string;
3656
+ unmergeLabel: string;
3657
+ unmergedToast: string;
3658
+ reporters: string;
3659
+ reporterAuthor: string;
3660
+ reporterVia: string;
3661
+ mergedHere: string;
3662
+ mergedFrom: string;
3663
+ mergedFromHint: string;
3664
+ buttonMenu: string;
3665
+ openPage: string;
3666
+ screenPick: string;
3667
+ screenPickHint: string;
3668
+ screenPickPlaceholder: string;
3669
+ newScreenOption: string;
3670
+ newScreenName: string;
3671
+ newScreenHint: string;
3672
+ newScreenRequired: string;
3673
+ newScreenTag: string;
3674
+ waiting: Record<"solicitante" | "responsaveis", string>;
3675
+ waitingFilter: string;
3676
+ waitingAny: string;
3677
+ waitingClear: string;
3678
+ waitingSaved: string;
3679
+ menuWaiting: string;
3680
+ groupFilter: string;
3681
+ allGroups: string;
3682
+ requestingGroups: string;
3683
+ noGroups: string;
3684
+ unread: _trismegisto_primitives.PluralMessage;
3685
+ fromRequester: string;
3686
+ cardChecklist: _trismegisto_primitives.PluralMessage;
3687
+ requestedByName: string;
3688
+ tabSummary: string;
3689
+ chatAuthor: string;
3690
+ chatSendHint: string;
3691
+ inbox: {
3692
+ label: string;
3693
+ comment: string;
3694
+ status: string;
3695
+ };
3696
+ page: {
3697
+ title: string;
3698
+ description: string;
3699
+ allTitle: string;
3700
+ statusPart: string;
3701
+ reasons: Record<"autor" | "relator" | "envolvido" | "responsavel" | "grupo", string>;
3702
+ reasonHints: Record<"autor" | "relator" | "envolvido" | "responsavel" | "grupo", string>;
3703
+ reasonFilter: string;
3704
+ allReasons: string;
3705
+ needsYou: string;
3706
+ sorts: Record<"activity" | "recent" | "votes", string>;
3707
+ empty: string;
3708
+ emptyHint: string;
3709
+ emptyFiltered: string;
3710
+ error: string;
3711
+ count: _trismegisto_primitives.PluralMessage;
3712
+ pickOne: string;
3713
+ notFound: string;
3714
+ conversation: string;
3715
+ conversationEmpty: string;
3716
+ conversationError: string;
3717
+ olderMessages: string;
3718
+ reply: string;
3719
+ replyPlaceholder: string;
3720
+ replySend: string;
3721
+ replyError: string;
3722
+ readOnly: string;
3723
+ team: string;
3724
+ you: string;
3725
+ groups: string;
3726
+ details: string;
3727
+ listLabel: string;
3728
+ filtersLabel: string;
3729
+ waitingYou: string;
3730
+ waitingTeam: string;
3731
+ };
3732
+ };
3733
+ private readonly preferences;
3734
+ private readonly scroller;
3735
+ /** As mensagens, do mais antigo ao mais novo. */
3736
+ readonly items: _angular_core.InputSignal<readonly SpineChatMessage[]>;
3737
+ /** O papel desta tela: as mensagens da pessoa escritas deste lado ficam à direita. */
3738
+ readonly side: _angular_core.InputSignal<SpineChatSide>;
3739
+ /** O `user_id` de quem está com a tela aberta. */
3740
+ readonly me: _angular_core.InputSignal<string>;
3741
+ readonly label: _angular_core.InputSignal<string>;
3742
+ readonly empty: _angular_core.InputSignal<string>;
3743
+ readonly hasMore: _angular_core.InputSignal<boolean>;
3744
+ readonly loading: _angular_core.InputSignal<boolean>;
3745
+ readonly canWrite: _angular_core.InputSignal<boolean>;
3746
+ readonly composerLabel: _angular_core.InputSignal<string>;
3747
+ readonly placeholder: _angular_core.InputSignal<string>;
3748
+ readonly sendLabel: _angular_core.InputSignal<string>;
3749
+ readonly sending: _angular_core.InputSignal<boolean>;
3750
+ readonly error: _angular_core.InputSignal<string>;
3751
+ /** O texto do campo (em mão dupla: quem usa limpa depois de enviar). */
3752
+ readonly draft: _angular_core.ModelSignal<string>;
3753
+ readonly loadHistory: _angular_core.OutputEmitterRef<void>;
3754
+ /** Enviar: o texto aparado (nunca vazio). */
3755
+ readonly send: _angular_core.OutputEmitterRef<string>;
3756
+ protected readonly statusColors: Record<"em_analise" | "planejada" | "em_desenvolvimento" | "concluida" | "recusada", _trismegisto_angular.TagColor>;
3757
+ protected readonly timeFormat: Intl.DateTimeFormatOptions;
3758
+ protected readonly rows: _angular_core.Signal<ChatRow[]>;
3759
+ /** Depois de enviar: a pessoa quer ver a própria mensagem, mesmo se estava lendo lá em cima. */
3760
+ scrollToEnd(): void;
3761
+ protected onKey(event: Event): void;
3762
+ protected submit(): void;
3763
+ protected statusOf(m: SpineChatMessage): SpineSuggestionStatus | null;
3764
+ /** "Ana Souza (Equipe)": do outro lado, o papel junto do nome — inclusive a própria pessoa no outro papel. */
3765
+ private authorText;
3766
+ private dayKey;
3767
+ /** "Hoje", "Ontem" ou a data por extenso (no idioma do catálogo e no fuso da pessoa). */
3768
+ private dayLabel;
3769
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SpineSuggestionChatComponent, never>;
3770
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SpineSuggestionChatComponent, "spine-suggestion-chat", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "side": { "alias": "side"; "required": true; "isSignal": true; }; "me": { "alias": "me"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "empty": { "alias": "empty"; "required": false; "isSignal": true; }; "hasMore": { "alias": "hasMore"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "canWrite": { "alias": "canWrite"; "required": false; "isSignal": true; }; "composerLabel": { "alias": "composerLabel"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "sendLabel": { "alias": "sendLabel"; "required": false; "isSignal": true; }; "sending": { "alias": "sending"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "draft": { "alias": "draft"; "required": false; "isSignal": true; }; }, { "draft": "draftChange"; "loadHistory": "loadHistory"; "send": "send"; }, never, ["[spineChatComposer]", "[spineChatReadOnly]"], true, never>;
3771
+ }
3772
+
3773
+ /** Um selo da linha: o nome e, se quiser, a cor (1..8, a paleta categórica do tema); sem cor, uma estável pelo id. */
3774
+ interface SpineTagRowItem {
3775
+ id: string;
3776
+ name: string;
3777
+ color?: number;
3778
+ }
3779
+ /** Cor categórica estável para um id (o mesmo grupo sempre na mesma cor, em qualquer tela). */
3780
+ declare function spineTagColor(id: string): number;
3781
+ /**
3782
+ * Selos numa linha só, no modelo dos rótulos do quadro (fundo claro da cor e o ponto na cor cheia): cabem os que cabem
3783
+ * na largura e o resto vira "+N", com os nomes na dica e para o leitor de tela. Mede de novo quando a largura muda
3784
+ * (ResizeObserver) e quando a lista muda; sem medida (servidor, teste sem layout), mostra todos.
3785
+ *
3786
+ * Os que não cabem continuam no DOM, fora do fluxo e invisíveis (`visibility: hidden`), só para a largura deles poder
3787
+ * ser medida; ficam `aria-hidden` — quem lê a tela ouve os nomes no "+N".
3788
+ */
3789
+ declare class SpineTagRowComponent {
3790
+ private readonly text;
3791
+ private readonly host;
3792
+ private readonly browser;
3793
+ private readonly injector;
3794
+ private readonly destroyRef;
3795
+ readonly items: _angular_core.InputSignal<readonly SpineTagRowItem[]>;
3796
+ readonly label: _angular_core.InputSignal<string>;
3797
+ /** Texto quando não há nenhum (vazio = nada). */
3798
+ readonly empty: _angular_core.InputSignal<string>;
3799
+ protected readonly tags: _angular_core.Signal<{
3800
+ color: number;
3801
+ id: string;
3802
+ name: string;
3803
+ }[]>;
3804
+ /** Quantos cabem; começa com todos (sem medida, todos aparecem). */
3805
+ protected readonly visible: _angular_core.WritableSignal<number>;
3806
+ protected readonly hiddenCount: _angular_core.Signal<number>;
3807
+ protected readonly hiddenNames: _angular_core.Signal<string>;
3808
+ protected readonly moreText: _angular_core.Signal<string>;
3809
+ constructor();
3810
+ /** Quantos selos cabem na largura, reservando o "+N" quando nem todos cabem. */
3811
+ private measure;
3812
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SpineTagRowComponent, never>;
3813
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SpineTagRowComponent, "spine-tag-row", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "empty": { "alias": "empty"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3814
+ }
3815
+
2954
3816
  /**
2955
3817
  * Modal de documentação das telas: índice (com busca) à esquerda e leitura à direita. Montado uma vez
2956
3818
  * pelo `spine-layout`; abrir, fechar e o que se lê vêm todos do `SpineDocsService`.
@@ -2996,6 +3858,6 @@ declare const SPINE_MARKDOWN_PURIFY_CONFIG: Config;
2996
3858
  /** HTML limpo pelo perfil do spine, ou `null` quando não há DOM (SSR: melhor não renderizar). */
2997
3859
  declare function sanitizeSpineMarkdownHtml(html: string): string | null;
2998
3860
 
2999
- export { AiAgentComponent, AppLauncherComponent, HeaderComponent, LayoutComponent, SPINE_BRAND, SPINE_GLOBAL_PREFERENCE_KEYS, SPINE_IDLE_WARNING_SECONDS, SPINE_MARKDOWN_PURIFY_CONFIG, SPINE_PREFERENCES_SAVE_DELAY_MS, SPINE_RATING_COMMENT_MAX, SPINE_RATING_SCORE_MAX, SPINE_SETTINGS_ALIASES, SPINE_SETTINGS_KEYS, SPINE_SETTINGS_SECTIONS, SPINE_SUGGESTION_KINDS, SPINE_SUGGESTION_KIND_COLORS, SPINE_SUGGESTION_KIND_ICONS, SPINE_SUGGESTION_LIMITS, SPINE_SUGGESTION_PUBLIC_SORTS, SPINE_SUGGESTION_PUBLIC_STATUSES, SPINE_SUGGESTION_STATUSES, SPINE_SUGGESTION_STATUS_COLORS, SPINE_SUGGESTION_STATUS_ICONS, SettingsPanelComponent, ShortcutService, ShortcutsCheatsheetComponent, SidebarComponent, SpineAccountPreferencesService, SpineAccountSecurityService, SpineAppTokensService, SpineBrandComponent, SpineConnectionBannerComponent, SpineDocsComponent, SpineDocsService, SpineIdleService, SpineIdleWarningComponent, SpineInitialSetupComponent, SpineInitialSetupService, SpineLogoutService, SpineMarkdownComponent, SpineMyGroupsService, SpineNewsComponent, SpineNewsService, SpineNoticesService, SpinePageActionsDirective, SpinePageActionsSlot, SpineRatingStarsComponent, SpineRatingsService, SpineSettingsService, SpineStartPageService, SpineSuggestionsService, accountErrorCode, argosAccountApi, buildMcpConfig, effectiveIdleMinutes, idleLimits, isInternalPath, provideSettingsSection, ratingTargetKey, resolveSettingsSection, sanitizeSpineMarkdownHtml, spineScoreBand, spineStarFills, stable };
3000
- export type { AccountActivityEntry, AccountActivityPage, AccountBadges, AccountMethod, AccountOverview, AccountPreferences, AccountReauth, AccountSession, AppToken, AppTokenList, AppTokenOptions, CreatedAppToken, DocsEntry, DocsGroup, DocsView, GroupMember, GroupRole, ManagedGroup, RealmUser, ShortcutActions, SpineAccountPreferencesDoc, SpineAccountPreferencesStatus, SpineAppSuggestion, SpineAppSuggestionsQuery, SpineGlobalPreferencesDoc, SpineIdleLimits, SpineInitialSetupMode, SpineInitialSetupStep, SpineNewsAuthor, SpineNewsDetail, SpineNewsFilter, SpineNewsKind, SpineNewsPage, SpineNewsSummary, SpineNotice, SpineNoticePermission, SpineRating, SpineRatingAverage, SpineRatingScope, SpineRatingTarget, SpineScoreBand, SpineSettingsSection, SpineStarFill, SpineSuggestion, SpineSuggestionComment, SpineSuggestionDraft, SpineSuggestionKind, SpineSuggestionPerson, SpineSuggestionPublicSort, SpineSuggestionPublicStatus, SpineSuggestionStatus };
3861
+ export { AiAgentComponent, AppLauncherComponent, HeaderComponent, LayoutComponent, NEW_SCREEN_VALUE, SPINE_BRAND, SPINE_GLOBAL_PREFERENCE_KEYS, SPINE_IDLE_WARNING_SECONDS, SPINE_INBOX_POLL_MS, SPINE_INBOX_SOURCES, SPINE_MARKDOWN_PURIFY_CONFIG, SPINE_PREFERENCES_SAVE_DELAY_MS, SPINE_RATING_COMMENT_MAX, SPINE_RATING_SCORE_MAX, SPINE_SETTINGS_ALIASES, SPINE_SETTINGS_KEYS, SPINE_SETTINGS_SECTIONS, SPINE_SUGGESTIONS_PAGE_ID, SPINE_SUGGESTIONS_PAGE_PATH, SPINE_SUGGESTION_KINDS, SPINE_SUGGESTION_KIND_COLORS, SPINE_SUGGESTION_KIND_ICONS, SPINE_SUGGESTION_LIMITS, SPINE_SUGGESTION_PAGE_PARAM, SPINE_SUGGESTION_PUBLIC_SORTS, SPINE_SUGGESTION_PUBLIC_STATUSES, SPINE_SUGGESTION_REASONS, SPINE_SUGGESTION_STATUSES, SPINE_SUGGESTION_STATUS_COLORS, SPINE_SUGGESTION_STATUS_ICONS, SPINE_SUGGESTION_TAB_CONVERSATION, SPINE_SUGGESTION_TAB_PARAM, SPINE_SUGGESTION_VISIBLE_SORTS, SPINE_SUGGESTION_WAITING, SPINE_SUGGESTION_WAITING_COLORS, SPINE_TAB, SettingsPanelComponent, ShortcutService, ShortcutsCheatsheetComponent, SidebarComponent, SpineAccountPreferencesService, SpineAccountSecurityService, SpineAppTokensService, SpineBrandComponent, SpineConnectionBannerComponent, SpineDocsComponent, SpineDocsService, SpineIdleService, SpineIdleWarningComponent, SpineInboxButtonComponent, SpineInboxService, SpineInitialSetupComponent, SpineInitialSetupService, SpineLogoutService, SpineMarkdownComponent, SpineMyGroupsService, SpineNewsComponent, SpineNewsService, SpineNoticesService, SpinePageActionsDirective, SpinePageActionsSlot, SpineRatingStarsComponent, SpineRatingsService, SpineSettingsService, SpineStartPageService, SpineSuggestionChatComponent, SpineSuggestionsService, SpineTagRowComponent, SpineWorkspaceNavService, accountErrorCode, argosAccountApi, buildMcpConfig, effectiveIdleMinutes, idleLimits, isInternalPath, provideSettingsSection, provideSpineInboxSource, provideSpineSuggestionsPage, ratingTargetKey, resolveSettingsSection, sanitizeSpineMarkdownHtml, screenModule, screenName, spineNormalizeUrl, spineParamsOf, spinePathOf, spineScoreBand, spineStarFills, spineSuggestionsEnabled, spineTagColor, stable, suggestionScreens };
3862
+ export type { AccountActivityEntry, AccountActivityPage, AccountBadges, AccountMethod, AccountOverview, AccountPreferences, AccountReauth, AccountSession, AppToken, AppTokenList, AppTokenOptions, CreatedAppToken, DocsEntry, DocsGroup, DocsView, GroupMember, GroupRole, ManagedGroup, RealmUser, ShortcutActions, SpineAccountPreferencesDoc, SpineAccountPreferencesStatus, SpineAppSuggestion, SpineAppSuggestionsQuery, SpineChatMessage, SpineChatSide, SpineGlobalPreferencesDoc, SpineIdleLimits, SpineInboxEntry, SpineInboxItem, SpineInboxSource, SpineInitialSetupMode, SpineInitialSetupStep, SpineNewsAuthor, SpineNewsDetail, SpineNewsFilter, SpineNewsKind, SpineNewsPage, SpineNewsSummary, SpineNotice, SpineNoticePermission, SpineOpenTabOptions, SpineRating, SpineRatingAverage, SpineRatingScope, SpineRatingTarget, SpineScoreBand, SpineSettingsSection, SpineStarFill, SpineSuggestion, SpineSuggestionComment, SpineSuggestionDraft, SpineSuggestionKind, SpineSuggestionMessage, SpineSuggestionPerson, SpineSuggestionPublicSort, SpineSuggestionPublicStatus, SpineSuggestionReason, SpineSuggestionScreen, SpineSuggestionStatus, SpineSuggestionUpdate, SpineSuggestionVisibleSort, SpineSuggestionWaiting, SpineTab, SpineTabParams, SpineTagRowItem, SpineVisibleCounts, SpineVisibleQuery, SpineVisibleSuggestion, SuggestionScreenOption };
3001
3863
  //# sourceMappingURL=trismegisto-spine-layout.d.ts.map