@controleonline/ui-customers 1.0.81 → 1.0.82
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/.github/workflows/integration-source-gate.yml +68 -0
- package/.github/workflows/publish-npm.yml +91 -0
- package/AGENTS.md +12 -6
- package/docs/technical/Client-Details-Criar-Usuario.md +113 -0
- package/package.json +5 -4
- package/src/react/components/tabs/AddressesTab.js +240 -335
- package/src/react/components/tabs/DocumentAttachments.js +270 -0
- package/src/react/components/tabs/DocumentsTab.js +355 -463
- package/src/react/components/tabs/DocumentsTab.styles.js +123 -0
- package/src/react/components/tabs/EmployeeCreateFormFields.js +203 -0
- package/src/react/components/tabs/EmployeesTab.js +17 -171
- package/src/react/components/tabs/EmployeesTab.styles.js +220 -172
- package/src/react/components/tabs/GeneralTab.js +84 -46
- package/src/react/components/tabs/GeneralTab.styles.js +81 -77
- package/src/react/components/tabs/MediaTab.js +50 -5
- package/src/react/components/tabs/PeopleCategoriesPanel.js +161 -78
- package/src/react/components/tabs/SalesmanTab.js +1 -1
- package/src/react/components/tabs/UserFormModal.js +26 -2
- package/src/react/components/tabs/UsersTab.js +30 -19
- package/src/react/components/tabs/UsersTab.styles.js +257 -257
- package/src/react/components/tabs/UsersTabApiKeyModal.js +115 -0
- package/src/react/components/tabs/UsersTabUserModal.js +222 -0
- package/src/react/components/tabs/addressesTabHelpers.js +190 -0
- package/src/react/components/tabs/documentsTabHelpers.js +142 -0
- package/src/react/components/tabs/employeeContacts.js +3 -23
- package/src/react/components/tabs/employeeUnlink.js +7 -4
- package/src/react/components/tabs/employeesTabHelpers.js +33 -9
- package/src/react/components/tabs/generalTabHelpers.js +30 -8
- package/src/react/components/tabs/useGeneralTabPeopleLink.js +68 -0
- package/src/react/components/tabs/usersTabHelpers.js +24 -23
- package/src/react/pages/details.page.styles.js +114 -100
- package/src/react/utils/humanCompanyLinkTypes.js +28 -0
- package/src/tests/browser/manager/client-details-add-user-modal.spec.js +281 -0
- package/src/tests/browser/manager/client-details-address-create-coords.spec.js +414 -0
- package/src/tests/browser/manager/client-details-address-edit.spec.js +331 -0
- package/src/tests/browser/manager/client-details-contact-edit.spec.js +198 -0
- package/src/tests/browser/manager/client-details-create-contact.spec.js +306 -0
- package/src/tests/browser/manager/client-details-documents.spec.js +346 -0
- package/src/tests/browser/manager/client-details-identity-case.spec.js +227 -0
- package/src/tests/browser/manager/client-details-people-type.manifest.md +18 -0
- package/src/tests/browser/manager/client-details-people-type.spec.js +345 -0
- package/src/tests/browser/manager/client-details-supplier-product-create.spec.js +334 -0
- package/src/tests/browser/manager/client-details-users-tab-load.spec.js +194 -0
- package/src/tests/browser/manager/employees-salesman-after-sales.spec.js +441 -0
- package/src/tests/react/components/SalesmanTab.company.test.js +40 -0
- package/src/tests/react/components/tabs/UsersTab.styles.test.js +39 -0
- package/src/tests/react/components/tabs/addressesTabHelpers.test.js +78 -0
- package/src/tests/react/components/tabs/documentsTabContract.test.mjs +37 -0
- package/src/tests/react/components/tabs/documentsTabHelpers.test.mjs +93 -0
- package/src/tests/react/components/tabs/employeeContacts.test.js +46 -4
- package/src/tests/react/components/tabs/employeeLinkTypes.contract.test.mjs +52 -0
- package/src/tests/react/components/tabs/employeeUnlink.test.js +11 -11
- package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +2 -23
- package/src/tests/react/components/tabs/employeesTabHelpers.test.js +59 -0
- package/src/tests/react/components/tabs/generalTabHelpers.test.js +35 -0
- package/src/tests/react/components/tabs/peopleMediaTabs.test.js +217 -217
- package/src/tests/react/components/tabs/peopleType.contract.test.mjs +47 -0
- package/src/tests/react/components/tabs/resolveSeededLinkType.test.mjs +20 -0
- package/src/tests/react/components/tabs/salesmanTabMedia.no-redeclare.test.mjs +33 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.js +20 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.mjs +63 -0
- package/src/tests/react/utils/humanCompanyLinkTypes.test.js +50 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Integration source gate
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [dev, staging, master]
|
|
6
|
+
types: [opened, synchronize, reopened, edited, ready_for_review]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
source-policy:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Enforce task or frozen RC source
|
|
17
|
+
env:
|
|
18
|
+
HEAD_REF: ${{ github.head_ref }}
|
|
19
|
+
BASE_REF: ${{ github.base_ref }}
|
|
20
|
+
run: |
|
|
21
|
+
set -eu
|
|
22
|
+
if [ "$BASE_REF" = "dev" ]; then
|
|
23
|
+
echo "$HEAD_REF" | grep -Eq '^task-[1-9][0-9]*$' || {
|
|
24
|
+
echo "::error::dev only accepts task-<numeric issue>."
|
|
25
|
+
exit 1
|
|
26
|
+
}
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
echo "$HEAD_REF" | grep -Eq '^rc/[0-9]+\.[0-9]+\.[0-9]+-rc\.[1-9][0-9]*$' || {
|
|
30
|
+
echo "::error::$BASE_REF only accepts a frozen rc/X.Y.Z-rc.N source."
|
|
31
|
+
exit 1
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
if: github.base_ref != 'dev'
|
|
36
|
+
with:
|
|
37
|
+
ref: ${{ github.head_ref }}
|
|
38
|
+
|
|
39
|
+
- name: Validate frozen RC manifest
|
|
40
|
+
if: github.base_ref != 'dev'
|
|
41
|
+
env:
|
|
42
|
+
HEAD_REF: ${{ github.head_ref }}
|
|
43
|
+
run: |
|
|
44
|
+
set -eu
|
|
45
|
+
test -f .release/rc-manifest.json || {
|
|
46
|
+
echo "::error::Missing .release/rc-manifest.json"
|
|
47
|
+
exit 1
|
|
48
|
+
}
|
|
49
|
+
node --input-type=module <<'NODE'
|
|
50
|
+
import fs from 'node:fs';
|
|
51
|
+
const m = JSON.parse(fs.readFileSync('.release/rc-manifest.json', 'utf8'));
|
|
52
|
+
const branch = process.env.HEAD_REF;
|
|
53
|
+
const match = /^rc\/(\d+\.\d+\.\d+)-rc\.([1-9][0-9]*)$/.exec(branch);
|
|
54
|
+
if (!match) throw new Error('invalid RC branch');
|
|
55
|
+
if (m.branch !== branch || m.version !== match[1] || Number(m.rc) !== Number(match[2])) throw new Error('manifest identity mismatch');
|
|
56
|
+
if (m.frozen !== true) throw new Error('manifest is not frozen');
|
|
57
|
+
if (!Array.isArray(m.tasks) || m.tasks.length < 1 || m.tasks.length > 5) throw new Error('RC must contain 1..5 tasks');
|
|
58
|
+
const tasks = m.tasks.map(Number);
|
|
59
|
+
if (tasks.some((id) => !Number.isInteger(id) || id < 1)) throw new Error('invalid task id');
|
|
60
|
+
if (new Set(tasks).size !== tasks.length) throw new Error('duplicate RC tasks');
|
|
61
|
+
if (!/^[0-9a-f]{40}$/i.test(String(m.baseMaster || ''))) throw new Error('invalid baseMaster');
|
|
62
|
+
const repos = m.repositories || {};
|
|
63
|
+
if (!Object.keys(repos).length) throw new Error('empty repositories manifest');
|
|
64
|
+
for (const [repo, sha] of Object.entries(repos)) {
|
|
65
|
+
if (!/^ControleOnline\/[A-Za-z0-9_.-]+$/.test(repo) || !/^[0-9a-f]{40}$/i.test(String(sha))) throw new Error('invalid repository manifest entry');
|
|
66
|
+
}
|
|
67
|
+
console.log('Frozen RC manifest valid:', branch, tasks);
|
|
68
|
+
NODE
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.repository }}-npm-release
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
publish:
|
|
16
|
+
if: ${{ github.repository_owner == 'ControleOnline' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) }}
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
ref: ${{ github.ref }}
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
- name: Validate package metadata and create version tag
|
|
24
|
+
id: release
|
|
25
|
+
env:
|
|
26
|
+
REF_TYPE: ${{ github.ref_type }}
|
|
27
|
+
REF_NAME: ${{ github.ref_name }}
|
|
28
|
+
EXPECTED_REPOSITORY: ${{ github.repository }}
|
|
29
|
+
run: |
|
|
30
|
+
node <<'NODE'
|
|
31
|
+
const fs = require('node:fs');
|
|
32
|
+
const cp = require('node:child_process');
|
|
33
|
+
const pkg = require('./package.json');
|
|
34
|
+
const expectedUrl = `https://github.com/${process.env.EXPECTED_REPOSITORY}`;
|
|
35
|
+
if (!/^\d+\.\d+\.\d+$/.test(String(pkg.version))) throw new Error(`Expected stable X.Y.Z, got ${pkg.version}`);
|
|
36
|
+
if (pkg.repository?.url !== expectedUrl) throw new Error(`repository.url must be ${expectedUrl}; got ${pkg.repository?.url}`);
|
|
37
|
+
const sourceSha = cp.execFileSync('git', ['rev-parse', 'HEAD'], {encoding:'utf8'}).trim();
|
|
38
|
+
let tag = '';
|
|
39
|
+
if (process.env.REF_TYPE === 'tag') {
|
|
40
|
+
tag = process.env.REF_NAME;
|
|
41
|
+
if (tag !== `v${pkg.version}`) throw new Error(`Tag ${tag} does not match package version ${pkg.version}`);
|
|
42
|
+
} else {
|
|
43
|
+
let previous = '';
|
|
44
|
+
try { previous = JSON.parse(cp.execFileSync('git', ['show', `${sourceSha}^:package.json`], {encoding:'utf8'})).version || ''; } catch {}
|
|
45
|
+
if (previous === pkg.version) { fs.appendFileSync(process.env.GITHUB_OUTPUT, 'release_tag=\n'); process.exit(0); }
|
|
46
|
+
const parts = String(pkg.version).split('.').map(Number);
|
|
47
|
+
if (previous) {
|
|
48
|
+
const old = String(previous).split('.').map(Number);
|
|
49
|
+
let cmp = 0; for (let i=0;i<3;i++) { if ((parts[i]||0)!==(old[i]||0)) { cmp=(parts[i]||0)>(old[i]||0)?1:-1; break; } }
|
|
50
|
+
if (cmp <= 0) throw new Error(`Version ${pkg.version} must be greater than first-parent version ${previous}`);
|
|
51
|
+
}
|
|
52
|
+
tag = `v${pkg.version}`;
|
|
53
|
+
const existing = cp.spawnSync('git', ['ls-remote', '--exit-code', '--refs', 'origin', `refs/tags/${tag}`], {encoding:'utf8'});
|
|
54
|
+
if (existing.status === 0) {
|
|
55
|
+
cp.execFileSync('git', ['fetch', 'origin', `refs/tags/${tag}:refs/tags/${tag}`], {stdio:'inherit'});
|
|
56
|
+
const tagged = cp.execFileSync('git', ['rev-parse', `${tag}^{commit}`], {encoding:'utf8'}).trim();
|
|
57
|
+
if (tagged !== sourceSha) throw new Error(`Immutable tag ${tag} already points at ${tagged}, not ${sourceSha}`);
|
|
58
|
+
} else {
|
|
59
|
+
cp.execFileSync('git', ['config', 'user.name', 'github-actions[bot]']);
|
|
60
|
+
cp.execFileSync('git', ['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
|
|
61
|
+
cp.execFileSync('git', ['tag', '-a', tag, sourceSha, '-m', `Release ${pkg.name}@${pkg.version}`], {stdio:'inherit'});
|
|
62
|
+
cp.execFileSync('git', ['push', 'origin', `refs/tags/${tag}`], {stdio:'inherit'});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `release_tag=${tag}\n`);
|
|
66
|
+
console.log(`Validated ${pkg.name}@${pkg.version} from ${sourceSha}; release tag ${tag}`);
|
|
67
|
+
NODE
|
|
68
|
+
- uses: actions/setup-node@v4
|
|
69
|
+
if: steps.release.outputs.release_tag != ''
|
|
70
|
+
with:
|
|
71
|
+
node-version: 24
|
|
72
|
+
- name: Ensure npm 11.5.1+ (OIDC support)
|
|
73
|
+
if: steps.release.outputs.release_tag != ''
|
|
74
|
+
run: |
|
|
75
|
+
npm install --global npm@latest
|
|
76
|
+
npm --version
|
|
77
|
+
- name: Skip if version is already on npm
|
|
78
|
+
id: registry
|
|
79
|
+
if: steps.release.outputs.release_tag != ''
|
|
80
|
+
run: |
|
|
81
|
+
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
82
|
+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
83
|
+
if npm view "$PACKAGE_NAME@$PACKAGE_VERSION" version >/dev/null 2>&1; then
|
|
84
|
+
echo 'published=true' >> "$GITHUB_OUTPUT"
|
|
85
|
+
echo "$PACKAGE_NAME@$PACKAGE_VERSION is already published; skipping duplicate publish"
|
|
86
|
+
else
|
|
87
|
+
echo 'published=false' >> "$GITHUB_OUTPUT"
|
|
88
|
+
fi
|
|
89
|
+
- name: Publish to npmjs with trusted publishing
|
|
90
|
+
if: steps.release.outputs.release_tag != '' && steps.registry.outputs.published != 'true'
|
|
91
|
+
run: npm publish --access public --loglevel verbose
|
package/AGENTS.md
CHANGED
|
@@ -22,20 +22,20 @@ Sempre comece pela **Home** da wiki e siga as categorias abaixo.
|
|
|
22
22
|
| Página | O que documenta |
|
|
23
23
|
| --- | --- |
|
|
24
24
|
| [Cliente × Vendedor — vínculo e permissões](https://github.com/ControleOnline/ui-customers/wiki/Cliente-Vendedor-Vinculo-e-Permissoes) | Aba Vendedores no detalhe; corte MANAGER vs CRM/outros |
|
|
25
|
-
| [Client Details —
|
|
25
|
+
| [Client Details — criar usuário (UsersTab)](https://github.com/ControleOnline/ui-customers/wiki/Client-Details-Criar-Usuario) | Criação de usuário no detalhe; people em IRI; auth ROLE_HUMAN |
|
|
26
26
|
| [Client Details — preservação de capitalização (nome/alias)](https://github.com/ControleOnline/ui-customers/wiki/Client-Details-People-Name-Case) | Nome/alias de pessoa/colaborador sem forçar CAIXA ALTA (UI + API) |
|
|
27
27
|
| Página canônica do fluxo (CRM) | https://github.com/ControleOnline/ui-crm/wiki/Cliente-Vendedor-Vinculo-e-Permissoes |
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Cópias versionadas no Git: `docs/technical/Cliente-Vendedor-Vinculo-e-Permissoes.md`, `docs/technical/Client-Details-Criar-Usuario.md`, `docs/technical/Client-Details-People-Name-Case.md`
|
|
30
30
|
|
|
31
31
|
### Visão deste módulo
|
|
32
32
|
|
|
33
33
|
`ui-customers` é o **detalhe e cadastro de pessoas/clientes** reutilizado por várias visões do app (`CRM`, `MANAGER`, `POS`, etc.).
|
|
34
34
|
|
|
35
|
-
- Dono da tela `ClientDetails` e abas (geral, contatos, documentos, **vendedores**,
|
|
35
|
+
- Dono da tela `ClientDetails` e abas (geral, contatos, documentos, **vendedores**, etc.).
|
|
36
36
|
- No fluxo comercial, recebe handoff do `ui-crm`.
|
|
37
|
-
- Gestão administrativa de vendedores
|
|
38
|
-
- Fora de `MANAGER` (ex.: CRM): pode identificar o vendedor
|
|
37
|
+
- Gestão administrativa de vendedores e comissões: apenas quando `APP_TYPE=MANAGER`.
|
|
38
|
+
- Fora de `MANAGER` (ex.: CRM): pode identificar o vendedor, sem expor comissão nem CRUD administrativo.
|
|
39
39
|
|
|
40
40
|
## Regras específicas
|
|
41
41
|
|
|
@@ -44,7 +44,13 @@ Cópia versionada no Git: `docs/technical/Cliente-Vendedor-Vinculo-e-Permissoes.
|
|
|
44
44
|
### Módulos relacionados (mesmo fluxo)
|
|
45
45
|
|
|
46
46
|
| Módulo | Papel | Entrada da documentação |
|
|
47
|
-
| --- | --- |
|
|
47
|
+
| --- | --- | --- |
|
|
48
48
|
| `ui-crm` | Entrada comercial / handoff | https://github.com/ControleOnline/ui-crm/wiki |
|
|
49
49
|
| `api-platform-people` | Backend `people_link` / SalesmanService | https://github.com/ControleOnline/api-platform-people/wiki |
|
|
50
|
+
| `api-platform-users` | Backend `POST /users` (ROLE_HUMAN) | https://github.com/ControleOnline/api-platform-users/wiki |
|
|
50
51
|
| `app-community` | Home do app e mapa de submódulos | https://github.com/ControleOnline/app-community/wiki |
|
|
52
|
+
|
|
53
|
+
### Usuários no detalhe de pessoa
|
|
54
|
+
|
|
55
|
+
- Aba `UsersTab` em `src/react/components/tabs/` (helpers em `usersTabHelpers.js`, modais em `UserFormModal` / `UserApiKeyModal`).
|
|
56
|
+
- Lista geral da empresa: `UsersPage` em `ui-users` (rota Manager `UsersPage` / path `users`).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Client Details — criar usuário (UsersTab)
|
|
2
|
+
|
|
3
|
+
Documentação técnica do fluxo de **criação de usuário** na tela **Client Details** (`/client-details`), com foco no contexto `contextKey=employee` e demais contexts que reutilizam a aba Usuários.
|
|
4
|
+
|
|
5
|
+
Trilha de origem: [app-community#369](https://github.com/ControleOnline/app-community/issues/369).
|
|
6
|
+
|
|
7
|
+
## Como este módulo se encaixa
|
|
8
|
+
|
|
9
|
+
| Visão (`APP_TYPE`) | Uso neste fluxo |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| **MANAGER** | Detalhe administrativo de pessoa/cliente/colaborador; aba **Usuários** permite listar e **criar** usuário vinculado à pessoa |
|
|
12
|
+
| **CRM** / outros | Reutilizam `ClientDetails` conforme rota e `contextKey`; a mesma aba e contrato de API se aplicam quando a tab de usuários está visível |
|
|
13
|
+
|
|
14
|
+
`contextKey` (query) seleciona o modo do detalhe (`employee`, `client`, `provider`, contatos, etc.). A criação de usuário na aba Usuários **não** depende de um `contextKey` exclusivo: o contrato de payload e autenticação é o mesmo.
|
|
15
|
+
|
|
16
|
+
## Objetivo
|
|
17
|
+
|
|
18
|
+
Registrar regras de negócio, contratos de API e modularização do fluxo:
|
|
19
|
+
|
|
20
|
+
1. listagem de usuários da pessoa no detalhe;
|
|
21
|
+
2. criação de usuário via `POST /users` com autenticação de sessão e vínculo correto à pessoa (IRI);
|
|
22
|
+
3. feedback de sucesso/erro (incluindo falhas de autenticação);
|
|
23
|
+
4. componentes e helpers ≤ 500 linhas, com testes unitários e smoke browser.
|
|
24
|
+
|
|
25
|
+
## Repositórios afetados
|
|
26
|
+
|
|
27
|
+
| Módulo | Papel no fluxo |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `ui-customers` | Página `ClientDetails`, aba `UsersTab`, helpers e smoke de criação |
|
|
30
|
+
| `api-platform-users` | Recurso `User`, operação `POST /users` (`CreateUserAction`), security `ROLE_HUMAN` |
|
|
31
|
+
| `app-community` | Composição / pin dos submódulos; rota `/client-details` |
|
|
32
|
+
|
|
33
|
+
## Regras de negócio (UI)
|
|
34
|
+
|
|
35
|
+
### Entrada
|
|
36
|
+
|
|
37
|
+
- Rota: `/client-details?clientId=<id>&contextKey=<contexto>` (ex.: `employee`).
|
|
38
|
+
- Aba: **Usuários** (`UsersTab`), ou equivalente quando o detalhe expõe a tab de usuários.
|
|
39
|
+
- Ação: **Adicionar Usuário** → modal com username, senha, confirmação (e timezone quando aplicável).
|
|
40
|
+
|
|
41
|
+
### Criação — contrato do payload
|
|
42
|
+
|
|
43
|
+
O frontend **deve** enviar:
|
|
44
|
+
|
|
45
|
+
| Campo | Formato | Observação |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `username` | string | Obrigatório |
|
|
48
|
+
| `password` | string | Obrigatório (política de senha via `ui-common`) |
|
|
49
|
+
| `people` | **IRI** `/people/{id}` | **Não** enviar id numérico nu (`"106218"`). Use `toPeopleIri(client.id \| client['@id'])` |
|
|
50
|
+
| `timezone` | IRI `/timezones/{id}` ou omitido | Opcional |
|
|
51
|
+
|
|
52
|
+
Helper canônico: `toPeopleIri` em `src/react/components/tabs/usersTabHelpers.js`.
|
|
53
|
+
|
|
54
|
+
### Autenticação na requisição
|
|
55
|
+
|
|
56
|
+
- O `POST /users` exige usuário autenticado com papel **`ROLE_HUMAN`** (`securityPostDenormalize` na operação Post do recurso `User`).
|
|
57
|
+
- A camada de API do app deve enviar o token/header de sessão válido (ex.: `API-TOKEN`). Ausência de credencial resulta em falha de auth (historicamente o backend podia responder HTTP 500 com `{"message":"Authentication required"}`; a UI trata 401 e a mensagem “Authentication required” de forma explícita).
|
|
58
|
+
|
|
59
|
+
### Feedback de erro
|
|
60
|
+
|
|
61
|
+
`extractErrorMessage` (mesmo helpers):
|
|
62
|
+
|
|
63
|
+
- HTTP **401** → mensagem orientando novo login;
|
|
64
|
+
- corpo com texto *Authentication required* → mesma mensagem amigável em PT;
|
|
65
|
+
- violações de validação / política de senha → mapeadas via `mapPasswordErrorMessage`.
|
|
66
|
+
|
|
67
|
+
Após sucesso, o usuário criado entra na listagem local da aba (normalização via `normalizeUserItem`).
|
|
68
|
+
|
|
69
|
+
## Regras de negócio (API)
|
|
70
|
+
|
|
71
|
+
| Operação | Segurança | Controller |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `POST /users` | `is_granted('ROLE_HUMAN')` (securityPostDenormalize) | `CreateUserAction` → `UserService::createUserFromContent` |
|
|
74
|
+
| `DELETE /users/{id}` | `ROLE_HUMAN` | `DeleteUserAction` |
|
|
75
|
+
| change-api-key / change-password | `ROLE_HUMAN` | controllers dedicados |
|
|
76
|
+
|
|
77
|
+
O vínculo com a pessoa é feito pelo campo `people` no payload (IRI). Payload com id nu (sem `/people/`) quebra a deserialização/associação e pode se manifestar como erro genérico de autenticação no cliente — por isso o frontend **obrigatoriamente** normaliza para IRI.
|
|
78
|
+
|
|
79
|
+
## Modularização (UI)
|
|
80
|
+
|
|
81
|
+
| Arquivo | Papel |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `src/react/pages/details.js` | `ClientDetails`, resolução de `contextKey` e tabs |
|
|
84
|
+
| `src/react/components/tabs/UsersTab.js` | Listagem + fluxo create/edit (orquestra store `users`) |
|
|
85
|
+
| `src/react/components/tabs/UsersTabUserModal.js` / `UsersTabApiKeyModal.js` | Modais extraídos |
|
|
86
|
+
| `src/react/components/tabs/usersTabHelpers.js` | `toPeopleIri`, `extractErrorMessage`, `normalizeUserItem`, etc. |
|
|
87
|
+
|
|
88
|
+
Limite absoluto de linhas do projeto: **≤ 500** por arquivo.
|
|
89
|
+
|
|
90
|
+
## Testes
|
|
91
|
+
|
|
92
|
+
| Tipo | Local | Cobertura |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| Unit | `src/tests/react/components/tabs/usersTabHelpers.test.js` (e `.mjs`) | `toPeopleIri`, `extractErrorMessage` (401 / Authentication required), normalização |
|
|
95
|
+
| Browser smoke | `src/tests/browser/manager/client-details-create-user.spec.js` | `/client-details?...&contextKey=employee&initialTab=users` → Adicionar Usuário → POST com token + people IRI → sucesso na listagem |
|
|
96
|
+
|
|
97
|
+
## O que este módulo **não** faz
|
|
98
|
+
|
|
99
|
+
- Não redefine o fluxo de login do usuário recém-criado.
|
|
100
|
+
- Não altera o contrato público de auto-cadastro (outra trilha em `api-platform-people` / auto-cadastro).
|
|
101
|
+
- Não é o enforce de autorização no backend — a UI apenas envia o token de sessão e o IRI correto; o gate real é `ROLE_HUMAN` no `POST /users`.
|
|
102
|
+
|
|
103
|
+
## Links cruzados
|
|
104
|
+
|
|
105
|
+
| Destino | URL |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| Home deste módulo | https://github.com/ControleOnline/ui-customers/wiki |
|
|
108
|
+
| Backend users (Home) | https://github.com/ControleOnline/api-platform-users/wiki |
|
|
109
|
+
| App home | https://github.com/ControleOnline/app-community/wiki |
|
|
110
|
+
| Issue de origem | https://github.com/ControleOnline/app-community/issues/369 |
|
|
111
|
+
| Visões do app | https://github.com/ControleOnline/app-community/blob/master/MODOS_OPERACAO.md |
|
|
112
|
+
|
|
113
|
+
Cópia versionada no Git: `docs/technical/Client-Details-Criar-Usuario.md`
|
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@controleonline/ui-customers",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.82",
|
|
4
4
|
"author": "ControleOnline",
|
|
5
5
|
"description": "ControleOnline customers Quasar UI Component",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/react/index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "npm run test:supplier-product-flow && npm run test:fiscal-shortcut && npm run test:
|
|
9
|
+
"test": "npm run test:supplier-product-flow && npm run test:fiscal-shortcut && npm run test:people-type && npm run test:salesman-tab",
|
|
10
|
+
"test:people-type": "node --test src/tests/react/components/tabs/peopleType.contract.test.mjs",
|
|
10
11
|
"test:supplier-product-flow": "node --test src/tests/react/domain/productSupplierFlow.test.mjs",
|
|
11
12
|
"test:fiscal-shortcut": "node --test src/tests/react/components/tabs/fiscalTabContract.test.mjs",
|
|
12
13
|
"test:documents": "node --test src/tests/react/components/tabs/documentsTabHelpers.test.mjs src/tests/react/components/tabs/documentsTabContract.test.mjs",
|
|
13
14
|
"test:employee-link-types": "node --test src/tests/react/components/tabs/employeeLinkTypes.contract.test.mjs",
|
|
14
|
-
"test:salesman-tab": "node --test src/tests/react/components/tabs/salesmanTab.helpers.test.mjs src/tests/react/components/tabs/salesmanTabHelpers.test.mjs"
|
|
15
|
+
"test:salesman-tab": "node --test src/tests/react/components/tabs/salesmanTab.helpers.test.mjs src/tests/react/components/tabs/salesmanTabHelpers.test.mjs src/tests/react/components/tabs/salesmanTabMedia.no-redeclare.test.mjs"
|
|
15
16
|
},
|
|
16
17
|
"repository": {
|
|
17
18
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/ControleOnline/ui-customers"
|
|
19
20
|
},
|
|
20
21
|
"bugs": "",
|
|
21
22
|
"homepage": "https://www.controleonline.com/devs/plugins",
|