@trismegisto/spine 3.0.4 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/fesm2022/{trismegisto-spine-auto-service-apps.usage-DeLfYMeO.mjs → trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs} +21 -22
- package/fesm2022/trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs.map +1 -0
- package/fesm2022/{trismegisto-spine-auto-service-auto-service-audit.component-BNtNWfiu.mjs → trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs} +2 -2
- 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
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs +65 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs.map +1 -0
- package/fesm2022/{trismegisto-spine-auto-service-auto-service-client.component-wu2tFGS7.mjs → trismegisto-spine-auto-service-auto-service-client.component-DzmlpLPu.mjs} +136 -87
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-DzmlpLPu.mjs.map +1 -0
- 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
- 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
- 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
- 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
- package/fesm2022/{trismegisto-spine-auto-service-auto-service.component-D-N-xXPN.mjs → trismegisto-spine-auto-service-auto-service.component-C4FBAefe.mjs} +89 -55
- package/fesm2022/trismegisto-spine-auto-service-auto-service.component-C4FBAefe.mjs.map +1 -0
- package/fesm2022/{trismegisto-spine-auto-service-client.usage-CcJANb20.mjs → trismegisto-spine-auto-service-client.usage-B16r3IHk.mjs} +16 -12
- package/fesm2022/trismegisto-spine-auto-service-client.usage-B16r3IHk.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service.mjs +7 -7
- package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -1
- package/fesm2022/trismegisto-spine.mjs +43 -5
- package/fesm2022/trismegisto-spine.mjs.map +1 -1
- package/package.json +6 -6
- package/types/trismegisto-spine-auto-service.d.ts.map +1 -1
- package/types/trismegisto-spine-graphql.d.ts +1 -1
- package/types/trismegisto-spine.d.ts +27 -3
- package/types/trismegisto-spine.d.ts.map +1 -1
- package/fesm2022/trismegisto-spine-auto-service-apps.usage-DeLfYMeO.mjs.map +0 -1
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-DdtDk_xl.mjs +0 -51
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-DdtDk_xl.mjs.map +0 -1
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-wu2tFGS7.mjs.map +0 -1
- package/fesm2022/trismegisto-spine-auto-service-auto-service.component-D-N-xXPN.mjs.map +0 -1
- package/fesm2022/trismegisto-spine-auto-service-client.usage-CcJANb20.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -113,6 +113,42 @@ O `spine-layout` também monta os avisos: o `spine-notification` (`NotificationS
|
|
|
113
113
|
(`HermesToastService`, usado nas configurações, inclusive em MFA e Sessões, e no auto-serviço). O app não monta outro; se
|
|
114
114
|
montar, os avisos não aparecem em dobro (só uma pilha desenha).
|
|
115
115
|
|
|
116
|
+
## Ambiente em tempo de execução (`config.json`)
|
|
117
|
+
|
|
118
|
+
Cada versão do app gera **uma imagem só**; o ambiente (homologação, produção…) é escolhido no deploy, por um
|
|
119
|
+
`config.json` servido junto do app (montado no container), e não mais por um `environment.<ambiente>.ts` no build.
|
|
120
|
+
No `main.ts`, antes de tudo:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { applyRuntimeEnvironment, loadRuntimeConfig } from '@trismegisto/spine';
|
|
124
|
+
import { environment } from './environments/environment';
|
|
125
|
+
|
|
126
|
+
loadRuntimeConfig(environment, { required: !isDevMode() })
|
|
127
|
+
.then(async () => {
|
|
128
|
+
applyRuntimeEnvironment(environment);
|
|
129
|
+
const [{ appConfig }, { AppComponent }] = await Promise.all([import('./app/app.config'), import('./app/app.component')]);
|
|
130
|
+
return bootstrapApplication(AppComponent, appConfig);
|
|
131
|
+
})
|
|
132
|
+
.catch((e) => console.error(e));
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- **`loadRuntimeConfig(environment, { file?, required? })`** (do `@trismegisto/primitives`, reexportado aqui;
|
|
136
|
+
app sem o spine importa direto de lá) busca `file` (padrão `config.json`)
|
|
137
|
+
relativo ao base href (sob `/app-exemplo/` busca `/app-exemplo/config.json`), sem cache, e mescla o JSON **no
|
|
138
|
+
próprio** `environment`, em profundidade: objetos mesclam chave a chave; arrays e valores simples substituem;
|
|
139
|
+
chaves novas entram. O `config.json` só precisa trazer o que muda. Devolve o próprio `environment`.
|
|
140
|
+
- Sem o arquivo (404, rede, ou o `index.html` do fallback de SPA): com `required: true` lança erro
|
|
141
|
+
("config.json não encontrado: o ambiente do app não foi configurado no deploy"); sem, avisa no console e segue
|
|
142
|
+
com o environment do build. JSON inválido lança erro sempre.
|
|
143
|
+
- **`applyRuntimeEnvironment(environment)`** vem depois: ajusta `redirectUrl`/`postLogoutRedirectUri` à origem e
|
|
144
|
+
ao prefixo atuais e, atrás do proxy, deriva `authority` e os endpoints GraphQL ainda vazios/`CHANGE_ME` — o que o
|
|
145
|
+
`config.json` definir explicitamente prevalece.
|
|
146
|
+
- **`required: !isDevMode()`**, não `environment.production`: com um environment base só, `production` é o do
|
|
147
|
+
build até o merge, e a imagem de produção subiria sem `config.json` sem erro nenhum.
|
|
148
|
+
- **Import dinâmico** do `app.config` e do componente raiz: o que lê o `environment` ao carregar o módulo (providers,
|
|
149
|
+
tokens) com import estático é avaliado antes do merge e fica com os valores do build.
|
|
150
|
+
- **Sem top-level await:** o build de app com Zone.js não aceita; use o `.then`.
|
|
151
|
+
|
|
116
152
|
## Logo e favicon
|
|
117
153
|
|
|
118
154
|
O spine não traz marca nenhuma: o logo do cabeçalho e o favicon são arquivos do app.
|
|
@@ -45,21 +45,21 @@ podem chamar a operação). A tela não cria nem edita operações.
|
|
|
45
45
|
|
|
46
46
|
## Aba Acessos
|
|
47
47
|
|
|
48
|
-
Mostra os grupos que têm acesso à aplicação
|
|
49
|
-
o acesso dele às aplicações é gerido só no painel central do Argos.
|
|
48
|
+
Mostra os grupos que têm acesso à aplicação: **Grupo**, **Tipo** (etiqueta) e **Operações**. O grupo de
|
|
49
|
+
administração do projeto não aparece: o acesso dele às aplicações é gerido só no painel central do Argos.
|
|
50
50
|
|
|
51
51
|
- **Novo acesso**: escolha o **Grupo** e clique em **Criar**. Só aparecem os grupos do seu client (sem o de
|
|
52
52
|
administração).
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
- **Gerenciar operações** (botão na coluna **Operações**) abre o painel **Operações de nome do grupo**: uma árvore com
|
|
54
|
+
as operações agrupadas pelo identificador (\`teams:members:add\` fica na pasta **teams** › **members**), cada uma
|
|
55
|
+
com método, nível e descrição. No topo fica só o campo **Filtrar operações**: ele casa com o identificador, o
|
|
56
|
+
método, o nível ou a descrição (sem diferenciar acentos), abre as pastas encontradas e, com ele ativo, marcar uma
|
|
57
|
+
pasta marca só as operações que aparecem. Só as **protected** dependem de permissão: as **public**, **private** e
|
|
58
|
+
**optional** aparecem marcadas e travadas. Cada pasta mostra quantas das operações escolhíveis dela estão marcadas
|
|
59
|
+
(**X de Y**). Marque o que o grupo pode chamar, desmarque o que não pode e clique em **Confirmar alterações** (o botão
|
|
60
|
+
só habilita quando algo mudou). **Cancelar** descarta.
|
|
61
|
+
- No menu de cada linha, **Remover** pede confirmação (**Remover acesso à aplicação?**, com o nome do grupo) e só
|
|
62
|
+
então tira o acesso do grupo à aplicação e as permissões de operação dele.
|
|
63
63
|
|
|
64
64
|
Depois de criar o acesso, use **Gerenciar operações** para escolher o que o grupo pode chamar.
|
|
65
65
|
|
|
@@ -67,7 +67,7 @@ Depois de criar o acesso, use **Gerenciar operações** para escolher o que o gr
|
|
|
67
67
|
|
|
68
68
|
Tokens de API da aplicação: a credencial que um serviço envia no cabeçalho \`x-api-token\` para chamar as operações
|
|
69
69
|
da aplicação sem login. A tabela mostra **Nome**, **Início do token** (os primeiros caracteres, para reconhecer),
|
|
70
|
-
**
|
|
70
|
+
**Status** (**Ativo**, **Expirado** ou **Revogado**), **Expira em**, **Último uso** e **Operações**.
|
|
71
71
|
|
|
72
72
|
1. **Novo token** abre o formulário:
|
|
73
73
|
- **Nome** (obrigatório) e **Descrição** (opcional).
|
|
@@ -78,16 +78,15 @@ da aplicação sem login. A tabela mostra **Nome**, **Início do token** (os pri
|
|
|
78
78
|
desmarcadas e travadas, com a nota **pública: não precisa de token**.
|
|
79
79
|
2. **Criar token** mostra o valor do token **uma única vez**, com o botão **Copiar**. **Copie e guarde na hora:
|
|
80
80
|
fechando a janela (Concluir ou Esc) não há como vê-lo de novo.** Se ele se perder, revogue e crie outro.
|
|
81
|
-
3.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Token revogado não tem mais ações. Se o servidor recusar a criação (por exemplo, validade fora do intervalo), o
|
|
81
|
+
3. **Gerenciar operações** (botão na coluna **Operações**) abre o mesmo painel em árvore, com o mesmo filtro, para o
|
|
82
|
+
token: marca o que já está liberado, deixa marcar e desmarcar as **protected**, **private** e **optional** e
|
|
83
|
+
mantém as **public** travadas e desmarcadas. **Confirmar alterações** grava só o que mudou.
|
|
84
|
+
4. No menu de cada linha, **Revogar** pede confirmação (**Revogar token?**, com o nome dele). Confirmando, o token
|
|
85
|
+
deixa de funcionar na hora e fica na lista como **Revogado**. Não tem volta.
|
|
86
|
+
|
|
87
|
+
Token revogado não tem mais ações (a coluna **Operações** mostra "—"). Se o servidor recusar a criação (por exemplo, validade fora do intervalo), o
|
|
89
88
|
motivo aparece no próprio formulário.
|
|
90
89
|
`;
|
|
91
90
|
|
|
92
91
|
export { apps_usage as default };
|
|
93
|
-
//# sourceMappingURL=trismegisto-spine-auto-service-apps.usage-
|
|
92
|
+
//# sourceMappingURL=trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trismegisto-spine-auto-service-apps.usage-po9Ds_SU.mjs","sources":["../../../projects/ui/auto-service/src/docs/apps.usage.ts"],"sourcesContent":["// Manual de uso da tela Aplicações do auto-serviço (`RouteDocument.load`), em Markdown. Módulo próprio,\n// carregado só pelo `import()` de `AUTO_SERVICE_DOCUMENTS`: vira um chunk à parte no FESM e fica fora do\n// bundle inicial. Não importe estaticamente nem reexporte no `public-api.ts`.\nexport default `# Aplicações\n\nGerencie as aplicações (credenciais \\`client_credentials\\`) do projeto do seu client, sem depender do painel\ncentral: cadastre, ative ou desative e exclua aplicações, veja as operações que cada uma registra, defina quais\ngrupos podem chamar quais operações e crie os tokens de API das aplicações.\n\n## Antes de começar\n\nComo nas outras telas do auto-serviço, o client administrado é o do app em que você está logado: não há client\npara escolher. É preciso estar no grupo de administração do projeto desse app e com o crachá **Administrador**\nativo.\n\n## Como usar\n\n1. A tela abre com o botão **Cadastrar** e um cartão com o seletor **Selecione uma aplicação**, que lista as\n aplicações do projeto. Escolha uma e clique em **Consultar**.\n2. Para criar uma aplicação, clique em **Cadastrar**. No modal **Nova aplicação**, preencha o\n **Nome** (obrigatório) e os **Grants** (separados por vírgula; já vem \\`client_credentials\\`) e clique em **Salvar**.\n3. Ao criar, aparece no topo da tela o aviso **Aplicação criada** com o secret. **Copie e guarde o secret na hora:\n ele não é exibido de novo.** O aviso some quando você o fecha, troca de client ou exclui a aplicação.\n4. A aplicação consultada abre embaixo do seletor: um cartão com o nome, a situação (**Ativo** ou **Inativo**),\n os grants e os botões das ações da aplicação:\n - **Editar**: muda nome, grants e a caixa **Ativo**.\n - **Desativar** / **Ativar**: liga ou desliga a aplicação sem apagar nada.\n - **Gerar novo segredo**: abre a confirmação **Gerar um novo segredo?**. Confirmando, o segredo atual deixa de\n funcionar na hora (atualize o APP_SECRET do serviço que usa a aplicação; tokens já emitidos valem até expirar,\n até 1 hora) e o novo aparece numa janela, **uma única vez**, com o botão **Copiar**. **Concluir** fecha a janela.\n - **Excluir**: abre a confirmação **Excluir aplicação?** com o nome dela; só depois de **Excluir** no diálogo a\n aplicação é apagada e a credencial dela para de funcionar. **Cancelar** (ou Esc) não muda nada.\n5. Embaixo do cartão ficam as abas **Operações**, **Acessos** e **Tokens** da aplicação. Consultar outra\n aplicação volta para a aba **Operações**.\n\n> **Desativar** age na hora e se desfaz com **Ativar**. **Excluir** não tem volta: na dúvida, desative. Depois de\n> excluir aparece a mensagem **Exclusão concluída.**; se o servidor recusar, a mensagem de erro diz o motivo e a\n> aplicação continua na tela.\n\n## Aba Operações\n\nLista, só para consulta, as operações registradas pela aplicação: **Identificador**, **Método**, **Nível** (o selo\nfica verde para operação pública e amarelo para protegida), **Descrição** e **Grupos permitidos** (quantos grupos já\npodem chamar a operação). A tela não cria nem edita operações.\n\n## Aba Acessos\n\nMostra os grupos que têm acesso à aplicação: **Grupo**, **Tipo** (etiqueta) e **Operações**. O grupo de\nadministração do projeto não aparece: o acesso dele às aplicações é gerido só no painel central do Argos.\n\n- **Novo acesso**: escolha o **Grupo** e clique em **Criar**. Só aparecem os grupos do seu client (sem o de\n administração).\n- **Gerenciar operações** (botão na coluna **Operações**) abre o painel **Operações de nome do grupo**: uma árvore com\n as operações agrupadas pelo identificador (\\`teams:members:add\\` fica na pasta **teams** › **members**), cada uma\n com método, nível e descrição. No topo fica só o campo **Filtrar operações**: ele casa com o identificador, o\n método, o nível ou a descrição (sem diferenciar acentos), abre as pastas encontradas e, com ele ativo, marcar uma\n pasta marca só as operações que aparecem. Só as **protected** dependem de permissão: as **public**, **private** e\n **optional** aparecem marcadas e travadas. Cada pasta mostra quantas das operações escolhíveis dela estão marcadas\n (**X de Y**). Marque o que o grupo pode chamar, desmarque o que não pode e clique em **Confirmar alterações** (o botão\n só habilita quando algo mudou). **Cancelar** descarta.\n- No menu de cada linha, **Remover** pede confirmação (**Remover acesso à aplicação?**, com o nome do grupo) e só\n então tira o acesso do grupo à aplicação e as permissões de operação dele.\n\nDepois de criar o acesso, use **Gerenciar operações** para escolher o que o grupo pode chamar.\n\n## Aba Tokens\n\nTokens de API da aplicação: a credencial que um serviço envia no cabeçalho \\`x-api-token\\` para chamar as operações\nda aplicação sem login. A tabela mostra **Nome**, **Início do token** (os primeiros caracteres, para reconhecer),\n**Status** (**Ativo**, **Expirado** ou **Revogado**), **Expira em**, **Último uso** e **Operações**.\n\n1. **Novo token** abre o formulário:\n - **Nome** (obrigatório) e **Descrição** (opcional).\n - **Expira em**: de amanhã até 365 dias a partir de hoje (vem com 90 dias). O token vale até a meia-noite desse\n dia.\n - **Operações liberadas ao token**: nada vem marcado. O token não tem login, então marque as operações\n **protected**, **private** e **optional** que ele pode chamar; o que ficar desmarcado ele não chama. As **public** aparecem\n desmarcadas e travadas, com a nota **pública: não precisa de token**.\n2. **Criar token** mostra o valor do token **uma única vez**, com o botão **Copiar**. **Copie e guarde na hora:\n fechando a janela (Concluir ou Esc) não há como vê-lo de novo.** Se ele se perder, revogue e crie outro.\n3. **Gerenciar operações** (botão na coluna **Operações**) abre o mesmo painel em árvore, com o mesmo filtro, para o\n token: marca o que já está liberado, deixa marcar e desmarcar as **protected**, **private** e **optional** e\n mantém as **public** travadas e desmarcadas. **Confirmar alterações** grava só o que mudou.\n4. No menu de cada linha, **Revogar** pede confirmação (**Revogar token?**, com o nome dele). Confirmando, o token\n deixa de funcionar na hora e fica na lista como **Revogado**. Não tem volta.\n\nToken revogado não tem mais ações (a coluna **Operações** mostra \"—\"). Se o servidor recusar a criação (por exemplo, validade fora do intervalo), o\nmotivo aparece no próprio formulário.\n`;\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA,iBAAe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFd;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { SpineAuditComponent } from '@trismegisto/spine/audit';
|
|
4
|
-
import { A as AutoServiceClientPickerComponent } from './trismegisto-spine-auto-service-auto-service-client-picker.component-
|
|
4
|
+
import { A as AutoServiceClientPickerComponent } from './trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Tela "Auditoria" do auto-serviço (router `AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID`): o dono/membro
|
|
@@ -34,4 +34,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
|
|
|
34
34
|
}] });
|
|
35
35
|
|
|
36
36
|
export { AutoServiceAuditComponent };
|
|
37
|
-
//# sourceMappingURL=trismegisto-spine-auto-service-auto-service-audit.component-
|
|
37
|
+
//# sourceMappingURL=trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trismegisto-spine-auto-service-auto-service-audit.component-
|
|
1
|
+
{"version":3,"file":"trismegisto-spine-auto-service-auto-service-audit.component-tfGcVR3i.mjs","sources":["../../../projects/ui/auto-service/src/audit/auto-service-audit.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, signal } from '@angular/core';\nimport { SpineAuditComponent } from '@trismegisto/spine/audit';\nimport { AutoServiceClient, AutoServiceClientPickerComponent } from '../client-picker/auto-service-client-picker.component';\n\n/**\n * Tela \"Auditoria\" do auto-serviço (router `AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID`): o dono/membro\n * do projeto escolhe o client (como em Aplicações) e vê os eventos dos apps dele — com a MESMA tela do\n * painel central (`SpineAuditComponent`, `@trismegisto/spine/audit`), no escopo `client`. Carregada só\n * por `AUTO_SERVICE_SCREENS.audit` — nunca exportada pelo ponto de entrada (ver `public-api.ts`).\n */\n@Component({\n selector: 'spine-auto-service-audit',\n imports: [AutoServiceClientPickerComponent, SpineAuditComponent],\n // Sem título/descrição internos: vêm da barra da página do spine (nome da rota + descrição do router\n // AD100004 e das cópias dele, `web.router.description` -- migration 016 do argos).\n template: `\n <spine-auto-service-client-picker (clientChange)=\"client.set($event)\" />\n @if (client(); as c) {\n <br />\n <spine-audit scope=\"client\" [clientId]=\"c.id\" />\n }\n `,\n styleUrl: './auto-service-audit.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AutoServiceAuditComponent {\n protected readonly client = signal<AutoServiceClient | null>(null);\n}\n"],"names":[],"mappings":";;;;;AAIA;;;;;AAKG;MAgBU,yBAAyB,CAAA;AAftC,IAAA,WAAA,GAAA;AAgBqB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAA2B,IAAI,6EAAC;AACnE,IAAA;+GAFY,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAzB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAV1B;;;;;;GAMT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,g8CAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EATS,gCAAgC,wGAAE,mBAAmB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAapD,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAfrC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,0BAA0B,WAC3B,CAAC,gCAAgC,EAAE,mBAAmB,CAAC,EAAA,QAAA,EAGtD;;;;;;GAMT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,MAAA,EAAA,CAAA,g8CAAA,CAAA,EAAA;;;"}
|
package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ChangeDetectorRef, EventEmitter, Output, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import * as i2 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
6
|
+
import { AlertComponent, ButtonComponent, CardComponent, ComboboxComponent } from '@trismegisto/angular';
|
|
7
|
+
import { formatMessage } from '@trismegisto/primitives';
|
|
8
|
+
import { SPINE_MESSAGES } from '@trismegisto/spine';
|
|
9
|
+
import { AutoServiceService } from './trismegisto-spine-auto-service.mjs';
|
|
10
|
+
|
|
11
|
+
class AutoServiceClientPickerComponent {
|
|
12
|
+
constructor(service) {
|
|
13
|
+
this.service = service;
|
|
14
|
+
this.text = inject(SPINE_MESSAGES).autoService;
|
|
15
|
+
/** Telas com estado em campo comum, preenchido depois de `await`: marca a view ao terminar (app sem zone.js). */
|
|
16
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
17
|
+
this.loading = true;
|
|
18
|
+
this.clients = [];
|
|
19
|
+
this.selectedClientId = '';
|
|
20
|
+
/**
|
|
21
|
+
* Falha ao buscar os clients (Argos fora do ar, rede, 5xx): mostrada como erro, com "Tentar de novo". Antes caía na
|
|
22
|
+
* lista vazia e a tela dizia "você não administra este app", que é outra coisa (falta de grupo ou de crachá).
|
|
23
|
+
*/
|
|
24
|
+
this.loadError = null;
|
|
25
|
+
this.clientChange = new EventEmitter();
|
|
26
|
+
}
|
|
27
|
+
get clientOptions() {
|
|
28
|
+
return this.clients.map((c) => ({ value: c.id, label: c.display_name || c.name }));
|
|
29
|
+
}
|
|
30
|
+
ngOnInit() { void this.load(); }
|
|
31
|
+
async load() {
|
|
32
|
+
this.loading = true;
|
|
33
|
+
this.loadError = null;
|
|
34
|
+
try {
|
|
35
|
+
const res = await this.service.getMyClients();
|
|
36
|
+
this.clients = res.clients;
|
|
37
|
+
if (this.clients.length === 1)
|
|
38
|
+
this.selectClient(this.clients[0].id);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
this.clients = [];
|
|
42
|
+
const status = err instanceof HttpErrorResponse ? err.status : 0;
|
|
43
|
+
this.loadError = formatMessage(this.text.clientsLoadError, { status });
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
this.loading = false;
|
|
47
|
+
this.cdr.markForCheck();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
selectClient(id) {
|
|
51
|
+
this.selectedClientId = id;
|
|
52
|
+
this.clientChange.emit(this.clients.find(c => c.id === id) ?? null);
|
|
53
|
+
}
|
|
54
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceClientPickerComponent, deps: [{ token: AutoServiceService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
55
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.24", type: AutoServiceClientPickerComponent, isStandalone: true, selector: "spine-auto-service-client-picker", outputs: { clientChange: "clientChange" }, ngImport: i0, template: "<hm-card *ngIf=\"loading\">\n <span class=\"muted\">{{ text.loading }}</span>\n</hm-card>\n\n<hm-alert *ngIf=\"!loading && loadError\" variant=\"error\">\n <div class=\"cp-error\">\n <span>{{ loadError }}</span>\n <hm-button emphasis=\"medium\" icon=\"refresh\" (clicked)=\"load()\">{{ text.retryLoad }}</hm-button>\n </div>\n</hm-alert>\n\n<hm-card *ngIf=\"!loading && !loadError && clients.length === 0\">\n <span [innerHTML]=\"text.noClients\"></span>\n</hm-card>\n\n<hm-card *ngIf=\"!loading && clients.length > 1\">\n <hm-combobox\n [label]=\"text.pickClient\"\n [options]=\"clientOptions\"\n [value]=\"selectedClientId\"\n (valueChange)=\"selectClient($event)\"\n ></hm-combobox>\n</hm-card>\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}:host{display:block}:host:empty{display:none}.cp-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: AlertComponent, selector: "hm-alert", inputs: ["variant", "appearance", "heading", "closable", "size", "showIcon", "link", "linkLabel", "linkTarget", "dismissKey", "duration"], outputs: ["closed"] }, { kind: "component", type: ButtonComponent, selector: "hm-button", inputs: ["emphasis", "intent", "size", "type", "icon", "iconDirection", "iconEnd", "disabled", "loading", "busy", "loadingState", "block", "link", "newTab", "caret", "inMenu", "toggle", "pressed"], outputs: ["loadingStateChange", "pressedChange", "clicked"] }, { kind: "component", type: CardComponent, selector: "hm-card", inputs: ["heading", "icon", "selected", "fill", "media", "mediaAlt", "mediaDecorative", "mediaPosition"] }, { kind: "component", type: ComboboxComponent, selector: "hm-combobox", inputs: ["label", "options", "value", "placeholder", "icon", "hint", "help", "size", "labelHidden", "clearable", "requiredManual", "loading", "allowCustomValue"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
56
|
+
}
|
|
57
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceClientPickerComponent, decorators: [{
|
|
58
|
+
type: Component,
|
|
59
|
+
args: [{ selector: 'spine-auto-service-client-picker', standalone: true, imports: [CommonModule, AlertComponent, ButtonComponent, CardComponent, ComboboxComponent], changeDetection: ChangeDetectionStrategy.Eager, template: "<hm-card *ngIf=\"loading\">\n <span class=\"muted\">{{ text.loading }}</span>\n</hm-card>\n\n<hm-alert *ngIf=\"!loading && loadError\" variant=\"error\">\n <div class=\"cp-error\">\n <span>{{ loadError }}</span>\n <hm-button emphasis=\"medium\" icon=\"refresh\" (clicked)=\"load()\">{{ text.retryLoad }}</hm-button>\n </div>\n</hm-alert>\n\n<hm-card *ngIf=\"!loading && !loadError && clients.length === 0\">\n <span [innerHTML]=\"text.noClients\"></span>\n</hm-card>\n\n<hm-card *ngIf=\"!loading && clients.length > 1\">\n <hm-combobox\n [label]=\"text.pickClient\"\n [options]=\"clientOptions\"\n [value]=\"selectedClientId\"\n (valueChange)=\"selectClient($event)\"\n ></hm-combobox>\n</hm-card>\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}:host{display:block}:host:empty{display:none}.cp-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--hm-space-sm)}\n"] }]
|
|
60
|
+
}], ctorParameters: () => [{ type: AutoServiceService }], propDecorators: { clientChange: [{
|
|
61
|
+
type: Output
|
|
62
|
+
}] } });
|
|
63
|
+
|
|
64
|
+
export { AutoServiceClientPickerComponent as A };
|
|
65
|
+
//# sourceMappingURL=trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trismegisto-spine-auto-service-auto-service-client-picker.component-Cl7ahisu.mjs","sources":["../../../projects/ui/auto-service/src/client-picker/auto-service-client-picker.component.ts","../../../projects/ui/auto-service/src/client-picker/auto-service-client-picker.component.html"],"sourcesContent":["import { Component, EventEmitter, OnInit, Output, ChangeDetectionStrategy, inject, ChangeDetectorRef } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { AlertComponent, ButtonComponent, CardComponent, ComboboxComponent, ComboboxOption } from '@trismegisto/angular';\nimport { formatMessage } from '@trismegisto/primitives';\nimport { AutoServiceService } from '../auto-service.service';\nimport { SPINE_MESSAGES } from '@trismegisto/spine';\n\nexport interface AutoServiceClient {\n id: string;\n name: string;\n display_name: string | null;\n realm_id: string;\n}\n\n@Component({\n selector: 'spine-auto-service-client-picker',\n standalone: true,\n imports: [CommonModule, AlertComponent, ButtonComponent, CardComponent, ComboboxComponent],\n changeDetection: ChangeDetectionStrategy.Eager,\n templateUrl: './auto-service-client-picker.component.html',\n styleUrl: './auto-service-client-picker.component.scss',\n})\nexport class AutoServiceClientPickerComponent implements OnInit {\n protected readonly text = inject(SPINE_MESSAGES).autoService;\n /** Telas com estado em campo comum, preenchido depois de `await`: marca a view ao terminar (app sem zone.js). */\n private readonly cdr = inject(ChangeDetectorRef);\n loading = true;\n clients: AutoServiceClient[] = [];\n selectedClientId = '';\n /**\n * Falha ao buscar os clients (Argos fora do ar, rede, 5xx): mostrada como erro, com \"Tentar de novo\". Antes caía na\n * lista vazia e a tela dizia \"você não administra este app\", que é outra coisa (falta de grupo ou de crachá).\n */\n loadError: string | null = null;\n @Output() clientChange = new EventEmitter<AutoServiceClient | null>();\n constructor(private service: AutoServiceService) {}\n\n get clientOptions(): ComboboxOption[] {\n return this.clients.map((c) => ({ value: c.id, label: c.display_name || c.name }));\n }\n\n ngOnInit() { void this.load(); }\n\n async load() {\n this.loading = true;\n this.loadError = null;\n try {\n const res = await this.service.getMyClients();\n this.clients = res.clients;\n if (this.clients.length === 1) this.selectClient(this.clients[0].id);\n } catch (err) {\n this.clients = [];\n const status = err instanceof HttpErrorResponse ? err.status : 0;\n this.loadError = formatMessage(this.text.clientsLoadError, { status });\n } finally { this.loading = false; this.cdr.markForCheck(); }\n }\n\n selectClient(id: string) {\n this.selectedClientId = id;\n this.clientChange.emit(this.clients.find(c => c.id === id) ?? null);\n }\n}\n","<hm-card *ngIf=\"loading\">\n <span class=\"muted\">{{ text.loading }}</span>\n</hm-card>\n\n<hm-alert *ngIf=\"!loading && loadError\" variant=\"error\">\n <div class=\"cp-error\">\n <span>{{ loadError }}</span>\n <hm-button emphasis=\"medium\" icon=\"refresh\" (clicked)=\"load()\">{{ text.retryLoad }}</hm-button>\n </div>\n</hm-alert>\n\n<hm-card *ngIf=\"!loading && !loadError && clients.length === 0\">\n <span [innerHTML]=\"text.noClients\"></span>\n</hm-card>\n\n<hm-card *ngIf=\"!loading && clients.length > 1\">\n <hm-combobox\n [label]=\"text.pickClient\"\n [options]=\"clientOptions\"\n [value]=\"selectedClientId\"\n (valueChange)=\"selectClient($event)\"\n ></hm-combobox>\n</hm-card>\n"],"names":["i1.AutoServiceService"],"mappings":"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"}
|