@galadrim/galadmin 0.2.10 → 0.2.11-alpha.1.1
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/.agents/report/blockers.json +1 -0
- package/.agents/report/failures/2026-09-23-api-user-filter-contract.md +31 -0
- package/.agents/report/failures/2026-09-23-api-values-contract.md +25 -0
- package/.agents/report/failures/2026-10-01-cycle-02-create-callback-contract.md +17 -0
- package/.agents/report/failures/2026-10-01-cycle-06-delete-callback-id-contract.md +17 -0
- package/.agents/report/failures/2026-10-01-cycle-07-panel-delete-callback-id-contract.md +24 -0
- package/.agents/report/failures/2026-10-01-cycle-13-update-callback-id-contract.md +17 -0
- package/.agents/report/failures/2026-10-01-cycle-15-rich-text-upload-boundary-contract.md +24 -0
- package/.agents/report/failures/2026-10-03-cycle-06-record-import-parser-contract.md +11 -0
- package/.agents/report/failures/2026-10-03-cycle-07-panel-import-parser-contract.md +24 -0
- package/.agents/report/failures/2026-10-07-resume-cycle-02-api-assembly-contract.md +46 -0
- package/.agents/report/port/2026-09-23-api-config-enrichment.md +13 -0
- package/.agents/report/port/2026-09-23-api-file-upload.md +11 -0
- package/.agents/report/port/2026-09-23-api-query-authorization.md +14 -0
- package/.agents/report/port/2026-09-23-api-request-configuration.md +11 -0
- package/.agents/report/port/2026-09-23-database-manager.md +13 -0
- package/.agents/report/port/2026-10-01-api-adjacent-record-id.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-01-api-config-route.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-03-custom-action.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-04-custom-component.md +7 -0
- package/.agents/report/port/2026-10-01-cycle-05-custom-query.md +7 -0
- package/.agents/report/port/2026-10-01-cycle-08-bulk-delete.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-09-duplicate-record.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-10-notification-badges.md +9 -0
- package/.agents/report/port/2026-10-01-cycle-11-record.md +7 -0
- package/.agents/report/port/2026-10-01-cycle-12-search-companies.md +11 -0
- package/.agents/report/port/2026-10-01-cycle-14-upload-file.md +7 -0
- package/.agents/report/port/2026-10-03-cycle-01-create-record.md +11 -0
- package/.agents/report/port/2026-10-03-cycle-02-delete-record.md +11 -0
- package/.agents/report/port/2026-10-03-cycle-03-panel-delete-record.md +11 -0
- package/.agents/report/port/2026-10-03-cycle-04-update-record.md +11 -0
- package/.agents/report/port/2026-10-03-cycle-05-api-values.md +11 -0
- package/.agents/report/port/2026-10-06-cycle-01-record-import.md +9 -0
- package/.agents/report/port/2026-10-06-cycle-03-rich-text-upload.md +7 -0
- package/.agents/report/port/2026-10-06-cycle-04-user-filters.md +11 -0
- package/.agents/report/port/2026-10-06-resume-cycle-01-panel-import.md +9 -0
- package/.agents/report/port/2026-10-07-cycle-01-api-assembly.md +16 -0
- package/.agents/report/port/2026-10-07-cycle-02-index-entry-point.md +13 -0
- package/.agents/report/remediation/2026-10-02-api-user-filter-remediation.md +71 -0
- package/.agents/report/remediation/2026-10-02-api-values-remediation.md +17 -0
- package/.agents/report/remediation/2026-10-03-callback-id-contract-remediation.md +36 -0
- package/.agents/report/remediation/2026-10-06-import-parser-remediation.md +41 -0
- package/.agents/report/remediation/2026-10-06-rich-text-upload-remediation.md +33 -0
- package/.agents/report/remediation/2026-10-07-api-assembly-remediation.md +32 -0
- package/.agents/skills/port-javascript-to-typescript/SKILL.md +42 -0
- package/.agents/skills/port-javascript-to-typescript/agents/openai.yaml +3 -0
- package/.agents/skills/port-javascript-to-typescript/references/blockers.md +31 -0
- package/.agents/skills/port-javascript-to-typescript/references/planning.md +43 -0
- package/.agents/skills/port-javascript-to-typescript/references/porting.md +9 -0
- package/.agents/skills/port-javascript-to-typescript/references/reporting.md +24 -0
- package/.agents/skills/port-javascript-to-typescript/references/rules.md +8 -0
- package/.agents/skills/port-javascript-to-typescript/references/selection.md +16 -0
- package/.agents/skills/port-javascript-to-typescript/references/tools.md +20 -0
- package/.agents/skills/port-javascript-to-typescript/scripts/check.sh +17 -0
- package/.agents/skills/port-javascript-to-typescript/scripts/graph.sh +30 -0
- package/.agents/skills/port-javascript-to-typescript/scripts/madge.json +12 -0
- package/.agents/skills/port-javascript-to-typescript/scripts/oxlint.json +14 -0
- package/.agents/skills/port-javascript-to-typescript/scripts/test-tools.cjs +76 -0
- package/.github/actions/version-bump/action.yml +41 -0
- package/.github/workflows/alpha.yml +53 -0
- package/.github/workflows/ci.yml +8 -9
- package/.github/workflows/main.yml +13 -14
- package/AGENTS.md +5 -0
- package/README.md +34 -4
- package/dist/api/authorization.d.ts +38 -0
- package/dist/api/authorization.js +74 -0
- package/dist/api/authorization.js.map +1 -0
- package/dist/api/config.d.ts +42 -0
- package/dist/api/config.js +105 -0
- package/dist/api/config.js.map +1 -0
- package/dist/api/filterUser.d.ts +2 -0
- package/dist/api/filterUser.js +24 -0
- package/dist/api/filterUser.js.map +1 -0
- package/dist/api/importRecords.d.ts +1 -0
- package/dist/api/importRecords.js +16 -0
- package/dist/api/importRecords.js.map +1 -0
- package/dist/api/queries.d.ts +48 -0
- package/dist/api/queries.js +139 -0
- package/dist/api/queries.js.map +1 -0
- package/dist/api/request.d.ts +29 -0
- package/dist/api/request.js +3 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/routes/adjacentRecordId.d.ts +10 -0
- package/dist/api/routes/adjacentRecordId.js +13 -0
- package/dist/api/routes/adjacentRecordId.js.map +1 -0
- package/dist/api/routes/config.d.ts +3 -0
- package/dist/api/routes/config.js +27 -0
- package/dist/api/routes/config.js.map +1 -0
- package/dist/api/routes/createRecord.d.ts +19 -0
- package/dist/api/routes/createRecord.js +93 -0
- package/dist/api/routes/createRecord.js.map +1 -0
- package/dist/api/routes/customAction.d.ts +17 -0
- package/dist/api/routes/customAction.js +35 -0
- package/dist/api/routes/customAction.js.map +1 -0
- package/dist/api/routes/customComponent.d.ts +3 -0
- package/dist/api/routes/customComponent.js +34 -0
- package/dist/api/routes/customComponent.js.map +1 -0
- package/dist/api/routes/customQuery.d.ts +7 -0
- package/dist/api/routes/customQuery.js +33 -0
- package/dist/api/routes/customQuery.js.map +1 -0
- package/dist/api/routes/deleteRecord.d.ts +9 -0
- package/dist/api/routes/deleteRecord.js +46 -0
- package/dist/api/routes/deleteRecord.js.map +1 -0
- package/dist/api/routes/deleteRecordFromPanel.d.ts +10 -0
- package/dist/api/routes/deleteRecordFromPanel.js +36 -0
- package/dist/api/routes/deleteRecordFromPanel.js.map +1 -0
- package/dist/api/routes/deleteRecords.d.ts +9 -0
- package/dist/api/routes/deleteRecords.js +12 -0
- package/dist/api/routes/deleteRecords.js.map +1 -0
- package/dist/api/routes/duplicateRecord.d.ts +17 -0
- package/dist/api/routes/duplicateRecord.js +55 -0
- package/dist/api/routes/duplicateRecord.js.map +1 -0
- package/dist/api/routes/foreignSelectRecords.d.ts +10 -0
- package/dist/api/routes/foreignSelectRecords.js +61 -0
- package/dist/api/routes/foreignSelectRecords.js.map +1 -0
- package/dist/api/routes/notificationBadges.d.ts +6 -0
- package/dist/api/routes/notificationBadges.js +31 -0
- package/dist/api/routes/notificationBadges.js.map +1 -0
- package/dist/api/routes/record.d.ts +7 -0
- package/dist/api/routes/record.js +32 -0
- package/dist/api/routes/record.js.map +1 -0
- package/dist/api/routes/records.d.ts +14 -0
- package/dist/api/routes/records.js +57 -0
- package/dist/api/routes/records.js.map +1 -0
- package/dist/api/routes/recordsExport.d.ts +13 -0
- package/dist/api/routes/recordsExport.js +67 -0
- package/dist/api/routes/recordsExport.js.map +1 -0
- package/dist/api/routes/recordsImport.d.ts +4 -0
- package/dist/api/routes/recordsImport.js +100 -0
- package/dist/api/routes/recordsImport.js.map +1 -0
- package/dist/api/routes/searchCompanies.d.ts +17 -0
- package/dist/api/routes/searchCompanies.js +72 -0
- package/dist/api/routes/searchCompanies.js.map +1 -0
- package/dist/api/routes/subrecordsImport.d.ts +4 -0
- package/dist/api/routes/subrecordsImport.js +94 -0
- package/dist/api/routes/subrecordsImport.js.map +1 -0
- package/dist/api/routes/updateRecord.d.ts +13 -0
- package/dist/api/routes/updateRecord.js +55 -0
- package/dist/api/routes/updateRecord.js.map +1 -0
- package/dist/api/routes/uploadFile.d.ts +3 -0
- package/dist/api/routes/uploadFile.js +13 -0
- package/dist/api/routes/uploadFile.js.map +1 -0
- package/dist/api/routes/uploadFileFromBetterRichTextInput.d.ts +3 -0
- package/dist/api/routes/uploadFileFromBetterRichTextInput.js +33 -0
- package/dist/api/routes/uploadFileFromBetterRichTextInput.js.map +1 -0
- package/dist/api/uploadFile.d.ts +4 -0
- package/dist/api/uploadFile.js +209 -0
- package/dist/api/uploadFile.js.map +1 -0
- package/dist/api/values.d.ts +6 -0
- package/dist/api/values.js +88 -0
- package/dist/api/values.js.map +1 -0
- package/dist/api.d.ts +8 -27
- package/dist/api.js +80 -1389
- package/dist/api.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.strict.tsbuildinfo +1 -0
- package/dist/types/config.d.ts +17 -7
- package/dist/types/config.js +4 -0
- package/dist/types/config.js.map +1 -1
- package/dist/types/database.d.ts +1 -0
- package/dist/types/database.js +3 -0
- package/dist/types/database.js.map +1 -0
- package/dist/utils/dbManager.d.ts +32 -7
- package/dist/utils/dbManager.js +59 -7
- package/dist/utils/dbManager.js.map +1 -1
- package/package.json +12 -3
- package/src/api/authorization.ts +129 -0
- package/src/api/config.ts +152 -0
- package/src/api/filterUser.ts +28 -0
- package/src/api/importRecords.ts +16 -0
- package/src/api/queries.ts +194 -0
- package/src/api/request.ts +31 -0
- package/src/api/routes/adjacentRecordId.ts +20 -0
- package/src/api/routes/config.ts +15 -0
- package/src/api/routes/createRecord.ts +131 -0
- package/src/api/routes/customAction.ts +60 -0
- package/src/api/routes/customComponent.ts +44 -0
- package/src/api/routes/customQuery.ts +53 -0
- package/src/api/routes/deleteRecord.ts +59 -0
- package/src/api/routes/deleteRecordFromPanel.ts +58 -0
- package/src/api/routes/deleteRecords.ts +28 -0
- package/src/api/routes/duplicateRecord.ts +73 -0
- package/src/api/routes/foreignSelectRecords.ts +80 -0
- package/src/api/routes/notificationBadges.ts +47 -0
- package/src/api/routes/record.ts +48 -0
- package/src/api/routes/records.ts +91 -0
- package/src/api/routes/recordsExport.ts +92 -0
- package/src/api/routes/recordsImport.ts +115 -0
- package/src/api/routes/searchCompanies.ts +96 -0
- package/src/api/routes/subrecordsImport.ts +114 -0
- package/src/api/routes/updateRecord.ts +74 -0
- package/src/api/routes/uploadFile.ts +16 -0
- package/src/api/routes/uploadFileFromBetterRichTextInput.ts +41 -0
- package/src/api/uploadFile.ts +249 -0
- package/src/api/values.ts +96 -0
- package/src/api.ts +94 -1578
- package/src/front/ckeditor5-build/node_modules/semver/bin/semver.js +0 -0
- package/src/index.ts +42 -25
- package/src/types/config.ts +17 -7
- package/src/types/database.ts +2 -0
- package/src/utils/dbManager.ts +99 -14
- package/tests/api-helpers.test.ts +59 -0
- package/tests/dbManager.test.ts +16 -1
- package/tests/helpers/fakeDb.ts +9 -7
- package/tests/integration/authorizationBoundary.integration.test.ts +57 -0
- package/tests/integration/configEnrichment.integration.test.ts +79 -0
- package/tests/integration/customComponentBoundary.integration.test.ts +58 -0
- package/tests/integration/dbManager.integration.test.ts +105 -3
- package/tests/integration/importParserChild.cjs +55 -0
- package/tests/integration/indexRuntime.integration.test.ts +22 -0
- package/tests/integration/indexRuntimeChild.cjs +110 -0
- package/tests/integration/queries.integration.test.ts +88 -0
- package/tests/integration/requestConfig.integration.test.ts +118 -0
- package/tests/integration/routes.authorization.integration.test.ts +1 -0
- package/tests/integration/routes.config.integration.test.ts +39 -1
- package/tests/integration/routes.crud.integration.test.ts +233 -1
- package/tests/integration/routes.custom.integration.test.ts +119 -0
- package/tests/integration/routes.foreign.integration.test.ts +3 -2
- package/tests/integration/routes.importExport.integration.test.ts +308 -6
- package/tests/integration/routes.integration.test.ts +4 -0
- package/tests/integration/routes.records.integration.test.ts +82 -6
- package/tests/integration/routes.upload.integration.test.ts +178 -0
- package/tests/integration/userFilters.integration.test.ts +225 -0
- package/tsconfig.json +1 -1
- package/tsconfig.strict.json +45 -0
- package/dist/front/ckeditor5-build/src/ckeditor.d.ts +0 -43
- package/dist/front/ckeditor5-build/src/ckeditor.js +0 -130
- package/dist/front/ckeditor5-build/src/ckeditor.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/front/ckeditor5-build/node_modules/.bin/semver +0 -12
- package/src/front/ckeditor5-build/node_modules/.bin/semver.cmd +0 -17
- package/src/front/ckeditor5-build/node_modules/.bin/semver.ps1 +0 -28
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"plugins": ["typescript"],
|
|
3
|
+
"categories": { "correctness": "off" },
|
|
4
|
+
"rules": {
|
|
5
|
+
"typescript/no-explicit-any": "warn",
|
|
6
|
+
"typescript/no-non-null-assertion": "warn",
|
|
7
|
+
"typescript/ban-ts-comment": ["warn", {
|
|
8
|
+
"ts-ignore": true,
|
|
9
|
+
"ts-expect-error": true,
|
|
10
|
+
"ts-nocheck": true,
|
|
11
|
+
"ts-check": false
|
|
12
|
+
}]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const assert = require('node:assert/strict');
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const os = require('node:os');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { spawnSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'port tools '));
|
|
8
|
+
const tools = path.join(temporary, 'copied skill');
|
|
9
|
+
const repo = path.join(temporary, 'target repo');
|
|
10
|
+
fs.cpSync(__dirname, tools, { recursive: true });
|
|
11
|
+
fs.mkdirSync(repo);
|
|
12
|
+
|
|
13
|
+
function run(script, args, status = 0) {
|
|
14
|
+
const result = spawnSync('bash', [path.join(tools, script), ...args], {
|
|
15
|
+
cwd: repo, encoding: 'utf8', timeout: 120000,
|
|
16
|
+
});
|
|
17
|
+
assert.ifError(result.error);
|
|
18
|
+
assert.equal(result.status, status, result.stderr + result.stdout);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const inputs = {
|
|
24
|
+
'tsconfig.json': JSON.stringify({ compilerOptions: {
|
|
25
|
+
baseUrl: '.', paths: { '@left': ['./left.ts'] }, allowJs: true,
|
|
26
|
+
} }),
|
|
27
|
+
'package.json': JSON.stringify({ madge: { excludeRegExp: ['.*'] } }),
|
|
28
|
+
'entry.ts': 'import { left } from "@left"; import type { Value } from "./types";\n'
|
|
29
|
+
+ 'const common = require("./common.cjs"); import("./dynamic");\n',
|
|
30
|
+
'left.ts': 'import "./right"; export const left = 1;',
|
|
31
|
+
'right.ts': 'import "./left";',
|
|
32
|
+
'types.ts': 'export type Value = string;',
|
|
33
|
+
'common.cjs': 'module.exports = 1;',
|
|
34
|
+
'dynamic.ts': 'export const dynamic = 1;',
|
|
35
|
+
'missing.ts': 'import "./does-not-exist";',
|
|
36
|
+
'warnings.ts': 'let value: any;\nvalue!.field;\n'
|
|
37
|
+
+ '// @ts-expect-error documented suppression\nvalue.call();\n'
|
|
38
|
+
+ '// @ts-check\nconst unused = 1; debugger;\n',
|
|
39
|
+
'.oxlintrc.json': JSON.stringify({ rules: {
|
|
40
|
+
'typescript/no-explicit-any': 'off', 'no-unused-vars': 'error',
|
|
41
|
+
} }),
|
|
42
|
+
'.eslintignore': 'warnings.ts\n',
|
|
43
|
+
'broken.ts': 'const = ;',
|
|
44
|
+
};
|
|
45
|
+
for (const [file, content] of Object.entries(inputs)) {
|
|
46
|
+
fs.writeFileSync(path.join(repo, file), content);
|
|
47
|
+
}
|
|
48
|
+
for (const script of ['graph.sh', 'check.sh']) {
|
|
49
|
+
run(script, ['--help']);
|
|
50
|
+
run(script, [], 2);
|
|
51
|
+
}
|
|
52
|
+
const graph = JSON.parse(run('graph.sh', ['tsconfig.json', 'entry.ts']).stdout);
|
|
53
|
+
assert.deepEqual(graph['entry.ts'], ['common.cjs', 'dynamic.ts', 'left.ts', 'types.ts']);
|
|
54
|
+
assert.deepEqual(graph['left.ts'], ['right.ts']);
|
|
55
|
+
assert.deepEqual(graph['right.ts'], ['left.ts']);
|
|
56
|
+
const missing = run('graph.sh', ['tsconfig.json', 'missing.ts']);
|
|
57
|
+
assert.match(missing.stderr, /does-not-exist/);
|
|
58
|
+
assert.deepEqual(JSON.parse(missing.stdout)['missing.ts'], []);
|
|
59
|
+
run('graph.sh', ['tsconfig.json', 'absent.ts'], 1);
|
|
60
|
+
|
|
61
|
+
const lint = JSON.parse(run('check.sh', ['warnings.ts']).stdout);
|
|
62
|
+
assert.equal(lint.number_of_files, 1);
|
|
63
|
+
assert.equal(lint.diagnostics.length, 3);
|
|
64
|
+
assert.ok(lint.diagnostics.every(diagnostic => diagnostic.severity === 'warning'));
|
|
65
|
+
for (const rule of ['no-explicit-any', 'no-non-null-assertion', 'ban-ts-comment']) {
|
|
66
|
+
assert.ok(lint.diagnostics.some(diagnostic => diagnostic.code.includes(rule)), rule);
|
|
67
|
+
}
|
|
68
|
+
run('check.sh', ['broken.ts'], 1);
|
|
69
|
+
run('check.sh', ['absent.ts'], 1);
|
|
70
|
+
for (const [file, content] of Object.entries(inputs)) {
|
|
71
|
+
assert.equal(fs.readFileSync(path.join(repo, file), 'utf8'), content);
|
|
72
|
+
}
|
|
73
|
+
console.log('Tool integration checks passed.');
|
|
74
|
+
} finally {
|
|
75
|
+
fs.rmSync(temporary, { recursive: true, force: true });
|
|
76
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: 'Automated Version Bump'
|
|
2
|
+
description: >-
|
|
3
|
+
Bumps the package version, commits package.json + package-lock.json,
|
|
4
|
+
tags the result and pushes both to the current branch.
|
|
5
|
+
Requires a checkout with persisted credentials and a job granting
|
|
6
|
+
`permissions: contents: write`.
|
|
7
|
+
|
|
8
|
+
inputs:
|
|
9
|
+
version-type:
|
|
10
|
+
description: 'SemVer release type: patch, minor or major'
|
|
11
|
+
required: false
|
|
12
|
+
default: 'patch'
|
|
13
|
+
|
|
14
|
+
outputs:
|
|
15
|
+
version:
|
|
16
|
+
description: 'The new version, without the v prefix (e.g. 0.2.12)'
|
|
17
|
+
value: ${{ steps.bump.outputs.version }}
|
|
18
|
+
|
|
19
|
+
runs:
|
|
20
|
+
using: 'composite'
|
|
21
|
+
steps:
|
|
22
|
+
- name: Configure git author
|
|
23
|
+
shell: bash
|
|
24
|
+
run: |
|
|
25
|
+
git config user.name "github-actions[bot]"
|
|
26
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
27
|
+
|
|
28
|
+
- name: Bump, commit and tag
|
|
29
|
+
id: bump
|
|
30
|
+
shell: bash
|
|
31
|
+
run: |
|
|
32
|
+
VERSION=$(npm version "${{ inputs.version-type }}" --no-git-tag-version)
|
|
33
|
+
VERSION="${VERSION#v}"
|
|
34
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
35
|
+
git add package.json package-lock.json
|
|
36
|
+
git commit -m "ci: version bump to $VERSION"
|
|
37
|
+
git tag "$VERSION"
|
|
38
|
+
|
|
39
|
+
- name: Push commit and tag
|
|
40
|
+
shell: bash
|
|
41
|
+
run: git push origin "HEAD:${{ github.ref_name }}" "${{ steps.bump.outputs.version }}"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Publish alpha
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: alpha-publish
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
uses: ./.github/workflows/ci.yml
|
|
15
|
+
|
|
16
|
+
build-and-publish-alpha:
|
|
17
|
+
needs: test
|
|
18
|
+
runs-on: ubicloud-standard-2
|
|
19
|
+
env:
|
|
20
|
+
CI: false
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v7
|
|
24
|
+
- uses: actions/setup-node@v7
|
|
25
|
+
with:
|
|
26
|
+
node-version: 22
|
|
27
|
+
registry-url: 'https://registry.npmjs.org'
|
|
28
|
+
cache: 'npm'
|
|
29
|
+
cache-dependency-path: |
|
|
30
|
+
package-lock.json
|
|
31
|
+
src/front/package-lock.json
|
|
32
|
+
- name: Compute alpha version
|
|
33
|
+
run: |
|
|
34
|
+
BASE=$(node -p "require('./package.json').version")
|
|
35
|
+
npm version "$BASE-alpha.${{ github.run_number }}.${{ github.run_attempt }}" --no-git-tag-version --allow-same-version
|
|
36
|
+
- name: Dependencies installation
|
|
37
|
+
run: npm ci
|
|
38
|
+
- name: Front-end - Dependencies installation
|
|
39
|
+
run: npm ci
|
|
40
|
+
working-directory: ./src/front
|
|
41
|
+
- name: Front-end - Generate build
|
|
42
|
+
run: npm run build
|
|
43
|
+
working-directory: ./src/front
|
|
44
|
+
- name: Generate build
|
|
45
|
+
run: npm run build
|
|
46
|
+
- name: Publish package
|
|
47
|
+
run: npm publish --tag alpha
|
|
48
|
+
env:
|
|
49
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
50
|
+
- name: Verify dist-tags
|
|
51
|
+
run: npm view @galadrim/galadmin dist-tags --json
|
|
52
|
+
env:
|
|
53
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -9,19 +9,18 @@ jobs:
|
|
|
9
9
|
runs-on: ubicloud-standard-2
|
|
10
10
|
steps:
|
|
11
11
|
- name: Checkout code
|
|
12
|
-
uses: actions/checkout@
|
|
13
|
-
- uses: actions/setup-node@
|
|
12
|
+
uses: actions/checkout@v7
|
|
13
|
+
- uses: actions/setup-node@v7
|
|
14
14
|
with:
|
|
15
15
|
node-version: 22
|
|
16
|
+
cache: 'npm'
|
|
17
|
+
cache-dependency-path: |
|
|
18
|
+
package-lock.json
|
|
19
|
+
src/front/package-lock.json
|
|
16
20
|
- name: Dependencies installation
|
|
17
|
-
run: npm
|
|
18
|
-
- name: Front-end - Load cache
|
|
19
|
-
uses: actions/cache@v4
|
|
20
|
-
with:
|
|
21
|
-
path: '**/src/front/node_modules'
|
|
22
|
-
key: ${{ runner.os }}-npm-front-${{ hashFiles('**/src/front/package-lock.json') }}
|
|
21
|
+
run: npm ci
|
|
23
22
|
- name: Front-end - Dependencies installation
|
|
24
|
-
run: npm
|
|
23
|
+
run: npm ci
|
|
25
24
|
working-directory: ./src/front
|
|
26
25
|
# The root tsconfig includes the custom CKEditor source under src/front.
|
|
27
26
|
- name: Typecheck
|
|
@@ -11,29 +11,28 @@ jobs:
|
|
|
11
11
|
build-and-deploy:
|
|
12
12
|
needs: test
|
|
13
13
|
runs-on: ubicloud-standard-2
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
14
16
|
env:
|
|
15
17
|
CI: false
|
|
16
18
|
steps:
|
|
17
19
|
- name: Checkout code
|
|
18
|
-
uses: actions/checkout@
|
|
19
|
-
- uses: actions/setup-node@
|
|
20
|
+
uses: actions/checkout@v7
|
|
21
|
+
- uses: actions/setup-node@v7
|
|
20
22
|
with:
|
|
21
23
|
node-version: 22
|
|
24
|
+
cache: 'npm'
|
|
25
|
+
cache-dependency-path: |
|
|
26
|
+
package-lock.json
|
|
27
|
+
src/front/package-lock.json
|
|
22
28
|
- name: 'Automated Version Bump'
|
|
23
|
-
uses:
|
|
24
|
-
env:
|
|
25
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
29
|
+
uses: ./.github/actions/version-bump
|
|
26
30
|
with:
|
|
27
|
-
version-type:
|
|
31
|
+
version-type: 'patch'
|
|
28
32
|
- name: Dependencies installation
|
|
29
|
-
run: npm
|
|
30
|
-
- name: Front-end - Load cache
|
|
31
|
-
uses: actions/cache@v4
|
|
32
|
-
with:
|
|
33
|
-
path: '**/src/front/node_modules'
|
|
34
|
-
key: ${{ runner.os }}-npm-front-${{ hashFiles('**/src/front/package-lock.json') }}
|
|
33
|
+
run: npm ci
|
|
35
34
|
- name: Front-end - Dependencies installation
|
|
36
|
-
run: npm
|
|
35
|
+
run: npm ci
|
|
37
36
|
working-directory: ./src/front
|
|
38
37
|
- name: Front-end - Generate build
|
|
39
38
|
run: npm run build
|
|
@@ -41,6 +40,6 @@ jobs:
|
|
|
41
40
|
- name: Generate build
|
|
42
41
|
run: npm run build
|
|
43
42
|
- name: Publish package
|
|
44
|
-
uses: JS-DevTools/npm-publish@
|
|
43
|
+
uses: JS-DevTools/npm-publish@v4
|
|
45
44
|
with:
|
|
46
45
|
token: ${{ secrets.NPM_TOKEN }}
|
package/AGENTS.md
ADDED
package/README.md
CHANGED
|
@@ -229,6 +229,7 @@ upload of a file onto AWS S3. A basic configuration would be as follow:
|
|
|
229
229
|
dataType: 'file',
|
|
230
230
|
s3Config: {
|
|
231
231
|
host: process.env.AWS_S3_HOST,
|
|
232
|
+
/** Optional. When omitted, the AWS SDK default credential chain is used. */
|
|
232
233
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
233
234
|
secretAccessKey: process.env.AWS_SECRET_KEY,
|
|
234
235
|
bucket: process.env.AWS_S3_PODCAST_BUCKET_NAME,
|
|
@@ -240,6 +241,35 @@ upload of a file onto AWS S3. A basic configuration would be as follow:
|
|
|
240
241
|
}]
|
|
241
242
|
```
|
|
242
243
|
|
|
244
|
+
When `accessKeyId` is omitted or empty, the AWS SDK will try to resolve the credentials itself (first match wins):
|
|
245
|
+
|
|
246
|
+
1. Env vars AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (+ AWS_SESSION_TOKEN), skipped if AWS_PROFILE is set
|
|
247
|
+
2. Profile AWS_PROFILE (or "default") from ~/.aws/config and ~/.aws/credentials (SSO, static keys, assumed role, credential_process)
|
|
248
|
+
3. Web identity token: AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN (e.g. EKS)
|
|
249
|
+
4. ECS container role: AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or AWS_CONTAINER_CREDENTIALS_FULL_URI
|
|
250
|
+
5. EC2 instance role via the instance metadata service, unless AWS_EC2_METADATA_DISABLED is set to anything but `false`
|
|
251
|
+
|
|
252
|
+
It's recommended to rely on a role rather than have long-lived AWS credentials added to the server: the instance profile role on EC2/Elastic Beanstalk, or the task role (not the execution role) on ECS/Fargate. Add the following permissions to that role:
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
{
|
|
256
|
+
"Version": "2012-10-17",
|
|
257
|
+
"Statement": [{
|
|
258
|
+
"Effect": "Allow",
|
|
259
|
+
"Action": [
|
|
260
|
+
"s3:PutObject",
|
|
261
|
+
"s3:PutObjectAcl"
|
|
262
|
+
],
|
|
263
|
+
"Resource": "arn:aws:s3:::<bucket>/<subfolder>/*"
|
|
264
|
+
}]
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
- Without `subfolder`, use `arn:aws:s3:::<bucket>/*` as the resource.
|
|
269
|
+
- By default, files are uploaded with a `public-read` ACL, so the bucket must allow ACLs: its Object Ownership must not be "Bucket owner enforced" (otherwise `AccessControlListNotSupported`), and `BlockPublicAcls` must be off (otherwise `AccessDenied`).
|
|
270
|
+
- With `signedUrlNeeded: true`, no ACL is set: only `s3:PutObject` is needed and the bucket can stay private.
|
|
271
|
+
- If the bucket is encrypted with SSE-KMS, also allow `kms:GenerateDataKey` on its KMS key.
|
|
272
|
+
|
|
243
273
|
### File upload on Google Cloud Platform (GCP)
|
|
244
274
|
|
|
245
275
|
You can also use the FileColumn to upload files to Google Cloud Storage. To use GCP instead of AWS S3, configure the gcpConfig as follows:
|
|
@@ -341,14 +371,14 @@ them.
|
|
|
341
371
|
A few robustness limitations remain documented (not assertable over HTTP
|
|
342
372
|
because the error escapes as an unhandled rejection under express 4):
|
|
343
373
|
|
|
344
|
-
|
|
374
|
+
- A throwing `parseImportFile` in `/recordsImport` or `/subrecordsImport` is
|
|
345
375
|
awaited OUTSIDE the try/catch of the multiparty callback — the 500 is never
|
|
346
376
|
sent and the process can crash.
|
|
347
|
-
|
|
377
|
+
- `formatValueForInsertion(false)` returns `"NULL"`, so a boolean `false`
|
|
348
378
|
cannot be imported.
|
|
349
|
-
|
|
379
|
+
- The local-fs upload backend requires `subdirectory` (publicPath +
|
|
350
380
|
undefined concat yields a nonexistent upload dir).
|
|
351
|
-
|
|
381
|
+
- A throwing `editCallbackFunction` in `/updateRecord` is awaited OUTSIDE any
|
|
352
382
|
try/catch — the update is committed but the request hangs forever.
|
|
353
383
|
|
|
354
384
|
### Frontend tests
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BaseTypeView, TablePanel } from "../types/config";
|
|
2
|
+
type SessionRequest = {
|
|
3
|
+
session?: object;
|
|
4
|
+
};
|
|
5
|
+
type WritableView = Pick<BaseTypeView, "roles"> & Pick<TablePanel, "tableName"> & {
|
|
6
|
+
recordViewPanels?: (Pick<TablePanel, "tableName"> & {
|
|
7
|
+
createConfig?: Pick<TablePanel, "tableName">;
|
|
8
|
+
})[];
|
|
9
|
+
};
|
|
10
|
+
export declare const ROOT_ROLE = "root";
|
|
11
|
+
export declare const roleOf: (req: SessionRequest) => string | undefined;
|
|
12
|
+
export declare const canWriteView: (view: Pick<BaseTypeView, "roles"> | undefined, role: string | undefined) => boolean;
|
|
13
|
+
export declare const viewFromRequest: <T = WritableView>(req: {
|
|
14
|
+
body?: {
|
|
15
|
+
viewIndex?: unknown;
|
|
16
|
+
};
|
|
17
|
+
query?: {
|
|
18
|
+
viewIndex?: unknown;
|
|
19
|
+
};
|
|
20
|
+
config?: {
|
|
21
|
+
views?: T[];
|
|
22
|
+
};
|
|
23
|
+
}) => T | undefined;
|
|
24
|
+
export declare const MUTATING_VIEW_ROUTES: Set<string>;
|
|
25
|
+
export declare const areSafeColumnNames: (data: unknown) => boolean;
|
|
26
|
+
export declare const writableTables: (req: SessionRequest & {
|
|
27
|
+
config?: {
|
|
28
|
+
views?: WritableView[];
|
|
29
|
+
};
|
|
30
|
+
}) => Set<string>;
|
|
31
|
+
export declare const looksLikeSqlBreakout: (frag: unknown) => boolean;
|
|
32
|
+
type HiddenColumnsView = {
|
|
33
|
+
__hiddenColumns?: string[];
|
|
34
|
+
};
|
|
35
|
+
export declare const hiddenColumnsOf: (view: HiddenColumnsView | undefined) => string[];
|
|
36
|
+
export declare const stripHiddenColumns: <T extends Record<string, unknown>>(view: HiddenColumnsView | undefined, record: T) => T;
|
|
37
|
+
export declare const touchesHiddenColumn: (view: HiddenColumnsView | undefined, data: unknown) => boolean;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.touchesHiddenColumn = exports.stripHiddenColumns = exports.hiddenColumnsOf = exports.looksLikeSqlBreakout = exports.writableTables = exports.areSafeColumnNames = exports.MUTATING_VIEW_ROUTES = exports.viewFromRequest = exports.canWriteView = exports.roleOf = exports.ROOT_ROLE = void 0;
|
|
4
|
+
exports.ROOT_ROLE = "root";
|
|
5
|
+
const roleOf = (req) => {
|
|
6
|
+
const user = req.session && Reflect.get(req.session, "user");
|
|
7
|
+
if (!user || typeof user !== "object")
|
|
8
|
+
return undefined;
|
|
9
|
+
const role = Reflect.get(user, "role");
|
|
10
|
+
return typeof role === "string" ? role : undefined;
|
|
11
|
+
};
|
|
12
|
+
exports.roleOf = roleOf;
|
|
13
|
+
const canWriteView = (view, role) => role === exports.ROOT_ROLE || !view || !view.roles || (role !== undefined && view.roles.includes(role));
|
|
14
|
+
exports.canWriteView = canWriteView;
|
|
15
|
+
const viewFromRequest = (req) => {
|
|
16
|
+
const idx = req.body && req.body.viewIndex !== undefined
|
|
17
|
+
? req.body.viewIndex
|
|
18
|
+
: req.query && req.query.viewIndex !== undefined
|
|
19
|
+
? req.query.viewIndex
|
|
20
|
+
: undefined;
|
|
21
|
+
if (idx === undefined || !req.config || !req.config.views)
|
|
22
|
+
return undefined;
|
|
23
|
+
const key = String(idx);
|
|
24
|
+
const index = Number(key);
|
|
25
|
+
if (!Number.isInteger(index) || index < 0 || index >= req.config.views.length || String(index) !== key) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return req.config.views[index];
|
|
29
|
+
};
|
|
30
|
+
exports.viewFromRequest = viewFromRequest;
|
|
31
|
+
exports.MUTATING_VIEW_ROUTES = new Set([
|
|
32
|
+
"/updateRecord",
|
|
33
|
+
"/createRecord",
|
|
34
|
+
"/deleteRecord",
|
|
35
|
+
"/deleteRecords",
|
|
36
|
+
"/deleteRecordFromPanel",
|
|
37
|
+
"/customAction",
|
|
38
|
+
"/uploadFile",
|
|
39
|
+
]);
|
|
40
|
+
const areSafeColumnNames = (data) => !data || Object.keys(data).every((k) => /^[A-Za-z0-9_]+$/.test(k));
|
|
41
|
+
exports.areSafeColumnNames = areSafeColumnNames;
|
|
42
|
+
const writableTables = (req) => {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
const role = (0, exports.roleOf)(req);
|
|
45
|
+
const tables = new Set();
|
|
46
|
+
for (const view of ((_a = req.config) === null || _a === void 0 ? void 0 : _a.views) || []) {
|
|
47
|
+
if (!(0, exports.canWriteView)(view, role))
|
|
48
|
+
continue;
|
|
49
|
+
if (view.tableName)
|
|
50
|
+
tables.add(view.tableName);
|
|
51
|
+
for (const panel of view.recordViewPanels || []) {
|
|
52
|
+
if (panel.tableName)
|
|
53
|
+
tables.add(panel.tableName);
|
|
54
|
+
if ((_b = panel.createConfig) === null || _b === void 0 ? void 0 : _b.tableName)
|
|
55
|
+
tables.add(panel.createConfig.tableName);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return tables;
|
|
59
|
+
};
|
|
60
|
+
exports.writableTables = writableTables;
|
|
61
|
+
const looksLikeSqlBreakout = (frag) => typeof frag === "string" &&
|
|
62
|
+
/(;|--|\/\*|\bunion\b|\binto\s+(out|dump)file\b|\bsleep\s*\(|\bbenchmark\s*\(|\bload_file\s*\()/i.test(frag);
|
|
63
|
+
exports.looksLikeSqlBreakout = looksLikeSqlBreakout;
|
|
64
|
+
const hiddenColumnsOf = (view) => (view && view.__hiddenColumns) || [];
|
|
65
|
+
exports.hiddenColumnsOf = hiddenColumnsOf;
|
|
66
|
+
const stripHiddenColumns = (view, record) => {
|
|
67
|
+
for (const name of (0, exports.hiddenColumnsOf)(view))
|
|
68
|
+
delete record[name];
|
|
69
|
+
return record;
|
|
70
|
+
};
|
|
71
|
+
exports.stripHiddenColumns = stripHiddenColumns;
|
|
72
|
+
const touchesHiddenColumn = (view, data) => (0, exports.hiddenColumnsOf)(view).some((name) => data && Object.prototype.hasOwnProperty.call(data, name));
|
|
73
|
+
exports.touchesHiddenColumn = touchesHiddenColumn;
|
|
74
|
+
//# sourceMappingURL=authorization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../src/api/authorization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BaseTypeColumn, Config, FileUploadProperties, RichTextColumn, SelectColumn, StandardColumn, Subview, View } from "../types/config";
|
|
2
|
+
import type dbManager from "../utils/dbManager";
|
|
3
|
+
type Identified = {
|
|
4
|
+
__id__?: string;
|
|
5
|
+
};
|
|
6
|
+
type EnrichmentColumn = StandardColumn & Pick<BaseTypeColumn, "required"> & Pick<RichTextColumn, "contentField"> & Pick<FileUploadProperties, "s3Config" | "gcpConfig"> & Partial<Pick<SelectColumn, "options">> & Identified & {
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
};
|
|
9
|
+
type EnrichmentView = Identified & {
|
|
10
|
+
subviews?: (Subview & Identified)[];
|
|
11
|
+
} & ({
|
|
12
|
+
type: "table";
|
|
13
|
+
tableName: string;
|
|
14
|
+
primaryId?: string;
|
|
15
|
+
columns: EnrichmentColumn[];
|
|
16
|
+
recordViewPanels?: (Identified & {
|
|
17
|
+
type: string;
|
|
18
|
+
createConfig?: {
|
|
19
|
+
columns: EnrichmentColumn[];
|
|
20
|
+
};
|
|
21
|
+
})[];
|
|
22
|
+
} | {
|
|
23
|
+
type: Exclude<View["type"], "table">;
|
|
24
|
+
});
|
|
25
|
+
type EnrichmentConfig = Pick<Config, "mysql" | "postgresql" | "enriched"> & {
|
|
26
|
+
views: EnrichmentView[];
|
|
27
|
+
};
|
|
28
|
+
type SchemaColumn = {
|
|
29
|
+
TABLE_NAME?: string;
|
|
30
|
+
COLUMN_NAME?: string;
|
|
31
|
+
COLUMN_KEY?: string;
|
|
32
|
+
IS_NULLABLE?: string;
|
|
33
|
+
DATA_TYPE?: string;
|
|
34
|
+
COLUMN_TYPE?: string;
|
|
35
|
+
};
|
|
36
|
+
type SchemaDatabase = {
|
|
37
|
+
query(...args: Parameters<dbManager["query"]>): Promise<Partial<Pick<Awaited<ReturnType<dbManager["query"]>>, "err" | "rows">>>;
|
|
38
|
+
};
|
|
39
|
+
export declare function generateUniqueIdForObject(obj: unknown): string;
|
|
40
|
+
export declare function enrichConfig(config: EnrichmentConfig, db: SchemaDatabase): Promise<void>;
|
|
41
|
+
export declare function enrichColumn(column: EnrichmentColumn, tableName: string, info: SchemaColumn[]): void;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateUniqueIdForObject = generateUniqueIdForObject;
|
|
4
|
+
exports.enrichConfig = enrichConfig;
|
|
5
|
+
exports.enrichColumn = enrichColumn;
|
|
6
|
+
const crypto = require("crypto");
|
|
7
|
+
function readSchemaColumns(value) {
|
|
8
|
+
if (!Array.isArray(value) || !value.every((row) => row !== null && typeof row === "object" && !Array.isArray(row)
|
|
9
|
+
&& (!("TABLE_NAME" in row) || typeof row.TABLE_NAME === "string")
|
|
10
|
+
&& (!("COLUMN_NAME" in row) || typeof row.COLUMN_NAME === "string")
|
|
11
|
+
&& (!("COLUMN_KEY" in row) || typeof row.COLUMN_KEY === "string")
|
|
12
|
+
&& (!("IS_NULLABLE" in row) || typeof row.IS_NULLABLE === "string")
|
|
13
|
+
&& (!("DATA_TYPE" in row) || typeof row.DATA_TYPE === "string")
|
|
14
|
+
&& (!("COLUMN_TYPE" in row) || typeof row.COLUMN_TYPE === "string")))
|
|
15
|
+
throw new TypeError("Invalid database schema columns");
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function readEnumOptions(columnType) {
|
|
19
|
+
if (columnType === undefined)
|
|
20
|
+
throw new TypeError("Missing enum column type");
|
|
21
|
+
const options = JSON.parse(columnType.replace("enum(", "[").replace(")", "]").replace(/'/g, '"'));
|
|
22
|
+
if (!Array.isArray(options) || !options.every((option) => typeof option === "string")) {
|
|
23
|
+
throw new TypeError("Invalid enum options");
|
|
24
|
+
}
|
|
25
|
+
return options;
|
|
26
|
+
}
|
|
27
|
+
function generateUniqueIdForObject(obj) {
|
|
28
|
+
const str = JSON.stringify(obj);
|
|
29
|
+
const hash = crypto.createHash("sha256").update(str).digest("hex");
|
|
30
|
+
return hash;
|
|
31
|
+
}
|
|
32
|
+
async function enrichConfig(config, db) {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
const { rows, err = null } = await db.query("SELECT * FROM information_schema.columns WHERE table_schema = ?", [((_a = config.mysql) === null || _a === void 0 ? void 0 : _a.database) || ((_b = config.postgresql) === null || _b === void 0 ? void 0 : _b.database)]);
|
|
35
|
+
if (err) {
|
|
36
|
+
console.error(err);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const info = readSchemaColumns(rows);
|
|
40
|
+
for (const view of config.views) {
|
|
41
|
+
if (view.type == "table") {
|
|
42
|
+
const tableName = view.tableName;
|
|
43
|
+
for (const infoEl of info) {
|
|
44
|
+
if (infoEl.TABLE_NAME == tableName && infoEl.COLUMN_KEY == "PRI") {
|
|
45
|
+
view.primaryId = infoEl.COLUMN_NAME;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const column of view.columns) {
|
|
49
|
+
enrichColumn(column, tableName, info);
|
|
50
|
+
}
|
|
51
|
+
if (view.recordViewPanels) {
|
|
52
|
+
for (const panel of view.recordViewPanels) {
|
|
53
|
+
if (panel.createConfig) {
|
|
54
|
+
for (const column of panel.createConfig.columns) {
|
|
55
|
+
enrichColumn(column, tableName, info);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!panel.__id__) {
|
|
59
|
+
panel.__id__ = generateUniqueIdForObject(panel);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (view.subviews) {
|
|
65
|
+
for (const subview of view.subviews) {
|
|
66
|
+
if (!subview.__id__) {
|
|
67
|
+
subview.__id__ = generateUniqueIdForObject(subview);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!view.__id__) {
|
|
72
|
+
view.__id__ = generateUniqueIdForObject(view);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
config.enriched = true;
|
|
76
|
+
}
|
|
77
|
+
function enrichColumn(column, tableName, info) {
|
|
78
|
+
var _a, _b, _c, _d;
|
|
79
|
+
if (!column.__id__) {
|
|
80
|
+
column.__id__ = generateUniqueIdForObject(column);
|
|
81
|
+
}
|
|
82
|
+
const infoEl = info.find((x) => x.TABLE_NAME == tableName && x.COLUMN_NAME == column.name);
|
|
83
|
+
if ((infoEl === null || infoEl === void 0 ? void 0 : infoEl.IS_NULLABLE) == "NO" &&
|
|
84
|
+
(infoEl === null || infoEl === void 0 ? void 0 : infoEl.DATA_TYPE) != "text" &&
|
|
85
|
+
column.required !== true &&
|
|
86
|
+
column.required !== false) {
|
|
87
|
+
column.required = true;
|
|
88
|
+
}
|
|
89
|
+
if (!column.dataType && infoEl) {
|
|
90
|
+
column.dataType = infoEl.DATA_TYPE;
|
|
91
|
+
if (column.dataType == "enum") {
|
|
92
|
+
column.dataType = "select";
|
|
93
|
+
column.options = readEnumOptions(infoEl.COLUMN_TYPE);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (column.dataType == "richText") {
|
|
97
|
+
column.name = column.contentField;
|
|
98
|
+
}
|
|
99
|
+
if (column.dataType == "file" && (column.s3Config || column.gcpConfig)) {
|
|
100
|
+
const host = ((_a = column.s3Config) === null || _a === void 0 ? void 0 : _a.host) || ((_b = column.gcpConfig) === null || _b === void 0 ? void 0 : _b.host);
|
|
101
|
+
const bucket = ((_c = column.s3Config) === null || _c === void 0 ? void 0 : _c.bucket) || ((_d = column.gcpConfig) === null || _d === void 0 ? void 0 : _d.bucket);
|
|
102
|
+
column.baseUrl = `https://${host}/${bucket}/`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/api/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterUserFromSession = filterUserFromSession;
|
|
4
|
+
function filterUserFromSession(value) {
|
|
5
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const role = "role" in value ? value.role : undefined;
|
|
9
|
+
if (typeof role !== "string") {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
if (role === "root") {
|
|
13
|
+
return { role };
|
|
14
|
+
}
|
|
15
|
+
const userId = "userId" in value ? value.userId : undefined;
|
|
16
|
+
if (userId === undefined) {
|
|
17
|
+
return { role };
|
|
18
|
+
}
|
|
19
|
+
if (typeof userId === "string" || typeof userId === "number") {
|
|
20
|
+
return { role, userId };
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=filterUser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterUser.js","sourceRoot":"","sources":["../../src/api/filterUser.ts"],"names":[],"mappings":";;AAMA,sDAqBC;AArBD,SAAgB,qBAAqB,CAAC,KAAc;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAY,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAY,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isImportRecords(value: unknown): value is Record<string, unknown>[];
|