@controleonline/ui-default 1.0.270 → 1.0.273
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/manager-worker.yml +19 -0
- package/.github/workflows/publish-npm.yml +91 -0
- package/AGENTS.md +46 -50
- package/docs/technical/Contrato-de-colunas.md +67 -0
- package/docs/technical/Default-Components.md +76 -0
- package/docs/technical/DefaultForm.md +80 -0
- package/docs/technical/DefaultInput-e-DefaultSelect.md +73 -0
- package/docs/technical/DefaultTable.md +272 -0
- package/docs/wiki.md +1 -0
- package/package.json +4 -3
- package/scripts/validate-wiki-pointer.cjs +13 -0
- package/src/react/components/address/DefaultAddress.js +446 -0
- package/src/react/components/address/DefaultAddress.styles.js +133 -0
- package/src/react/components/address/DefaultAddressCoordFields.js +59 -0
- package/src/react/components/address/DefaultAddressMapPane.js +55 -0
- package/src/react/components/address/LatLonReadonlyFields.js +51 -0
- package/src/react/components/address/defaultAddressHelpers.js +163 -0
- package/src/react/components/address/defaultAddressStyles.js +148 -0
- package/src/react/components/address/defaultAddressUtils.js +129 -0
- package/src/react/components/extra-data/DefaultExtraData.js +152 -0
- package/src/react/components/extra-data/DefaultExtraData.styles.js +61 -0
- package/src/react/components/files/DefaultFile.js +231 -46
- package/src/react/components/files/DefaultFileColumn.js +123 -0
- package/src/react/components/files/DefaultFileColumn.styles.js +52 -0
- package/src/react/components/files/DefaultFileColumn.utils.js +104 -0
- package/src/react/components/filters/CompactFilterSelector.js +51 -35
- package/src/react/components/filters/DefaultColumnFilter.js +60 -48
- package/src/react/components/filters/DefaultExternalFilters.js +324 -265
- package/src/react/components/filters/filterValue.js +65 -0
- package/src/react/components/form/DefaultForm.js +99 -79
- package/src/react/components/help/DefaultTooltip.js +48 -12
- package/src/react/components/help/DefaultTooltip.styles.js +20 -0
- package/src/react/components/inputs/DefaultColorInput.js +153 -0
- package/src/react/components/inputs/DefaultFeatherIconPicker.js +146 -0
- package/src/react/components/inputs/DefaultFeatherIconPicker.styles.js +113 -0
- package/src/react/components/inputs/DefaultInput.js +296 -141
- package/src/react/components/inputs/DefaultInput.styles.js +26 -0
- package/src/react/components/inputs/DefaultSelect.js +134 -123
- package/src/react/components/inputs/defaultInputUtils.js +262 -213
- package/src/react/components/map/DefaultMap.native.js +73 -73
- package/src/react/components/map/DefaultMap.shared.js +911 -762
- package/src/react/components/map/DefaultMap.web.js +124 -68
- package/src/react/components/table/DefaultColumnMenu.js +22 -3
- package/src/react/components/table/DefaultDebug.js +44 -37
- package/src/react/components/table/DefaultSearchModal.js +9 -1
- package/src/react/components/table/DefaultTable.grouping.js +98 -0
- package/src/react/components/table/DefaultTable.js +217 -111
- package/src/react/components/table/DefaultTable.styles.js +369 -310
- package/src/react/components/table/DefaultTable.utils.js +38 -4
- package/src/react/components/table/DefaultTableBody.js +13 -8
- package/src/react/components/table/DefaultTableCards.js +20 -1
- package/src/react/components/table/DefaultTableControls.js +180 -205
- package/src/react/components/table/DefaultTableImportModal.js +108 -0
- package/src/react/components/table/DefaultTableInput.js +1 -0
- package/src/react/components/table/DefaultTableRowActions.js +1 -1
- package/src/react/components/table/DefaultTableRows.js +357 -325
- package/src/react/components/table/DefaultTableSearch.js +28 -5
- package/src/react/components/table/DefaultTableToolbar.js +92 -3
- package/src/react/components/table/useDefaultTablePagination.js +56 -7
- package/src/react/components/table/useDefaultTableStoreSync.js +164 -0
- package/src/react/components/upload/DefaultUpload.js +406 -0
- package/src/react/components/upload/DefaultUpload.styles.js +153 -0
- package/src/react/components/upload/DefaultUploadAttachmentsList.js +146 -0
- package/src/react/components/upload/DefaultUploadManagerModal.js +247 -0
- package/src/react/components/upload/defaultUploadHelpers.js +108 -0
- package/src/react/components/upload/defaultUploadLibrary.js +248 -0
- package/src/react/components/upload/fileUpload.js +93 -0
- package/src/react/hooks/usePostalCodeLookup.js +159 -0
- package/src/react/index.js +6 -0
- package/src/react/services/addressFormUtils.js +262 -0
- package/src/react/services/addressGeo.js +230 -0
- package/src/react/utils/tableVisibleColumnsPreferences.js +113 -15
- package/src/tests/react/components/address/defaultAddressHelpers.test.js +104 -0
- package/src/tests/react/components/files/DefaultFile.test.js +22 -6
- package/src/tests/react/components/files/DefaultFileColumn.company.test.js +24 -0
- package/src/tests/react/components/form/DefaultForm.test.js +123 -0
- package/src/tests/react/components/help/DefaultTooltip.test.js +93 -0
- package/src/tests/react/components/inputs/DefaultSelect.test.js +108 -79
- package/src/tests/react/components/table/DefaultTable.grouping.test.js +49 -0
- package/src/tests/react/components/table/DefaultTable.test.js +53 -2
- package/src/tests/react/components/table/DefaultTable.utils.test.js +10 -0
- package/src/tests/react/components/table/DefaultTableControls.filters.test.mjs +21 -0
- package/src/tests/react/components/table/DefaultTableRowActions.test.js +23 -0
- package/src/tests/react/components/table/DefaultTableRows.rowActions.test.js +152 -0
- package/src/tests/react/components/table/resolveRowBackgroundColor.test.mjs +45 -0
- package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +161 -0
- package/src/tests/react/components/upload/DefaultUpload.test.js +353 -0
- package/src/tests/react/components/upload/defaultUploadLibrary.test.js +104 -0
- package/src/tests/react/components/upload/peopleMediaLibraryPreview.test.mjs +57 -0
- package/src/tests/react/filters/filterValue.test.js +46 -0
- package/src/tests/react/hooks/usePostalCodeLookup.test.js +107 -0
- package/src/tests/react/inputs/defaultInputUtils.test.js +9 -1
- package/src/tests/react/services/SMOKE-637-cep-hydrate.md +45 -0
- package/src/tests/react/services/addressFormUtils.test.js +179 -0
- package/src/tests/react/services/addressGeoLookup.async.test.js +104 -0
- package/src/tests/react/services/addressGeoLookup.test.js +105 -0
- package/src/tests/react/services/smoke-637/form-cep-12941040.png +0 -0
- package/src/tests/react/services/smoke-637/index.html +132 -0
- package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +96 -49
|
@@ -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,19 @@
|
|
|
1
|
+
name: Manager Worker
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
# PAUSA CTO ControleOnline/agents-mcp#201 (2026-08-29)
|
|
7
|
+
# Trigger original desativado: push em master, dev, staging.
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
issues: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
manager:
|
|
16
|
+
name: Manager — paused
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- run: echo "Manager Worker paused by ControleOnline/agents-mcp#201"
|
|
@@ -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
|
@@ -1,50 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- `
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Telas antigas devem ser simplificadas para passar o store e apenas as excecoes declarativas que o store nao cobre.
|
|
49
|
-
- Se a listagem precisa de outra regra de exibicao, a primeira opcao e mover essa regra para `columns` ou para o store correspondente.
|
|
50
|
-
- Se duas telas repetem a mesma logica de listagem, a resposta e um componente default ou um ajuste no `DefaultTable`, nunca uma copia local do comportamento.
|
|
1
|
+
## Ponto de entrada
|
|
2
|
+
|
|
3
|
+
- A documentação funcional e de regras deste modulo vive na **wiki do proprio repositório** e na wiki principal do app.
|
|
4
|
+
- Regras transversais de qualidade, modularizacao e limites de componente vivem em `https://github.com/ControleOnline/agents-mcp/blob/master/skills/shared/code-quality.md`.
|
|
5
|
+
- Quando houver detalhe especifico de implementacao, prefira comentar no codigo em ingles perto da regra.
|
|
6
|
+
- Este arquivo deve ficar curto e servir apenas como ponte para as fontes oficiais.
|
|
7
|
+
|
|
8
|
+
## Documentação (navegação humana)
|
|
9
|
+
|
|
10
|
+
| Categoria | Destino |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| Home do módulo | https://github.com/ControleOnline/ui-default/wiki |
|
|
13
|
+
| Wiki principal do app | https://github.com/ControleOnline/app-community/wiki |
|
|
14
|
+
|
|
15
|
+
### Componentes Default*
|
|
16
|
+
|
|
17
|
+
| Página | O que documenta |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| [Índice Default*](https://github.com/ControleOnline/ui-default/wiki/Default-Components) | Mapa da família e arquitetura |
|
|
20
|
+
| [DefaultTable](https://github.com/ControleOnline/ui-default/wiki/DefaultTable) | Listagens, store contract, view modes, **hydrate único de filtros** (`useDefaultTableStoreSync`, anti #185) |
|
|
21
|
+
| [DefaultForm](https://github.com/ControleOnline/ui-default/wiki/DefaultForm) | Create/edit genérico |
|
|
22
|
+
| [DefaultInput e DefaultSelect](https://github.com/ControleOnline/ui-default/wiki/DefaultInput-e-DefaultSelect) | Campos e listas |
|
|
23
|
+
| [Contrato de colunas](https://github.com/ControleOnline/ui-default/wiki/Contrato-de-colunas) | Flags e serialização |
|
|
24
|
+
|
|
25
|
+
Cópias versionadas: `docs/technical/*.md`
|
|
26
|
+
|
|
27
|
+
### Visão deste módulo
|
|
28
|
+
|
|
29
|
+
`ui-default` é a **biblioteca de UI genérica** (tabela, form, inputs, filtros, upload, mapa) consumida pelos submódulos do `app-community`. Não carrega regra de domínio de um `APP_TYPE` específico; o domínio entra via `storeName` + `columns`.
|
|
30
|
+
|
|
31
|
+
### DefaultUpload (app-community#296)
|
|
32
|
+
|
|
33
|
+
| Página / arquivo | O que documenta |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `src/react/components/upload/DefaultUpload.js` | Mini gerenciador de arquivos por **contexto** (biblioteca + anexos da entidade) |
|
|
36
|
+
| `DefaultUploadManagerModal.js` | Modal de biblioteca / upload / attach |
|
|
37
|
+
| `DefaultUploadAttachmentsList.js` | Lista inline de anexos + capa |
|
|
38
|
+
| `defaultUploadHelpers.js` / `defaultUploadLibrary.js` / `fileUpload.js` | Helpers puros e fetch da biblioteca |
|
|
39
|
+
|
|
40
|
+
**Contrato de uso**
|
|
41
|
+
|
|
42
|
+
- Props principais: `context` (obrigatório — escopo dos arquivos), `companyId` / people da empresa, `entityId` + `relationResource` / `relationField` para vínculo, `fileActions` / `relationActions` (stores), `fileType`, `maxFiles`, `attachmentRows`, callbacks `onChanged` / `onCoverChanged` / `onAttachFile` / `onUploadFile`.
|
|
43
|
+
- Todo upload abre o mini gerenciador já limitado ao `context` (e `people` da company quando informado).
|
|
44
|
+
- Listagem da biblioteca chama `fileActions.getItems({ context, people, ... })` — o backend aplica `FileService::securityFilter` (company-scoped).
|
|
45
|
+
- Não chamar API de files diretamente nas telas consumidoras; usar stores/actions.
|
|
46
|
+
- Reutilizar `DefaultFile` para preview/download.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Contrato de colunas (`defaultInputUtils`)
|
|
2
|
+
|
|
3
|
+
**Arquivo:** `src/react/components/inputs/defaultInputUtils.js`
|
|
4
|
+
|
|
5
|
+
A coluna é o **contrato de UI + serialização** compartilhado por Table, Form e Inputs.
|
|
6
|
+
|
|
7
|
+
## Identidade
|
|
8
|
+
|
|
9
|
+
| Campo | Uso |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `key` ou `name` | Nome do campo (`getColumnKey`) |
|
|
12
|
+
| `label` | Rótulo (i18n via `formatStoreColumnLabel`) |
|
|
13
|
+
| `isIdentity` | PK visual; fora do form; largura própria na tabela |
|
|
14
|
+
|
|
15
|
+
## Visibilidade e edição
|
|
16
|
+
|
|
17
|
+
| Flag | Efeito |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `show` / `visible` / `table` | Inclusão na tabela (`shouldIncludeColumn` em utils da table) |
|
|
20
|
+
| `form` | `false` remove do form |
|
|
21
|
+
| `add` | `false` remove do create |
|
|
22
|
+
| `editable` | `false` bloqueia edição |
|
|
23
|
+
| `visibleForm` | bool ou fn |
|
|
24
|
+
| `multiline` | excluído do DefaultForm atual |
|
|
25
|
+
| `sortable` / `sortField` / `defaultSort` | Sort |
|
|
26
|
+
| `summary` | Agregações no footer |
|
|
27
|
+
|
|
28
|
+
## Tipos de input
|
|
29
|
+
|
|
30
|
+
| `inputType` / `type` | Comportamento |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `date` / `date-range` / `range-date` | `DefaultDateInput`; save via `Formatter` |
|
|
33
|
+
| `color` / `hexcolor` ou nome color-like | `DefaultColorInput` |
|
|
34
|
+
| `file` / `image` / `document` / … | `DefaultFileColumn` (não editável inline) |
|
|
35
|
+
| `extradata` | `DefaultExtraData` |
|
|
36
|
+
| `number` / `float` | teclado numérico |
|
|
37
|
+
| `increase` | não editável |
|
|
38
|
+
|
|
39
|
+
## Listas (select)
|
|
40
|
+
|
|
41
|
+
| Campo | Uso |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `list` | Array local **ou** `"store/action"` |
|
|
44
|
+
| `listRequestParams` | Filtros extras do load |
|
|
45
|
+
| `listSearchParam` / `searchParam` | Query de busca |
|
|
46
|
+
| `formatList` | Normaliza item → label/meta |
|
|
47
|
+
| `translate` | Força/desliga i18n de labels de opção |
|
|
48
|
+
|
|
49
|
+
## Formatação
|
|
50
|
+
|
|
51
|
+
| Campo | Uso |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `format` | Apresentação de célula (pode retornar objeto com color/icon) |
|
|
54
|
+
| `editFormat` | Valor ao entrar em edição |
|
|
55
|
+
| `saveFormat` | Valor ao persistir |
|
|
56
|
+
| `prefix` / `sufix`/`suffix` | Decoração textual |
|
|
57
|
+
| `style` | estilo estático ou fn(row) |
|
|
58
|
+
| `width` / `minWidth` / `flexBasis` | Layout de coluna na table |
|
|
59
|
+
| `defaultValue` / `initialValue` / `defaultColor` | Defaults de form/cor |
|
|
60
|
+
|
|
61
|
+
## Helpers exportados (referência rápida)
|
|
62
|
+
|
|
63
|
+
`normalizeText`, `getColumnKey`, `isEditableColumn`, `isDateLikeColumn`, `isColorColumn`, `isFileColumn`, `isExtraDataColumn`, `normalizeId`, `normalizeOptionKey`, `mapOptions`, `buildOptionsFromColumn`, `resolveCellText`, `resolveCellPresentation`, `buildReadPresentationStyles`, `resolveEditValue`, `formatSaveValue`, `resolveStoreNameFromList`, `resolveColorToken`
|
|
64
|
+
|
|
65
|
+
## Campos traduzíveis por convenção
|
|
66
|
+
|
|
67
|
+
Sem `translate: true`, ainda traduz labels de opção se o nome do campo estiver em: `active`, `app`, `channel`, `status`, `ordertype`, `peopletype`, etc. (`DEFAULT_TRANSLATABLE_FIELDS`).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Componentes Default* (`ui-default`)
|
|
2
|
+
|
|
3
|
+
Documentação técnica da família de componentes genéricos do módulo **`ControleOnline/ui-default`**.
|
|
4
|
+
|
|
5
|
+
> Público: desenvolvedores e agents internos.
|
|
6
|
+
> Issue: `ControleOnline/ui-default#2`.
|
|
7
|
+
|
|
8
|
+
## Objetivo do módulo
|
|
9
|
+
|
|
10
|
+
`ui-default` concentra UI reutilizável orientada a **stores** (`useStore(storeName)`): tabelas, formulários, inputs, filtros, upload, mapas e anexos. O contrato central é a **definição de colunas** (`columns`) + estado do store (`items`, `filters`, `configs`, `actions`).
|
|
11
|
+
|
|
12
|
+
```mermaid
|
|
13
|
+
flowchart TB
|
|
14
|
+
subgraph app [Módulo de domínio]
|
|
15
|
+
Page[Page / Screen]
|
|
16
|
+
Store[useStore storeName]
|
|
17
|
+
end
|
|
18
|
+
subgraph defaults [ui-default]
|
|
19
|
+
DT[DefaultTable]
|
|
20
|
+
DF[DefaultForm]
|
|
21
|
+
DI[DefaultInput]
|
|
22
|
+
DS[DefaultSelect]
|
|
23
|
+
end
|
|
24
|
+
Page --> DT
|
|
25
|
+
Page --> DF
|
|
26
|
+
DT --> Store
|
|
27
|
+
DF --> DI
|
|
28
|
+
DI --> DS
|
|
29
|
+
DI --> Store
|
|
30
|
+
DS --> Store
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Mapa de componentes
|
|
34
|
+
|
|
35
|
+
| Família | Componentes principais | Pasta |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| Tabela | `DefaultTable`, Body, Rows, Cards, Toolbar, Footer, Search, Controls… | `src/react/components/table/` |
|
|
38
|
+
| Formulário | `DefaultForm` | `src/react/components/form/` |
|
|
39
|
+
| Inputs | `DefaultInput`, `DefaultSelect`, `DefaultDateInput`, `DefaultColorInput`, `DefaultFeatherIconPicker` | `src/react/components/inputs/` |
|
|
40
|
+
| Filtros | `DefaultSearch`, `DefaultColumnFilter`, `DefaultExternalFilters`, `DateShortcutFilter`, `CompactFilterSelector` | `src/react/components/filters/` |
|
|
41
|
+
| Arquivos | `DefaultFile`, `DefaultFileColumn` | `src/react/components/files/` |
|
|
42
|
+
| Upload | `DefaultUpload` | `src/react/components/upload/` |
|
|
43
|
+
| Extra | `DefaultExtraData` | `src/react/components/extra-data/` |
|
|
44
|
+
| Erros | `DefaultErrors` | `src/react/components/errors/` |
|
|
45
|
+
| Ajuda | `DefaultTooltip` | `src/react/components/help/` |
|
|
46
|
+
| Mapa | `DefaultMap`, `DefaultGoogleMap`, `DefaultNativeMap` | `src/react/components/map/` |
|
|
47
|
+
|
|
48
|
+
## Páginas detalhadas
|
|
49
|
+
|
|
50
|
+
| Página | Conteúdo |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| [DefaultTable](DefaultTable) | Orquestração, props, store contract, view modes, preferências |
|
|
53
|
+
| [DefaultForm](DefaultForm) | Create/edit, draft, payload de save |
|
|
54
|
+
| [DefaultInput-e-DefaultSelect](DefaultInput-e-DefaultSelect) | Roteamento por tipo de coluna, list remote, apresentação |
|
|
55
|
+
| [Contrato-de-colunas](Contrato-de-colunas) | Flags e helpers de `defaultInputUtils` |
|
|
56
|
+
|
|
57
|
+
## Dependências transversais
|
|
58
|
+
|
|
59
|
+
- `@store` — `useStore` / `getAllStores`
|
|
60
|
+
- `@controleonline/ui-common` — `MessageService`, `Formatter`, `formatStoreColumnLabel` / `formatStoreColumnValue`, date range helpers
|
|
61
|
+
- `@react-navigation/native` — foco e escopo de preferências da tabela
|
|
62
|
+
- Tema via store `theme` e tokens em `useDefaultTableTheme`
|
|
63
|
+
|
|
64
|
+
## Quando usar
|
|
65
|
+
|
|
66
|
+
| Situação | Preferir |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| Listagem CRUD ligada a store com `getItems` / `save` | `DefaultTable` (+ `DefaultForm` no modal de add/edit) |
|
|
69
|
+
| Campo isolado em tela custom | `DefaultInput` / `DefaultSelect` |
|
|
70
|
+
| Upload de arquivos | `DefaultUpload` |
|
|
71
|
+
| Mapa web/native | família `DefaultMap*` |
|
|
72
|
+
|
|
73
|
+
## Não objetivos
|
|
74
|
+
|
|
75
|
+
- Não substituir telas de domínio com regras de negócio específicas sem `columns`/`store`.
|
|
76
|
+
- Não publicar esta documentação na Central de Ajuda do cliente (`tutorial-assistant`); é documentação **técnica**.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# DefaultForm
|
|
2
|
+
|
|
3
|
+
Formulário genérico create/edit orientado a **colunas** e `actions.save`.
|
|
4
|
+
|
|
5
|
+
**Arquivo:** `src/react/components/form/DefaultForm.js`
|
|
6
|
+
|
|
7
|
+
## Responsabilidade
|
|
8
|
+
|
|
9
|
+
- Filtrar colunas elegíveis ao formulário
|
|
10
|
+
- Montar **draft** a partir da row / defaults
|
|
11
|
+
- Salvar apenas campos alterados (edit) ou preenchidos (create)
|
|
12
|
+
- Renderizar cada campo com `DefaultInput` em `variant="form"`
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
|
|
16
|
+
| Prop | Default | Função |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `storeName` | `''` | i18n de labels/botões |
|
|
19
|
+
| `columns` | `[]` | Definição de campos |
|
|
20
|
+
| `row` | `{}` | Registro em edição |
|
|
21
|
+
| `mode` | `'edit'` | `'create'` \| `'edit'` |
|
|
22
|
+
| `actions` | `{}` | Precisa de `actions.save(payload)` |
|
|
23
|
+
| `getOptionsForColumn` | null | Options locais |
|
|
24
|
+
| `onBeforeOpen` | null | Antes de abrir select (`(column) => ...`) |
|
|
25
|
+
| `onCancel` | null | Cancelar |
|
|
26
|
+
| `onSaved` | null | `(savedItem, previousRow) => ...` |
|
|
27
|
+
|
|
28
|
+
## Inclusão de coluna no form
|
|
29
|
+
|
|
30
|
+
`shouldIncludeColumn(column, row, mode)`:
|
|
31
|
+
|
|
32
|
+
- precisa de `key`/`name`
|
|
33
|
+
- **exclui** `isIdentity === true`
|
|
34
|
+
- **exclui** `form === false` ou `multiline === true`
|
|
35
|
+
- em `create`: respeita `add === false`
|
|
36
|
+
- em `edit`: exige `isEditableColumn(column)`
|
|
37
|
+
- `visibleForm` (bool ou fn `(row, column) => boolean`)
|
|
38
|
+
|
|
39
|
+
## Draft e defaults
|
|
40
|
+
|
|
41
|
+
Ordem em `resolveDefaultValue`:
|
|
42
|
+
|
|
43
|
+
1. `row[field]`
|
|
44
|
+
2. `column.defaultValue` (valor ou fn)
|
|
45
|
+
3. `column.initialValue` (valor ou fn)
|
|
46
|
+
|
|
47
|
+
`resolveEditValue` normaliza para edição (list → option key, date → dmY, `editFormat`).
|
|
48
|
+
|
|
49
|
+
## Payload de save
|
|
50
|
+
|
|
51
|
+
**Create:** objeto só com campos que `hasValue`.
|
|
52
|
+
**Edit:** sempre inclui `id` (`@id` ou `id` normalizado) + campos cujo texto normalizado **mudou**.
|
|
53
|
+
|
|
54
|
+
`formatSaveValue(column, value, row)`:
|
|
55
|
+
|
|
56
|
+
- `column.saveFormat` se existir
|
|
57
|
+
- objetos com `value` / `@id`
|
|
58
|
+
- datas → formato americano via `Formatter`
|
|
59
|
+
- números quando aplicável
|
|
60
|
+
|
|
61
|
+
Se não há nada a salvar → chama `onCancel` e não bate no backend.
|
|
62
|
+
|
|
63
|
+
## UI
|
|
64
|
+
|
|
65
|
+
- Grid scrollável de campos
|
|
66
|
+
- Botões Cancelar / Salvar (tema: store `theme`)
|
|
67
|
+
- Estado `isSaving` desabilita botão primário
|
|
68
|
+
|
|
69
|
+
## Exemplo
|
|
70
|
+
|
|
71
|
+
```jsx
|
|
72
|
+
<DefaultForm
|
|
73
|
+
mode="create"
|
|
74
|
+
storeName="customers"
|
|
75
|
+
columns={store.getters.columns}
|
|
76
|
+
actions={{ save: store.actions.save }}
|
|
77
|
+
onCancel={close}
|
|
78
|
+
onSaved={(item) => { close(); refresh(); }}
|
|
79
|
+
/>
|
|
80
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# DefaultInput e DefaultSelect
|
|
2
|
+
|
|
3
|
+
Camada de campo único usada por **tabela** (`variant="cell"`) e **form** (`variant="form"`).
|
|
4
|
+
|
|
5
|
+
## DefaultInput
|
|
6
|
+
|
|
7
|
+
**Arquivo:** `src/react/components/inputs/DefaultInput.js`
|
|
8
|
+
|
|
9
|
+
### Roteamento por tipo de coluna
|
|
10
|
+
|
|
11
|
+
| Condição | Componente |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `column.list` truthy | `DefaultSelect` |
|
|
14
|
+
| `isColorColumn(column)` | `DefaultColorInput` |
|
|
15
|
+
| `isDateLikeColumn(column)` | `DefaultDateInput` |
|
|
16
|
+
| leitura + extra data | `DefaultExtraData` |
|
|
17
|
+
| leitura + file | `DefaultFileColumn` |
|
|
18
|
+
| senão | `TextInput` ou modo leitura com badge/ícone/imagem |
|
|
19
|
+
|
|
20
|
+
### Props relevantes
|
|
21
|
+
|
|
22
|
+
| Prop | Função |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `column` / `columns` / `row` | Contrato de coluna e contexto |
|
|
25
|
+
| `editing` | Alterna leitura × edição (cell) |
|
|
26
|
+
| `variant` | `'cell'` \| `'form'` |
|
|
27
|
+
| `autoSave` | `true`: `onSave` no blur/submit; `false`: só `onChangeValue` |
|
|
28
|
+
| `onStartEditing` / `onCancelEditing` / `onSave` | Ciclo de edição inline |
|
|
29
|
+
| `getOptionsForColumn` | Options injetadas |
|
|
30
|
+
| `showLabel` | Label acima do campo |
|
|
31
|
+
| `displayValue` | Override de texto lido |
|
|
32
|
+
| `accentColor` / `defaultColor` | Tema / cor default |
|
|
33
|
+
|
|
34
|
+
### Modo leitura
|
|
35
|
+
|
|
36
|
+
- `resolveCellText` + `resolveCellPresentation` (cor, ícone Feather, image, badge)
|
|
37
|
+
- Ícone de editar se `isEditableColumn` e existe `onStartEditing`
|
|
38
|
+
- Prefixo/sufixo da coluna
|
|
39
|
+
|
|
40
|
+
### Modo edição texto
|
|
41
|
+
|
|
42
|
+
- `keyboardType` numérico se `inputType` number/float
|
|
43
|
+
- Cancel (X) só fora de form
|
|
44
|
+
|
|
45
|
+
## DefaultSelect
|
|
46
|
+
|
|
47
|
+
**Arquivo:** `src/react/components/inputs/DefaultSelect.js`
|
|
48
|
+
|
|
49
|
+
### Fontes de opções
|
|
50
|
+
|
|
51
|
+
1. `getOptionsForColumn(column)`
|
|
52
|
+
2. `column.list` como **array** estática
|
|
53
|
+
3. `column.list` como string `"storeName/actionName"` → `getAllStores()[store].actions[action]`
|
|
54
|
+
4. Cache em memória por chave serializada de params
|
|
55
|
+
|
|
56
|
+
### Params de load remoto
|
|
57
|
+
|
|
58
|
+
`resolveColumnListLoadParams`:
|
|
59
|
+
|
|
60
|
+
- escopo empresa para `categories` (`company`), `paymentType` / `wallet` (`people`)
|
|
61
|
+
- `column.listRequestParams` (objeto ou fn)
|
|
62
|
+
- busca: `listSearchParam` \|\| `searchParam` \|\| `'search'`
|
|
63
|
+
|
|
64
|
+
### UX
|
|
65
|
+
|
|
66
|
+
- Toque abre `Modal` com busca e lista
|
|
67
|
+
- `autoSave`: `onSave({ value, label, object })`
|
|
68
|
+
- form: `onChangeValue(key, meta)`
|
|
69
|
+
- `onBeforeOpen` pode pré-carregar items
|
|
70
|
+
|
|
71
|
+
### Meta visual de opção
|
|
72
|
+
|
|
73
|
+
`formatList` / item pode expor `color`, `icon`, `image` para badges na lista e no valor selecionado.
|