Compare commits

...

59 Commits

Author SHA1 Message Date
semantic-release-bot 1db6984de3 chore(release): 7.8.0 [skip ci]
# [7.8.0](https://git.datacontroller.io/dc/dc/compare/v7.7.3...v7.8.0) (2026-05-15)

### Bug Fixes

* enabling DSN=*ALL* in MPE_SECURITY ([7d94cb2](7d94cb2ae4))
* providing default values for RULE_ACTIVE on MPE_VALIDATIONS ([f031b4e](f031b4eb89))
* switch away from api usage for CASLIB metadata ([ce921a0](ce921a032a))
* use correct debug param for runAsTask ([bb80476](bb80476767))

### Features

* add runAsTask config attribute parser ([1635bc9](1635bc9c45))
* enabling *ALL* option by default in MPE_SECURITY (DSN col) ([93d4ab6](93d4ab65ac))
2026-05-15 09:07:49 +00:00
allan 636ff237dd Merge pull request 'Updates following customer session' (#231) from customerfeedback into main
Release / Build-production-and-ng-test (push) Successful in 3m39s
Release / Build-and-test-development (push) Successful in 8m50s
Release / release (push) Successful in 7m39s
Reviewed-on: #231
2026-05-15 08:52:14 +00:00
sead 02963ab6d5 chore: bump adapter
Build / Build-and-ng-test (pull_request) Successful in 3m49s
Build / Build-and-test-development (pull_request) Successful in 9m2s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m12s
2026-05-15 10:29:54 +02:00
allan d40f61292a Merge pull request 'feat: add runAsTask config attribute parser' (#232) from feat/execution-tasks-flag into customerfeedback
Lighthouse Checks / lighthouse (pull_request) Failing after 3m31s
Build / Build-and-ng-test (pull_request) Failing after 3m51s
Build / Build-and-test-development (pull_request) Has been skipped
Reviewed-on: #232
2026-05-15 08:08:39 +00:00
4gl 7d94cb2ae4 fix: enabling DSN=*ALL* in MPE_SECURITY
Build / Build-and-ng-test (pull_request) Successful in 3m48s
Build / Build-and-test-development (pull_request) Successful in 8m59s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m8s
2026-05-14 22:47:17 +01:00
sead bb80476767 fix: use correct debug param for runAsTask
Lighthouse Checks / lighthouse (pull_request) Failing after 3m28s
Build / Build-and-ng-test (pull_request) Failing after 3m51s
Build / Build-and-test-development (pull_request) Has been skipped
2026-05-14 11:21:01 +02:00
sead 1635bc9c45 feat: add runAsTask config attribute parser 2026-05-14 11:19:32 +02:00
4gl f031b4eb89 fix: providing default values for RULE_ACTIVE on MPE_VALIDATIONS
Lighthouse Checks / lighthouse (pull_request) Successful in 18m12s
Build / Build-and-ng-test (pull_request) Successful in 3m40s
Build / Build-and-test-development (pull_request) Successful in 8m58s
2026-05-13 19:02:09 +01:00
4gl 93d4ab65ac feat: enabling *ALL* option by default in MPE_SECURITY (DSN col)
Build / Build-and-ng-test (pull_request) Successful in 3m53s
Build / Build-and-test-development (pull_request) Successful in 9m12s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m15s
2026-05-13 18:47:19 +01:00
4gl ce921a032a fix: switch away from api usage for CASLIB metadata 2026-05-13 18:46:35 +01:00
semantic-release-bot 322f904b4b chore(release): 7.7.3 [skip ci]
## [7.7.3](https://git.datacontroller.io/dc/dc/compare/v7.7.2...v7.7.3) (2026-05-12)

### Bug Fixes

* move cas session assign to settings.sas and abort when lib is unassigned ([65f0b97](65f0b979a4))
2026-05-12 18:43:04 +00:00
allan 982eeac58c Merge pull request 'fix: move cas session assign to settings.sas and abort when lib is unassigned' (#230) from viyaux into main
Release / Build-production-and-ng-test (push) Successful in 3m49s
Release / Build-and-test-development (push) Successful in 9m10s
Release / release (push) Successful in 8m2s
Reviewed-on: #230
2026-05-12 18:26:47 +00:00
allan 0ab9717556 Merge branch 'main' into viyaux
Build / Build-and-test-development (pull_request) Has been cancelled
Build / Build-and-ng-test (pull_request) Has been cancelled
Lighthouse Checks / lighthouse (pull_request) Successful in 18m27s
2026-05-12 18:26:35 +00:00
allan 24a85de8e1 Merge pull request 'chore(client): bump fast-uri' (#229) from audit-20260511 into main
Release / Build-production-and-ng-test (push) Successful in 3m40s
Release / Build-and-test-development (push) Successful in 8m50s
Release / release (push) Failing after 3m10s
Reviewed-on: #229
2026-05-11 17:38:14 +00:00
4gl 65f0b979a4 fix: move cas session assign to settings.sas and abort when lib is unassigned
Build / Build-and-ng-test (pull_request) Successful in 3m55s
Build / Build-and-test-development (pull_request) Successful in 9m13s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m48s
2026-05-11 15:08:20 +01:00
sead 947f34a0ad chore(client): bump fast-uri
Build / Build-and-ng-test (pull_request) Successful in 3m50s
Build / Build-and-test-development (pull_request) Successful in 9m6s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m19s
Resolve GHSA-q3j6-qgpj-74h6, GHSA-v39h-62p7-jpjc
2026-05-11 09:39:36 +02:00
semantic-release-bot 0f60fd7181 chore(release): 7.7.2 [skip ci]
## [7.7.2](https://git.datacontroller.io/dc/dc/compare/v7.7.1...v7.7.2) (2026-05-07)

### Bug Fixes

* **client:** bundle Metropolis font locally to satisfy CSP ([9546fcd](9546fcd631))
* **client:** clear angular build cache on font strip to avoid stale dist ([503cb08](503cb08b2f))
* **client:** postinstall removal of Metropolis [@font-face](https://git.datacontroller.io/font-face) from @clr/ui ([e6397ce](e6397cecc1))
* **client:** serve text-security-disc font locally ([80ce80e](80ce80ece4))
* **editor:** preserve numeric type for SAS num cols with static SOFTSELECT/HARDSELECT ([05a3289](05a328976e))
2026-05-07 15:18:44 +00:00
allan 251062e42e Merge pull request 'Multiple frontend client issues' (#228) from 227-csp-issues-20260507 into main
Release / Build-production-and-ng-test (push) Successful in 3m38s
Release / Build-and-test-development (push) Successful in 8m50s
Release / release (push) Successful in 7m35s
Reviewed-on: #228
2026-05-07 15:03:08 +00:00
sead 05a328976e fix(editor): preserve numeric type for SAS num cols with static SOFTSELECT/HARDSELECT
Build / Build-and-ng-test (pull_request) Successful in 3m43s
Build / Build-and-test-development (pull_request) Successful in 9m21s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m25s
2026-05-07 15:02:06 +02:00
sead 503cb08b2f fix(client): clear angular build cache on font strip to avoid stale dist 2026-05-07 13:43:57 +02:00
sead f71be20476 build(client): drop duplicate asset emits for fonts and CSS-referenced svgs 2026-05-07 13:43:49 +02:00
sead e6397cecc1 fix(client): postinstall removal of Metropolis @font-face from @clr/ui 2026-05-07 13:43:37 +02:00
sead 80ce80ece4 fix(client): serve text-security-disc font locally 2026-05-07 13:43:21 +02:00
sead 9546fcd631 fix(client): bundle Metropolis font locally to satisfy CSP 2026-05-07 13:43:05 +02:00
semantic-release-bot b79aaf4327 chore(release): 7.7.1 [skip ci]
## [7.7.1](https://git.datacontroller.io/dc/dc/compare/v7.7.0...v7.7.1) (2026-05-05)

### Bug Fixes

* **client:** bump adapter ([d26f7d2](d26f7d2511))
* **sas:** bump cli ([d60029d](d60029deae))
2026-05-05 20:04:33 +00:00
allan 76f9198f73 Merge pull request 'fix(client): bump adapter' (#226) from fix/adapter-20260505 into main
Release / Build-production-and-ng-test (push) Successful in 3m28s
Release / Build-and-test-development (push) Successful in 8m44s
Release / release (push) Successful in 7m33s
Reviewed-on: #226
2026-05-05 19:49:17 +00:00
4gl d60029deae fix(sas): bump cli
Build / Build-and-ng-test (pull_request) Successful in 3m57s
Build / Build-and-test-development (pull_request) Successful in 9m9s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m10s
2026-05-05 18:48:15 +01:00
sead d26f7d2511 fix(client): bump adapter
Build / Build-and-ng-test (pull_request) Successful in 4m21s
Build / Build-and-test-development (pull_request) Successful in 10m34s
Lighthouse Checks / lighthouse (pull_request) Successful in 19m37s
2026-05-05 17:16:55 +02:00
semantic-release-bot 33efe09b50 chore(release): 7.7.0 [skip ci]
# [7.7.0](https://git.datacontroller.io/dc/dc/compare/v7.6.0...v7.7.0) (2026-05-04)

### Bug Fixes

* bump adapter to 4.16.6 ([1707f38](1707f3802a))
* remove data:image/svg+xml CSP violation, use class instead changing style directly ([d66eb5d](d66eb5dfc2))
* remove WORK, SASUSER and CASUSER as library options.  [#224](#224) ([ec66631](ec66631a33))

### Features

* auto-save CAS tables [#224](#224) ([40d04a5](40d04a53c4))
* autoload CAS tables. [#224](#224) ([d5ebb01](d5ebb01ce3))
2026-05-04 23:24:36 +00:00
4gl e0aef9bf00 chore: pin got lib to enable release flow
Release / Build-production-and-ng-test (push) Successful in 11m47s
Release / Build-and-test-development (push) Successful in 17m37s
Release / release (push) Successful in 8m18s
2026-05-04 23:51:19 +01:00
allan 02d1a2e0b1 Merge pull request 'fix: resolve CSP violation and update dependancies' (#223) from fix/audit-20260413 into main
Release / Build-production-and-ng-test (push) Successful in 8m48s
Release / Build-and-test-development (push) Successful in 17m50s
Release / release (push) Failing after 5m52s
Reviewed-on: #223
Reviewed-by: allan <allan@4gl.io>
2026-05-04 16:50:52 +00:00
sead 4e3154e929 chore(cypress): enable e2e video, folder guards
Build / Build-and-ng-test (pull_request) Successful in 3m58s
Build / Build-and-test-development (pull_request) Successful in 9m6s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m21s
2026-05-04 12:57:31 +02:00
sead 32c0713256 chore: add hyperformula license exception
Build / Build-and-ng-test (pull_request) Successful in 3m44s
Build / Build-and-test-development (pull_request) Failing after 8m45s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m29s
2026-05-04 11:05:00 +02:00
sead defe15bcec chore: bump client eslint and sas sasjs packages
Build / Build-and-ng-test (pull_request) Failing after 1m34s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Failing after 1m47s
2026-05-04 10:42:31 +02:00
4gl 6f8e471f16 chore: dep man
Build / Build-and-ng-test (pull_request) Failing after 40s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Failing after 55s
2026-05-01 12:53:07 +01:00
4gl dc35abfd85 chore: dependency bumps
Build / Build-and-ng-test (pull_request) Failing after 42s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Failing after 1m0s
2026-05-01 12:36:39 +01:00
4gl 04a8c5d52a chore: bumping node
Build / Build-and-ng-test (pull_request) Failing after 50s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Failing after 57s
2026-05-01 11:46:10 +01:00
4gl 2cb370053d chore: rebuilt package lock
Build / Build-and-ng-test (pull_request) Failing after 42s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Failing after 1m3s
2026-05-01 11:34:30 +01:00
4gl 1707f3802a fix: bump adapter to 4.16.6
Lighthouse Checks / lighthouse (pull_request) Failing after 1m7s
Build / Build-and-ng-test (pull_request) Failing after 1m44s
Build / Build-and-test-development (pull_request) Has been skipped
2026-05-01 10:59:59 +01:00
allan c87ba660ca Merge branch 'main' into fix/audit-20260413
Build / Build-and-ng-test (pull_request) Successful in 3m58s
Build / Build-and-test-development (pull_request) Successful in 9m56s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m30s
2026-04-30 16:44:46 +00:00
allan ef8a2dbc38 Merge pull request 'fix: remove WORK, SASUSER and CASUSER as library options, plus auto CAS table load' (#225) from issue224 into main
Release / Build-production-and-ng-test (push) Failing after 1m28s
Release / Build-and-test-development (push) Has been skipped
Release / release (push) Has been skipped
Reviewed-on: #225
2026-04-30 15:28:50 +00:00
4gl 40d04a53c4 feat: auto-save CAS tables #224
Build / Build-and-ng-test (pull_request) Successful in 4m2s
Build / Build-and-test-development (pull_request) Successful in 10m6s
Lighthouse Checks / lighthouse (pull_request) Successful in 19m5s
2026-04-30 16:04:31 +01:00
4gl d5ebb01ce3 feat: autoload CAS tables. #224
Build / Build-and-ng-test (pull_request) Successful in 4m6s
Build / Build-and-test-development (pull_request) Successful in 10m9s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m54s
2026-04-30 15:41:20 +01:00
allan ec66631a33 fix: remove WORK, SASUSER and CASUSER as library options. #224
Build / Build-and-ng-test (pull_request) Successful in 4m15s
Build / Build-and-test-development (pull_request) Successful in 10m28s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m47s
2026-04-17 14:21:24 +01:00
sead d66eb5dfc2 fix: remove data:image/svg+xml CSP violation, use class instead changing style directly
Build / Build-and-ng-test (pull_request) Failing after 1m16s
Build / Build-and-test-development (pull_request) Has been skipped
Lighthouse Checks / lighthouse (pull_request) Successful in 18m7s
2026-04-13 10:29:54 +02:00
sead 731b589ed8 chore: override ajv and regenrate lock file 2026-04-13 09:23:13 +02:00
sead fe92d5fc36 chore: bump angular to latest 19 2026-04-13 08:58:54 +02:00
sead a335b400f1 chore: bump @sasjs/adapter 2026-04-13 08:55:48 +02:00
semantic-release-bot f63e507ddf chore(release): 7.6.0 [skip ci]
# [7.6.0](https://git.datacontroller.io/dc/dc/compare/v7.5.0...v7.6.0) (2026-04-03)

### Bug Fixes

* add label and tooltip for libref download, sanitise input ([52d5803](52d58036a4))

### Features

* configurable email alerts.  Closes [#217](#217) ([2ccf0d1](2ccf0d1100))
2026-04-03 22:17:14 +00:00
allan 991cc0567d Merge pull request 'feat: configurable email alerts. Closes #217' (#222) from issue217 into main
Release / Build-production-and-ng-test (push) Successful in 3m42s
Release / Build-and-test-development (push) Successful in 10m10s
Release / release (push) Successful in 7m48s
Reviewed-on: #222
2026-04-03 21:09:11 +00:00
sead 52d58036a4 fix: add label and tooltip for libref download, sanitise input
Build / Build-and-ng-test (pull_request) Successful in 4m6s
Build / Build-and-test-development (pull_request) Successful in 10m13s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m37s
2026-04-03 19:55:42 +02:00
allan 26bff85792 chore: fix debug line
Build / Build-and-ng-test (pull_request) Successful in 4m47s
Build / Build-and-test-development (pull_request) Successful in 10m16s
Lighthouse Checks / lighthouse (pull_request) Successful in 19m41s
2026-04-03 18:35:48 +01:00
allan 2ccf0d1100 feat: configurable email alerts. Closes #217
Build / Build-and-ng-test (pull_request) Successful in 4m42s
Build / Build-and-test-development (pull_request) Has been cancelled
Lighthouse Checks / lighthouse (pull_request) Has been cancelled
2026-04-03 18:34:23 +01:00
semantic-release-bot 3be33186bc chore(release): 7.5.0 [skip ci]
# [7.5.0](https://git.datacontroller.io/dc/dc/compare/v7.4.1...v7.5.0) (2026-04-03)

### Bug Fixes

* add workflow audits, update deps ([66e98a9](66e98a96cb))
* allow CSV uploads with licence row limit ([5b260e4](5b260e4915)), closes [#213](#213)
* bumping cli and pinning versions in .npmrc ([80039f4](80039f4876))
* guard CSV upload with fileUpload licence flag ([ed40df6](ed40df6295))
* parse embed param from window.location.hash for hash router compatibility ([0269c24](0269c2421d))
* quote CSV char values.  Closes [#215](#215) ([d9980e8](d9980e866d))
* resolve outer promise in parseCsvFile for non-WLATIN1 path ([4ee15e1](4ee15e1b6e))
* use XLSX for CSV row truncation to handle new lines in values ([6d590c0](6d590c050d))

### Features

* add embed URL parameter to hide header and back button ([b0dc441](b0dc441d68)), closes [#214](#214)
* add target libref input to config download ([a89657b](a89657b0b8)), closes [#212](#212)
* export config service to allow dclib swapping.  Closes [#212](#212) ([326c26f](326c26fddf))
2026-04-03 11:06:36 +00:00
allan 1a7f950ae2 Merge pull request 'feat: enabling dclib switching when exporting config' (#220) from issue212 into main
Release / Build-production-and-ng-test (push) Successful in 3m39s
Release / Build-and-test-development (push) Successful in 9m55s
Release / release (push) Successful in 7m46s
Reviewed-on: #220
2026-04-03 10:49:43 +00:00
allan 8924dc8ab1 chore: merge buid.yaml
Build / Build-and-ng-test (pull_request) Successful in 3m58s
Build / Build-and-test-development (pull_request) Successful in 10m3s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m46s
2026-04-03 10:30:05 +00:00
allan 0b0db1c543 chore: run audit check in build.yaml as well as release.yaml
Build / Build-and-ng-test (pull_request) Failing after 1m31s
Build / Build-and-test-development (pull_request) Successful in 10m23s
Lighthouse Checks / lighthouse (24.5.0) (pull_request) Successful in 19m32s
2026-04-03 01:18:54 +00:00
allan 80039f4876 fix: bumping cli and pinning versions in .npmrc
Build / Build-and-ng-test (pull_request) Successful in 3m51s
Build / Build-and-test-development (pull_request) Successful in 10m9s
Lighthouse Checks / lighthouse (24.5.0) (pull_request) Successful in 19m11s
2026-04-03 02:02:05 +01:00
allan 326c26fddf feat: export config service to allow dclib swapping. Closes #212 2026-04-03 02:01:44 +01:00
62 changed files with 8278 additions and 9031 deletions
+19 -15
View File
@@ -3,7 +3,7 @@ run-name: Running Lint Check and Licence checker on Pull Request
on: [pull_request]
env:
NODE_VERSION: '24.5.0'
NODE_VERSION: '24.15.0'
jobs:
Build-and-ng-test:
@@ -22,30 +22,33 @@ jobs:
apt install -y ./google-chrome*.deb
- name: Write .npmrc file
run: echo "$NPMRC" > client/.npmrc
run: echo "$NPMRC" >> client/.npmrc
shell: bash
env:
NPMRC: ${{ secrets.NPMRC}}
- name: Check audit
# Audit should fail and stop the CI if critical vulnerability found
run: |
npm audit --omit=dev
cd ./sas
npm audit --omit=dev
cd ../client
npm audit --audit-level=critical --omit=dev
- name: Lint check
run: npm run lint:check
- name: Install dependencies
run: |
cd client
# Decrypt and Install sheet
echo ${{ secrets.SHEET_PWD }} | gpg --batch --yes --passphrase-fd 0 ./libraries/sheet-crypto.tgz.gpg
echo "${{ secrets.SHEET_PWD }}" | \
gpg --batch --yes --passphrase-fd 0 \
--output ./libraries/sheet-crypto.tgz \
--decrypt ./libraries/sheet-crypto.tgz.gpg
npm ci
- name: Check audit
# Audit should fail and stop the CI if critical vulnerability found
run: |
npm audit --audit-level=critical --omit=dev
cd ./sas
npm audit --audit-level=critical --omit=dev
cd ../client
npm audit --audit-level=critical --omit=dev
- name: Lint check
run: npm run lint:check
- name: Licence checker
run: |
cd client
@@ -139,6 +142,7 @@ jobs:
- name: Zip Cypress videos
if: always()
run: |
mkdir -p ./client/cypress/videos
zip -r cypress-videos ./client/cypress/videos
- name: Add cypress videos artifacts
+5 -2
View File
@@ -3,7 +3,7 @@ run-name: Running Lighthouse Performance and Accessibility Checks on Pull Reques
on: [pull_request]
env:
NODE_VERSION: '24.5.0'
NODE_VERSION: '24.15.0'
jobs:
lighthouse:
@@ -48,7 +48,10 @@ jobs:
run: |
cd client
# Decrypt and Install sheet
echo ${{ secrets.SHEET_PWD }} | gpg --batch --yes --passphrase-fd 0 ./libraries/sheet-crypto.tgz.gpg
echo "${{ secrets.SHEET_PWD }}" | \
gpg --batch --yes --passphrase-fd 0 \
--output ./libraries/sheet-crypto.tgz \
--decrypt ./libraries/sheet-crypto.tgz.gpg
npm ci
npm install -g replace-in-files-cli
+1
View File
@@ -142,6 +142,7 @@ jobs:
- name: Zip Cypress videos
if: always()
run: |
mkdir -p ./client/cypress/videos
zip -r cypress-videos ./client/cypress/videos
- name: Add cypress videos artifacts
+3
View File
@@ -1 +1,4 @@
legacy-peer-deps=true
ignore-scripts=true
save-exact=true
fund=false
+90
View File
@@ -1,3 +1,93 @@
# [7.8.0](https://git.datacontroller.io/dc/dc/compare/v7.7.3...v7.8.0) (2026-05-15)
### Bug Fixes
* enabling DSN=*ALL* in MPE_SECURITY ([7d94cb2](https://git.datacontroller.io/dc/dc/commit/7d94cb2ae4a3f6c1fa1011ae0fced7083a2f2793))
* providing default values for RULE_ACTIVE on MPE_VALIDATIONS ([f031b4e](https://git.datacontroller.io/dc/dc/commit/f031b4eb8925397e60dcc739a721cfbbb6da8dff))
* switch away from api usage for CASLIB metadata ([ce921a0](https://git.datacontroller.io/dc/dc/commit/ce921a032a8970b8078a463a41da884e1fa71bc3))
* use correct debug param for runAsTask ([bb80476](https://git.datacontroller.io/dc/dc/commit/bb8047676749814d3b86eea666726dbe4bf5f270))
### Features
* add runAsTask config attribute parser ([1635bc9](https://git.datacontroller.io/dc/dc/commit/1635bc9c451bc221f386241007f594096f114b4f))
* enabling *ALL* option by default in MPE_SECURITY (DSN col) ([93d4ab6](https://git.datacontroller.io/dc/dc/commit/93d4ab65acce7b5b35e448146f9893964ad2cca3))
## [7.7.3](https://git.datacontroller.io/dc/dc/compare/v7.7.2...v7.7.3) (2026-05-12)
### Bug Fixes
* move cas session assign to settings.sas and abort when lib is unassigned ([65f0b97](https://git.datacontroller.io/dc/dc/commit/65f0b979a401277b3e070d409659ae3fae2ff8c0))
## [7.7.2](https://git.datacontroller.io/dc/dc/compare/v7.7.1...v7.7.2) (2026-05-07)
### Bug Fixes
* **client:** bundle Metropolis font locally to satisfy CSP ([9546fcd](https://git.datacontroller.io/dc/dc/commit/9546fcd6312f3e81f746ef6e32ef398810ed434a))
* **client:** clear angular build cache on font strip to avoid stale dist ([503cb08](https://git.datacontroller.io/dc/dc/commit/503cb08b2fa40397434189f9c20eff3358eb7010))
* **client:** postinstall removal of Metropolis [@font-face](https://git.datacontroller.io/font-face) from @clr/ui ([e6397ce](https://git.datacontroller.io/dc/dc/commit/e6397cecc13afe2a9238bdfb2b4b9b81f38d055c))
* **client:** serve text-security-disc font locally ([80ce80e](https://git.datacontroller.io/dc/dc/commit/80ce80ece40012e59c7cd0340b4aa9a9aca46443))
* **editor:** preserve numeric type for SAS num cols with static SOFTSELECT/HARDSELECT ([05a3289](https://git.datacontroller.io/dc/dc/commit/05a328976ea3d1d6ef7559850369aa580f0d067f))
## [7.7.1](https://git.datacontroller.io/dc/dc/compare/v7.7.0...v7.7.1) (2026-05-05)
### Bug Fixes
* **client:** bump adapter ([d26f7d2](https://git.datacontroller.io/dc/dc/commit/d26f7d2511008634124c7d6fde115abb43db9c43))
* **sas:** bump cli ([d60029d](https://git.datacontroller.io/dc/dc/commit/d60029deae0ec21f3b8570461e2a4ca041d58f72))
# [7.7.0](https://git.datacontroller.io/dc/dc/compare/v7.6.0...v7.7.0) (2026-05-04)
### Bug Fixes
* bump adapter to 4.16.6 ([1707f38](https://git.datacontroller.io/dc/dc/commit/1707f3802a97de8c659f1a88c92fc917e8a30615))
* remove data:image/svg+xml CSP violation, use class instead changing style directly ([d66eb5d](https://git.datacontroller.io/dc/dc/commit/d66eb5dfc2dbb01f1e6c0c7d15fc2ad2a39dd829))
* remove WORK, SASUSER and CASUSER as library options. [#224](https://git.datacontroller.io/dc/dc/issues/224) ([ec66631](https://git.datacontroller.io/dc/dc/commit/ec66631a33aabb8ab2f92fe22c15440127085782))
### Features
* auto-save CAS tables [#224](https://git.datacontroller.io/dc/dc/issues/224) ([40d04a5](https://git.datacontroller.io/dc/dc/commit/40d04a53c4c00183116bdbd08397e0f2ffb1f578))
* autoload CAS tables. [#224](https://git.datacontroller.io/dc/dc/issues/224) ([d5ebb01](https://git.datacontroller.io/dc/dc/commit/d5ebb01ce381f5f4ec06de041f3ab9e632c02e43))
# [7.6.0](https://git.datacontroller.io/dc/dc/compare/v7.5.0...v7.6.0) (2026-04-03)
### Bug Fixes
* add label and tooltip for libref download, sanitise input ([52d5803](https://git.datacontroller.io/dc/dc/commit/52d58036a40e25847e900f9b04a77dbcc409c12b))
### Features
* configurable email alerts. Closes [#217](https://git.datacontroller.io/dc/dc/issues/217) ([2ccf0d1](https://git.datacontroller.io/dc/dc/commit/2ccf0d11000129629a0665421135b7530af9892f))
# [7.5.0](https://git.datacontroller.io/dc/dc/compare/v7.4.1...v7.5.0) (2026-04-03)
### Bug Fixes
* add workflow audits, update deps ([66e98a9](https://git.datacontroller.io/dc/dc/commit/66e98a96cbd092e762b94a04660f8e17ca003ceb))
* allow CSV uploads with licence row limit ([5b260e4](https://git.datacontroller.io/dc/dc/commit/5b260e49153dd85bc0023ad94d8a5f57b8ffa6dc)), closes [#213](https://git.datacontroller.io/dc/dc/issues/213)
* bumping cli and pinning versions in .npmrc ([80039f4](https://git.datacontroller.io/dc/dc/commit/80039f4876c8e09dc477678e1eff58329094c9e9))
* guard CSV upload with fileUpload licence flag ([ed40df6](https://git.datacontroller.io/dc/dc/commit/ed40df62953c3055770b5cbf50738f4a48b943cd))
* parse embed param from window.location.hash for hash router compatibility ([0269c24](https://git.datacontroller.io/dc/dc/commit/0269c2421db245f7f5405678605cb4d4587e2a67))
* quote CSV char values. Closes [#215](https://git.datacontroller.io/dc/dc/issues/215) ([d9980e8](https://git.datacontroller.io/dc/dc/commit/d9980e866d1a2fe7a731ff279d73accd35003e67))
* resolve outer promise in parseCsvFile for non-WLATIN1 path ([4ee15e1](https://git.datacontroller.io/dc/dc/commit/4ee15e1b6e83f27f279fc345e6998452a8f64d7e))
* use XLSX for CSV row truncation to handle new lines in values ([6d590c0](https://git.datacontroller.io/dc/dc/commit/6d590c050dcd593a73464fae5604f774f016b10d))
### Features
* add embed URL parameter to hide header and back button ([b0dc441](https://git.datacontroller.io/dc/dc/commit/b0dc441d681369e06eee58288dbdbb236f930bdc)), closes [#214](https://git.datacontroller.io/dc/dc/issues/214)
* add target libref input to config download ([a89657b](https://git.datacontroller.io/dc/dc/commit/a89657b0b81b9c531f64c0dda2714b4eb16c4bc9)), closes [#212](https://git.datacontroller.io/dc/dc/issues/212)
* export config service to allow dclib swapping. Closes [#212](https://git.datacontroller.io/dc/dc/issues/212) ([326c26f](https://git.datacontroller.io/dc/dc/commit/326c26fddfa88a0dc4ca79d3bd0c77c4d807f37c))
## [7.4.1](https://git.datacontroller.io/dc/dc/compare/v7.4.0...v7.4.1) (2026-03-12)
+2 -1
View File
@@ -62,7 +62,8 @@
{
"glob": "**/*",
"input": "src/images",
"output": "images"
"output": "images",
"ignore": ["spinner.svg", "caret.svg"]
}
],
"styles": ["src/styles.scss"],
+18 -17
View File
@@ -1,13 +1,13 @@
import { defineConfig } from "cypress";
import { defineConfig } from 'cypress'
export default defineConfig({
reporter: "mochawesome",
reporter: 'mochawesome',
reporterOptions: {
reportDir: "cypress/results",
reportDir: 'cypress/results',
overwrite: false,
html: true,
json: false,
json: false
},
viewportHeight: 900,
viewportWidth: 1600,
@@ -16,24 +16,25 @@ export default defineConfig({
defaultCommandTimeout: 30000,
env: {
hosturl: "http://localhost:4200",
appLocation: "",
site_id_SAS9: "70221618",
site_id_SASVIYA: "70253615",
site_id_SASJS: "123",
serverType: "SASJS",
libraryToOpenIncludes_SASVIYA: "viya",
libraryToOpenIncludes_SAS9: "dc",
libraryToOpenIncludes_SASJS: "dc",
hosturl: 'http://localhost:4200',
appLocation: '',
site_id_SAS9: '70221618',
site_id_SASVIYA: '70253615',
site_id_SASJS: '123',
serverType: 'SASJS',
libraryToOpenIncludes_SASVIYA: 'viya',
libraryToOpenIncludes_SAS9: 'dc',
libraryToOpenIncludes_SASJS: 'dc',
debug: false,
screenshotOnRunFailure: false,
longerCommandTimeout: 50000,
testLicenceUserLimits: false,
testLicenceUserLimits: false
},
e2e: {
video: true,
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
}
}
})
+1 -1
View File
@@ -10,7 +10,7 @@ const check = (cwd) => {
onlyAllow:
'AFLv2.1;Apache 2.0;Apache-2.0;Apache*;Artistic-2.0;0BSD;BSD*;BSD-2-Clause;BSD-3-Clause;CC0-1.0;CC-BY-3.0;CC-BY-4.0;ISC;MIT;MPL-2.0;ODC-By-1.0;Python-2.0;Unlicense;',
excludePackages:
'@cds/city@1.1.0;@handsontable/angular-wrapper@16.0.1;handsontable@^16.0.1;handsontable@16.2.0;hyperformula@2.7.1;hyperformula@3.0.0;hyperformula@3.1.0;jackspeak@3.4.3;path-scurry@1.11.1;package-json-from-dist@1.0.1'
'@cds/city@1.1.0;@handsontable/angular-wrapper@16.0.1;handsontable@^16.0.1;handsontable@16.2.0;hyperformula@2.7.1;hyperformula@3.0.0;hyperformula@3.1.0;hyperformula@3.2.0;jackspeak@3.4.3;path-scurry@1.11.1;package-json-from-dist@1.0.1'
},
(error, json) => {
if (error) {
+5343 -6471
View File
File diff suppressed because it is too large Load Diff
+22 -19
View File
@@ -23,7 +23,7 @@
"watch": "ng test watch=true",
"pree2e": "webdriver-manager update",
"e2e": "protractor protractor.config.js",
"postinstall": "node ./src/version.ts && npm run add-githook",
"postinstall": "node ./src/version.ts && npm run add-githook && node ./scripts/strip-clr-base64-fonts.mjs",
"add-githook": "[ -d ../.git ] && git config core.hooksPath ./.git-hooks || true",
"cypress": "cypress open",
"cy:run": "cypress run",
@@ -37,21 +37,21 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^19.2.18",
"@angular/animations": "^19.2.20",
"@angular/cdk": "^19.2.19",
"@angular/common": "^19.2.18",
"@angular/compiler": "^19.2.18",
"@angular/core": "^19.2.18",
"@angular/forms": "^19.2.18",
"@angular/platform-browser": "^19.2.18",
"@angular/platform-browser-dynamic": "^19.2.18",
"@angular/router": "^19.2.18",
"@angular/common": "^19.2.20",
"@angular/compiler": "^19.2.20",
"@angular/core": "^19.2.20",
"@angular/forms": "^19.2.20",
"@angular/platform-browser": "^19.2.20",
"@angular/platform-browser-dynamic": "^19.2.20",
"@angular/router": "^19.2.20",
"@cds/core": "^6.15.1",
"@clr/angular": "file:libraries/clr-angular-17.9.0.tgz",
"@clr/icons": "^13.0.2",
"@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
"@handsontable/angular-wrapper": "16.0.1",
"@sasjs/adapter": "^4.16.3",
"@sasjs/adapter": "^4.17.0",
"@sasjs/utils": "^3.5.3",
"@sheet/crypto": "file:libraries/sheet-crypto.tgz",
"@types/d3-graphviz": "^2.6.7",
@@ -86,18 +86,18 @@
"zone.js": "~0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.2.19",
"@angular-devkit/build-angular": "^19.2.24",
"@angular-eslint/builder": "19.8.1",
"@angular-eslint/eslint-plugin": "19.8.1",
"@angular-eslint/eslint-plugin-template": "19.8.1",
"@angular-eslint/schematics": "19.8.1",
"@angular-eslint/template-parser": "19.8.1",
"@angular/cli": "^19.2.19",
"@angular/compiler-cli": "^19.2.18",
"@angular/cli": "^19.2.24",
"@angular/compiler-cli": "^19.2.20",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@compodoc/compodoc": "^1.1.21",
"@compodoc/compodoc": "^1.2.1",
"@cypress/webpack-preprocessor": "^5.17.1",
"@lhci/cli": "^0.12.0",
"@lhci/cli": "^0.15.1",
"@types/core-js": "^2.5.5",
"@types/crypto-js": "^4.2.1",
"@types/es6-shim": "^0.31.39",
@@ -105,15 +105,15 @@
"@types/lodash-es": "^4.17.3",
"@types/marked": "^4.3.0",
"@types/node": "12.20.50",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
"core-js": "^2.5.4",
"cypress": "12.17.1",
"cypress": "^15.14.2",
"cypress-file-upload": "^5.0.8",
"cypress-plugin-tab": "^1.0.5",
"cypress-real-events": "^1.8.1",
"es6-shim": "^0.35.5",
"eslint": "^8.33.0",
"eslint": "8.57.1",
"git-describe": "^4.0.4",
"jasmine-core": "~5.1.2",
"karma": "~6.4.3",
@@ -132,5 +132,8 @@
"typescript": "~5.8.3",
"wait-on": "^6.0.1",
"watch": "^1.0.2"
},
"overrides": {
"ajv": "8.18.0"
}
}
+59
View File
@@ -0,0 +1,59 @@
import { readFileSync, writeFileSync, statSync, rmSync, existsSync } from 'fs'
import { resolve } from 'path'
/**
* Remove Clarity's Metropolis @font-face blocks from clr-ui.min.css.
*
* Why: Clarity ships Metropolis as base64 data: URLs. The deployed app
* runs under CSP `default-src 'self'` (no data: font-src), so every page
* logs a font-load failure for each weight. Firefox preemptively
* validates every parsed src against CSP even when a later @font-face
* supersedes the rule at render time, so the only way to silence the
* console is to remove the offending blocks from the parsed CSS.
*
* Our styles.scss declares the same family/weight/style with same-origin
* .woff files, so removing Clarity's blocks entirely is safe and leaves
* Metropolis fully functional.
*
* Idempotent: matches by font-family, so works on a fresh install or a
* file that's already been stripped on a previous run.
*/
const target = resolve('node_modules/@clr/ui/clr-ui.min.css')
let css
try {
css = readFileSync(target, 'utf8')
} catch (err) {
if (err.code === 'ENOENT') {
console.log(`skip: ${target} not found (likely pre-install run)`)
process.exit(0)
}
throw err
}
const sizeBefore = statSync(target).size
const blockRe = /@font-face\{[^}]*Metropolis[^}]*\}/g
const matches = css.match(blockRe) ?? []
if (matches.length === 0) {
console.log(`already stripped: ${target}`)
process.exit(0)
}
const stripped = css.replace(blockRe, '')
writeFileSync(target, stripped)
const sizeAfter = Buffer.byteLength(stripped)
console.log(
`removed ${matches.length} Metropolis @font-face block(s) from clr-ui.min.css ` +
`(${sizeBefore} -> ${sizeAfter} bytes, saved ${sizeBefore - sizeAfter})`
)
// Webpack 5's persistent cache treats node_modules as immutable
// (snapshot.module.managedPaths default), so in-place edits don't
// invalidate cached entries. Drop the Angular build cache so the next
// build re-reads our stripped clr-ui.min.css.
const cacheDir = resolve('.angular/cache')
if (existsSync(cacheDir)) {
rmSync(cacheDir, { recursive: true, force: true })
console.log(`cleared ${cacheDir} (webpack persistent cache)`)
}
+1
View File
@@ -209,6 +209,7 @@ export class AppComponent {
dcPath: getAppAttribute('dcPath') || '',
debug: getAppAttribute('debug') === 'true' || false,
useComputeApi: this.parseComputeApi(getAppAttribute('useComputeApi')),
runAsTask: getAppAttribute('runAsTask') === 'true' || false,
contextName: getAppAttribute('contextName') || '',
hotLicenceKey: getAppAttribute('hotLicenceKey') || ''
}
@@ -373,7 +373,7 @@ export class AutomaticComponent implements OnInit {
let contextname = `&_contextname=${params.contextName}`
let admin = `&admin=${params.admin}`
let dcPath = `&dcpath=${params.dcPath}`
let debug = `&_debug=131`
let debug = this.sasService.getDebugUrlParam()
let programUrl =
serverUrl +
@@ -251,7 +251,7 @@ export class ManualComponent implements OnInit {
this.selectedAdminGroup +
'&DCPATH=' +
this.dcPath +
'&_debug=131'
this.sasService.getDebugUrlParam()
window.open(url, '_blank')
+2 -1
View File
@@ -13,6 +13,7 @@ import {
import { ActivatedRoute, Router } from '@angular/router'
import Handsontable from 'handsontable'
import { Subject, Subscription } from 'rxjs'
import { sanitiseForSas } from '../shared/utils/sanitise'
import { SasStoreService } from '../services/sas-store.service'
type AOA = any[][]
@@ -1669,7 +1670,7 @@ export class EditorComponent implements OnInit, AfterViewInit, OnDestroy {
this.submit = true
const updateParams: any = {}
updateParams.ACTION = 'LOAD'
this.message = this.message.replace(/\n/g, '. ')
this.message = sanitiseForSas(this.message.replace(/\n/g, '. '))
updateParams.MESSAGE = this.message
// updateParams.APPROVER = this.approver;
updateParams.LIBDS = this.libds
@@ -1,4 +1,5 @@
import { ActivatedRoute } from '@angular/router'
import { sanitiseForSas } from '../../shared/utils/sanitise'
import { SasStoreService } from '../../services/sas-store.service'
import {
Component,
@@ -136,7 +137,7 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
public async rejecting() {
this.rejectLoading = true
this.submitReason = this.submitReason.replace(/\n/g, '. ')
this.submitReason = sanitiseForSas(this.submitReason.replace(/\n/g, '. '))
let rejParams = {
STP_ACTION: 'REJECT_TABLE',
+17
View File
@@ -641,6 +641,23 @@ export class SasService {
this.sasjsAdapter.setDebugState(state)
}
/**
* Returns the `&_debug=...` URL segment honoring the live adapter
* config. Empty string when debug is off. `128` on the Viya WEB JES path
* with `runAsTask` enabled, `131` otherwise.
*/
public getDebugUrlParam(): string {
const config = this.sasjsAdapter.getSasjsConfig()
if (!config.debug) return ''
const value =
config.serverType === ServerType.SasViya &&
config.useComputeApi === null &&
config.runAsTask === true
? 128
: 131
return `&_debug=${value}`
}
public getSasjsInstance() {
return this.sasjsAdapter
}
@@ -284,10 +284,18 @@ export class DcValidator {
)
if (source.length > 0) {
// For SAS num cols keep type='numeric' so HOT's numericEditor /
// numericRenderer + numbro coercion stay alive — same per-column
// model as the per-cell pattern in
// editor.component.ts:reSetCellValidationValues().
this.rules[i].source = source
this.rules[i].type = 'autocomplete'
this.rules[i].editor = 'autocomplete.custom'
this.rules[i].renderer = 'autocomplete'
this.rules[i].filter = false
if (this.rules[i].sasType !== 'num') {
this.rules[i].type = 'autocomplete'
}
}
if (this.hasDqRules(ruleColName, ['SOFTSELECT'])) {
@@ -10,6 +10,9 @@ export interface DcColumnSettings {
valid?: boolean
desc?: string
clsRule?: string
// SAS-side column type from $dataFormats (e.g. 'num', 'char') — distinct
// from Handsontable's `type` which drives renderer/editor selection
sasType?: string
}
export interface DcValidation extends HotColumnSettings, DcColumnSettings {}
@@ -38,11 +38,52 @@ describe('DC Validator - merge spec rules', () => {
data: 'test_col',
desc: 'test_desc',
clsRule: 'cls_rule',
length: 8
length: 8,
sasType: 'test_type'
}
]
expect(mergeColsRules(cols, rules, $dataFormats)).toEqual(expected)
expect(cols[0].TYPE).toEqual('test_type')
})
it('should populate sasType for num and char cols', () => {
const rules: DcValidation[] = [{ data: 'num_col' }, { data: 'char_col' }]
const cols: Col[] = [
{
NAME: 'num_col',
MEMLABEL: '',
DESC: '',
LONGDESC: '',
TYPE: '',
CLS_RULE: '',
VARNUM: 0,
LABEL: '',
FMTNAME: '',
DDTYPE: ''
},
{
NAME: 'char_col',
MEMLABEL: '',
DESC: '',
LONGDESC: '',
TYPE: '',
CLS_RULE: '',
VARNUM: 0,
LABEL: '',
FMTNAME: '',
DDTYPE: ''
}
]
const $dataFormats: any = {
vars: {
num_col: { format: 'best.', label: '', length: '8', type: 'num' },
char_col: { format: '$32.', label: '', length: '32', type: 'char' }
}
}
const merged = mergeColsRules(cols, rules, $dataFormats)
expect(merged.find((r) => r.data === 'num_col')?.sasType).toEqual('num')
expect(merged.find((r) => r.data === 'char_col')?.sasType).toEqual('char')
})
})
@@ -29,6 +29,7 @@ export const mergeColsRules = (
if (rule && col.DESC) rule.desc = col.DESC
if (rule && colFormats.length) rule.length = parseInt(colFormats.length)
if (rule && col.CLS_RULE) rule.clsRule = col.CLS_RULE
if (rule && colFormats?.type) rule.sasType = colFormats.type
}
return rules
@@ -80,15 +80,13 @@ export class SidebarComponent implements OnInit {
public resizeStart() {
this.resizing = true
let body = document.getElementsByTagName('body')[0]
body.style.cssText = 'user-select: none'
document.body.classList.add('select-none')
}
public resizeEnd() {
this.resizing = false
let body = document.getElementsByTagName('body')[0]
body.style.cssText = ''
document.body.classList.remove('select-none')
}
@HostListener('document:mousemove', ['$event'])
+6
View File
@@ -0,0 +1,6 @@
/**
* Strips characters that could cause SAS macro injection (& % ;).
*/
export function sanitiseForSas(input: string): string {
return input.replace(/[%&;]/g, '')
}
+25 -8
View File
@@ -236,14 +236,31 @@
<div class="admin-action">
Download Configuration
<input
type="text"
class="clr-input libref-input"
maxlength="8"
[ngModel]="dcLib"
(ngModelChange)="targetLibref = $event.toUpperCase()"
placeholder="Target Libref"
/>
<div class="libref-group">
<clr-tooltip class="libref-tooltip">
<label clrTooltipTrigger class="libref-label">
Target DC Library
<cds-icon shape="info-circle" size="16"></cds-icon>
</label>
<clr-tooltip-content
clrPosition="bottom-left"
clrSize="md"
*clrIfOpen
>
Enter the target DC library and the downloaded files will
contain this, instead of the original.
</clr-tooltip-content>
</clr-tooltip>
<input
type="text"
class="clr-input libref-input"
maxlength="8"
[ngModel]="dcLib"
(ngModelChange)="targetLibref = $event.toUpperCase()"
placeholder="e.g. MYLIB"
/>
</div>
<button
(click)="downloadConfiguration()"
[disabled]="targetLibref !== dcLib && !isValidLibref(targetLibref)"
+17 -1
View File
@@ -1,5 +1,21 @@
.libref-group {
display: inline-flex;
align-items: center;
gap: 4px;
margin: 0 8px;
}
.libref-label {
cursor: pointer;
font-size: 0.55rem;
font-weight: 600;
color: var(--clr-p4-color, #565656);
display: inline-flex;
align-items: center;
gap: 4px;
}
.libref-input {
width: 100px;
margin: 0 8px;
text-transform: uppercase;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+31 -14
View File
@@ -9,9 +9,39 @@
@import './colors.scss';
/* CSP: replace Clarity's base64 Metropolis @font-face srcs with same-origin files. */
@font-face {
font-family: 'Metropolis';
src: url('./assets/fonts/Metropolis-200.woff') format('woff');
font-weight: 200;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Metropolis';
src: url('./assets/fonts/Metropolis-400.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Metropolis';
src: url('./assets/fonts/Metropolis-500.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Metropolis';
src: url('./assets/fonts/Metropolis-600.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: text-security-disc;
src: url('https://raw.githubusercontent.com/noppa/text-security/master/dist/text-security-disc.woff');
src: url('./assets/fonts/text-security-disc.woff') format('woff');
}
// TODO: IMPORTANT CSP WOKRAROUND
@@ -1882,19 +1912,6 @@ app-query {
}
}
.clause-row:after {
position: relative;
content: "";
height: .41667rem;
width: .41667rem;
top: .29167rem;
right: .25rem;
background-image: url(data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org…%2C9.84%2C3.24a0.68%2C0.68%2C0%2C1%2C1%2C1%2C1Z%22%2F%3E%0A%3C%2Fsvg%3E%0A);
background-repeat: no-repeat;
background-size: contain;
vertical-align: middle;
margin: 0;
}
pre[class*="language-"] {
padding: 8px;
+1890 -2359
View File
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -1,17 +1,20 @@
{
"name": "dcfrontend",
"version": "7.4.1",
"version": "7.8.0",
"description": "Data Controller",
"devDependencies": {
"@saithodev/semantic-release-gitea": "^2.1.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^10.0.1",
"@semantic-release/commit-analyzer": "13.0.1",
"@semantic-release/git": "^10.0.1",
"@semantic-release/npm": "11.0.0",
"@semantic-release/release-notes-generator": "^11.0.4",
"commit-and-tag-version": "^11.2.2",
"@semantic-release/npm": "13.1.5",
"@semantic-release/release-notes-generator": "14.1.0",
"commit-and-tag-version": "12.7.1",
"prettier": "^3.7.4"
},
"overrides": {
"got": "11.8.6"
},
"scripts": {
"install": "cd client && npm i && cd ../sas && npm i",
"build-frontend": "cd client && npm run build",
+2
View File
@@ -0,0 +1,2 @@
ignore-scripts=true
save-exact=true
+2 -2
View File
@@ -1,8 +1,8 @@
{
"fromjs": [
{
"ADMIN": "DCDEFAULT",
"ADMIN": "AllUsers",
"DCPATH": "/tmp/dcdata"
}
]
}
}
+43 -37
View File
@@ -6,8 +6,8 @@
"": {
"name": "dc-sas",
"dependencies": {
"@sasjs/cli": "^4.15.0",
"@sasjs/core": "^4.62.0"
"@sasjs/cli": "4.16.2",
"@sasjs/core": "4.67.1"
}
},
"node_modules/@asamuzakjp/css-color": {
@@ -124,7 +124,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
},
@@ -147,7 +146,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
}
@@ -202,13 +200,13 @@
}
},
"node_modules/@sasjs/adapter": {
"version": "4.16.3",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.16.3.tgz",
"integrity": "sha512-xcoZT9qZhF6pXvXx4bHxbmauLdEHng8pSlTK4F6asUkHNR5uzeSvY6znA1yJqK+8FFtsVILyvMQyGyhWw6WsOA==",
"version": "4.16.7",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.16.7.tgz",
"integrity": "sha512-pOKAhOPijr663PFWGx+JEcWaMOGwICMA0w8LeXHPHQwvbHVGPCJKV5QroGqrjTO62HlhsHzow4Vb+DjIui1jgQ==",
"license": "ISC",
"dependencies": {
"@sasjs/utils": "3.5.6",
"axios": "^1.13.5",
"@sasjs/utils": "^3.5.6",
"axios": "1.16.0",
"axios-cookiejar-support": "5.0.5",
"form-data": "4.0.4",
"https": "1.0.0",
@@ -216,9 +214,9 @@
}
},
"node_modules/@sasjs/adapter/node_modules/@sasjs/utils": {
"version": "3.5.6",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.6.tgz",
"integrity": "sha512-jx8zWSOysDD66vTjA0BWiZ8bcFqmqh8F+56fUCgLmJhm89eDbKrGF3mDKMQx3UE7d2+gxp9xYhJCdaBWz0Dlxw==",
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.8.tgz",
"integrity": "sha512-rR2nCJG5AsuLj+nonpVO4PvA5OW8pUhDivY/25E4PCrQYLAmOaWQyIRne1gvSLL5ELzsOwRZWz6Zf6a02uNayA==",
"license": "ISC",
"dependencies": {
"@fast-csv/format": "4.3.5",
@@ -251,15 +249,15 @@
}
},
"node_modules/@sasjs/cli": {
"version": "4.15.0",
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.15.0.tgz",
"integrity": "sha512-lVKzm8+4b9VSqbchfLnzyNm53cKDZfqSM8KU7izD/JDBsuATSZtjLo61iNenZaPg9d3WXglb1jf2ASbVKbXxUQ==",
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.16.2.tgz",
"integrity": "sha512-hIyIK8reud8zS6A40R4kgE7Uh0X2Ppaqn3jWt5JuNoZLqfooVBv/2kuqJX+CNkOW5QAaGhoPHCvj99Ujvk4ExQ==",
"license": "ISC",
"dependencies": {
"@sasjs/adapter": "4.16.3",
"@sasjs/core": "4.62.0",
"@sasjs/adapter": "4.16.7",
"@sasjs/core": "4.64.1",
"@sasjs/lint": "2.4.3",
"@sasjs/utils": "3.5.6",
"@sasjs/utils": "3.5.8",
"adm-zip": "0.5.10",
"chalk": "4.1.2",
"dotenv": "16.0.3",
@@ -281,10 +279,16 @@
"sasjs": "build/index.js"
}
},
"node_modules/@sasjs/cli/node_modules/@sasjs/core": {
"version": "4.64.1",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.64.1.tgz",
"integrity": "sha512-gdVzSM3+FYvd9XZ26ftLv6yDLndA6L/14nQGLUqjfL/jTPwuhJiojrkaLBAsPDlnRbHSMZSqTF94cKLvS09NBg==",
"license": "MIT"
},
"node_modules/@sasjs/cli/node_modules/@sasjs/utils": {
"version": "3.5.6",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.6.tgz",
"integrity": "sha512-jx8zWSOysDD66vTjA0BWiZ8bcFqmqh8F+56fUCgLmJhm89eDbKrGF3mDKMQx3UE7d2+gxp9xYhJCdaBWz0Dlxw==",
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.8.tgz",
"integrity": "sha512-rR2nCJG5AsuLj+nonpVO4PvA5OW8pUhDivY/25E4PCrQYLAmOaWQyIRne1gvSLL5ELzsOwRZWz6Zf6a02uNayA==",
"license": "ISC",
"dependencies": {
"@fast-csv/format": "4.3.5",
@@ -317,9 +321,9 @@
}
},
"node_modules/@sasjs/core": {
"version": "4.62.0",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.62.0.tgz",
"integrity": "sha512-xMWeZbxlvuCP0B9fnSTgSFbSiA0hiKDpTua8wb0ghMUOl+dnh/XF+BYgrHhWhPL9j0+k5d8mJejLmf/l/txpzg==",
"version": "4.67.1",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.67.1.tgz",
"integrity": "sha512-yb4xW8JxsWWY3ZTN4yj/mP8ZasPIHSQVjHESLui3xS0HNatBw96H9ZYGJO3LcrkDx+X5xJz45f6sdHAJYxVeSA==",
"license": "MIT"
},
"node_modules/@sasjs/lint": {
@@ -462,14 +466,14 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.11",
"follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
"proxy-from-env": "^2.1.0"
}
},
"node_modules/axios-cookiejar-support": {
@@ -1013,9 +1017,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
"funding": [
{
"type": "individual",
@@ -1845,10 +1849,13 @@
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/psl": {
"version": "1.15.0",
@@ -2168,7 +2175,6 @@
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
+2 -2
View File
@@ -28,7 +28,7 @@
},
"private": true,
"dependencies": {
"@sasjs/cli": "^4.15.0",
"@sasjs/core": "^4.62.0"
"@sasjs/cli": "4.16.2",
"@sasjs/core": "4.67.1"
}
}
@@ -0,0 +1,52 @@
/**
@file
@brief migration script to move from v7.0 to v7.6 of data controller
OPTIONAL CHANGE - upload additional data as placeholders for modifying the
default email message
**/
%let dclib=YOURDCLIB;
libname &dclib "/YOUR/DATACONTROLLER/LIBRARY/PATH";
proc sql;
insert into &dclib..mpe_config set
tx_from=%sysfunc(datetime())
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="SUBMITTED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been proposed by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'Reason provided: '
!!'%superq(SUBMITTED_TXT)'
!!'0A'x!!'This is an automated email by Data Controller for SAS. For '
!!'documentation, please visit https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after submitting a change';
insert into &dclib..mpe_config set
tx_from=%sysfunc(datetime())
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="APPROVED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been approved by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'This is an automated email by Data'
!!' Controller for SAS. For documentation, please visit '
!!'https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after approving a change';
insert into &dclib..mpe_config set
tx_from=%sysfunc(datetime())
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="REJECTED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been rejected by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'Reason provided: '
!!'%superq(REVIEW_REASON_TXT)'
!!'0A'x!!'This is an automated email by Data Controller for SAS. For '
!!'documentation, please visit https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after rejecting a change';
+46 -5
View File
@@ -127,6 +127,11 @@ run;
filename __out email (&emails)
subject="Table &alert_lib..&alert_ds has been &alert_event";
data work.alertmessage;
set &mpelib..mpe_config;
where &dc_dttmtfmt. lt tx_to;
where also var_scope='DC_EMAIL' and var_name="&alert_event._TEMPLATE";
run;
%local SUBMITTED_TXT;
%if &alert_event=SUBMITTED %then %do;
data _null_;
@@ -136,30 +141,54 @@ filename __out email (&emails)
run;
data _null_;
File __out lrecl=32000;
length txt $2048;
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
put 'Dear user,';
put ' ';
put "Please be advised that a change to table &alert_lib..&alert_ds has "
"been proposed by &from_user on the '&syshostname' SAS server.";
"been proposed by &from_user on the &syshostname SAS server.";
put " ";
length txt $2048;
txt=symget('SUBMITTED_TXT');
put "Reason provided: " txt;
put " ";
put "This is an automated email by Data Controller for SAS. For "
"documentation, please visit https://docs.datacontroller.io";
%end;
%else %do;
/* take template from config table */
set work.alertmessage;
cnt=countw(var_value,'0A'x);
do i=1 to cnt;
txt=resolve(scan(var_value,i,'0A'x));
put txt /;
end;
%end;
run;
%end;
%else %if &alert_event=APPROVED %then %do;
/* there is no approval message */
data _null_;
File __out lrecl=32000;
length txt $2048;
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
/* fallback message */
put 'Dear user,';
put ' ';
put "Please be advised that a change to table &alert_lib..&alert_ds has "
"been approved by &from_user on the '&syshostname' SAS server.";
"been approved by &from_user on the &syshostname SAS server.";
put " ";
put "This is an automated email by Data Controller for SAS. For "
"documentation, please visit https://docs.datacontroller.io";
%end;
%else %do;
/* take template from config table */
set work.alertmessage;
cnt=countw(var_value,'0A'x);
do i=1 to cnt;
txt=resolve(scan(var_value,i,'0A'x));
put txt /;
end;
%end;
run;
%end;
%else %if &alert_event=REJECTED %then %do;
@@ -170,17 +199,29 @@ filename __out email (&emails)
run;
data _null_;
File __out lrecl=32000;
length txt $2048;
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
/* fallback message */
put 'Dear user,';
put ' ';
put "Please be advised that a change to table &alert_lib..&alert_ds has "
"been rejected by &from_user on the '&syshostname' SAS server.";
"been rejected by &from_user on the &syshostname SAS server.";
put " ";
length txt $2048;
txt=symget('REVIEW_REASON_TXT');
put "Reason provided: " txt;
put " ";
put "This is an automated email by Data Controller for SAS. For "
"documentation, please visit https://docs.datacontroller.io";
%end;
%else %do;
/* take template from config table */
set work.alertmessage;
cnt=countw(var_value,'0A'x);
do i=1 to cnt;
txt=resolve(scan(var_value,i,'0A'x));
put txt /;
end;
%end;
run;
%end;
+36
View File
@@ -0,0 +1,36 @@
/**
@file
@brief Returns the path to the settings file
@details The settings file location differs by platform:
@li SASJS - `<apploc>/services/public/settings.sas`
@li SASMETA - `<apploc>/services/public/Data_Controller_Settings`
@li SASVIYA - `<apploc>/services/settings.sas`
Usage:
%let settingspath=%mpe_getpath2settings();
%put &=settingspath;
<h4> SAS Macros </h4>
@li mf_getapploc.sas
@li mf_getplatform.sas
**/
%macro mpe_getpath2settings();
%local root platform;
%let root=%mf_getapploc();
%let platform=%mf_getplatform();
%if &platform=SASJS %then %do;
&root/services/public/settings
%end;
%else %if &platform=SASMETA %then %do;
&root/services/public/Data_Controller_Settings
%end;
%else %if &platform=SASVIYA %then %do;
&root/services/settings
%end;
%mend mpe_getpath2settings;
+74 -30
View File
@@ -201,6 +201,44 @@ insert into &lib..mpe_config set
,var_value=' '
,var_active=1
,var_desc='Activation Key';
insert into &lib..mpe_config set
tx_from=0
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="SUBMITTED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been proposed by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'Reason provided: '
!!'%superq(SUBMITTED_TXT)'
!!'0A'x!!'This is an automated email by Data Controller for SAS. For '
!!'documentation, please visit https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after submitting a change';
insert into &lib..mpe_config set
tx_from=0
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="APPROVED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been approved by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'This is an automated email by Data'
!!' Controller for SAS. For documentation, please visit '
!!'https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after approving a change';
insert into &lib..mpe_config set
tx_from=0
,tx_to='31DEC9999:23:59:59'dt
,var_scope="DC_EMAIL"
,var_name="REJECTED_TEMPLATE"
,var_value='Dear user,'!!'0A'x!!'Please be advised that a change to table'
!!' &alert_lib..&alert_ds has been rejected by &from_user on the '
!!'&syshostname SAS server.'!!'0A'x!!'Reason provided: '
!!'%superq(REVIEW_REASON_TXT)'
!!'0A'x!!'This is an automated email by Data Controller for SAS. For '
!!'documentation, please visit https://docs.datacontroller.io'
,var_active=1
,var_desc='Template email, sent after rejecting a change';
insert into &lib..mpe_datadictionary set
@@ -213,7 +251,6 @@ insert into &lib..mpe_datadictionary set
,DD_RESPONSIBLE="&sysuserid"
,DD_SENSITIVITY="Low"
,tx_to='31DEC5999:23:59:59'dt;
insert into &lib..mpe_datadictionary set
tx_from=0
,DD_TYPE='TABLE'
@@ -224,7 +261,6 @@ insert into &lib..mpe_datadictionary set
,DD_RESPONSIBLE="&sysuserid"
,DD_SENSITIVITY="Low"
,tx_to='31DEC5999:23:59:59'dt;
insert into &lib..mpe_datadictionary set
tx_from=0
,DD_TYPE='COLUMN'
@@ -235,7 +271,6 @@ insert into &lib..mpe_datadictionary set
,DD_RESPONSIBLE="&sysuserid"
,DD_SENSITIVITY="Low"
,tx_to='31DEC5999:23:59:59'dt;
insert into &lib..mpe_datadictionary set
tx_from=0
,DD_TYPE='DIRECTORY'
@@ -806,16 +841,16 @@ insert into &lib..mpe_selectbox set
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="HARDSELECT"
,selectbox_value="NOTNULL"
,selectbox_order=4
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="SOFTSELECT"
,selectbox_value="HARDSELECT"
,selectbox_order=5
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
@@ -824,26 +859,53 @@ insert into &lib..mpe_selectbox set
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="NOTNULL"
,selectbox_value="HARDSELECT_HOOK"
,selectbox_order=6
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="SOFTSELECT"
,selectbox_order=7
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_SECURITY"
,base_column="DSN"
,selectbox_value="SOME_DATASET"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="SOFTSELECT_HOOK"
,selectbox_order=8
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_ACTIVE"
,selectbox_value="1"
,selectbox_order=1
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_ACTIVE"
,selectbox_value="0"
,selectbox_order=2
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_SECURITY"
,base_column="DSN"
,selectbox_value="EXAMPLE"
,selectbox_order=2
,selectbox_value="*ALL*"
,selectbox_order=1
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
@@ -908,24 +970,6 @@ insert into &lib..mpe_selectbox set
,selectbox_value='AUDIT'
,selectbox_order=4
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="HARDSELECT_HOOK"
,selectbox_order=7
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
,select_lib="&lib"
,select_ds="MPE_VALIDATIONS"
,base_column="RULE_TYPE"
,selectbox_value="SOFTSELECT_HOOK"
,selectbox_order=7
,ver_to_dttm='31DEC5999:23:59:59'dt;
insert into &lib..mpe_selectbox set
selectbox_rk=%mf_increment(rk)
,ver_from_dttm=0
+6 -3
View File
@@ -143,17 +143,17 @@
},
{
"name": "vtest",
"appLoc": "/30.SASApps/app/vtest",
"appLoc": "/Users/&sysuserid/dctest",
"serverType": "SASVIYA",
"serverUrl": "https://sas.4gl.io",
"contextName": "Datacontroller compute context",
"contextName": "Compute Reusable",
"testConfig": {
"testSetUp": "sasjs/tests/testsetup.sas"
},
"serviceConfig": {
"initProgram": "sasjs/utils/serviceinitviya.sas",
"serviceFolders": [
"sasjs/targets/viya/services_viya/usernav",
"sasjs/targets/viya/services_viya/viya_users",
"sasjs/targets/viya/services_viya/admin",
"sasjs/targets/viya/services_viya/public"
]
@@ -166,6 +166,9 @@
],
"deployConfig": {
"deployServicePack": true
},
"streamConfig": {
"streamWeb": false
}
},
{
+45 -10
View File
@@ -9,10 +9,12 @@
<h4> SAS Macros </h4>
@li mf_getuser.sas
@li mf_nobs.sas
@li mp_ds2cards.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mp_ds2cards.sas
@li mp_ds2csv.sas
@li mp_streamfile.sas
@li mp_validatecol.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
@@ -21,23 +23,33 @@
**/
%global dclib islib newlib;
%mpeinit()
data _null_;
newlib=coalescec(symget('dclib'),"&mpelib");
%mp_validatecol(newlib,ISLIB,islib)
call symputx('islib',islib);
call symputx('newlib',upcase(newlib));
putlog (_all_)(=);
run;
%mp_abort(iftrue= (&islib ne 1)
,mac=&_program
,msg=%nrstr(&newlib is not a valid libref)
)
%let work=%sysfunc(pathname(work));
/* excel does not work in all envs */
%let mime=application/vnd.ms-excel;
%let dbms=EXCEL;
%let mime=application/csv;
%let dbms=CSV;
%let ext=csv;
%macro conditional_export(ds);
%if %mf_nobs(&ds)>0 %then %do;
PROC EXPORT DATA= &ds OUTFILE= "&work/&ds..&ext"
DBMS=&dbms REPLACE;
RUN;
ods package(ProdOutput) add file="&work/&ds..&ext" mimetype="&mime";
/* cannot use PROC EXPORT as we need to wrap all csv char values in quotes */
/* cannot use excel as it does not work consistently in all SAS envs */
%mp_ds2csv(&ds,outfile="&work/&newlib..&ds..csv",headerformat=NAME)
ods package(ProdOutput) add file="&work/&newlib..&ds..&ext" mimetype="&mime";
%end;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&_program
@@ -52,6 +64,7 @@ data MPE_ALERTS;
set &mpelib..MPE_ALERTS;
where &dc_dttmtfmt. le tx_to;
drop tx_: ;
if alert_lib="&mpelib" then alert_lib="&newlib";
run;
%conditional_export(MPE_ALERTS)
@@ -61,6 +74,7 @@ data MPE_COLUMN_LEVEL_SECURITY;
where &dc_dttmtfmt. le tx_to;
where also CLS_LIBREF ne "&mpelib";
drop tx_: ;
CLS_LIBREF="&newlib";
run;
%conditional_export(MPE_COLUMN_LEVEL_SECURITY)
@@ -68,6 +82,7 @@ data MPE_CONFIG;
set &mpelib..MPE_CONFIG;
where &dc_dttmtfmt. le tx_to;
drop tx_: ;
if var_name='DC_MACROS' then var_value=tranwrd(var_value,"&mpelib","&newlib");
run;
%conditional_export(MPE_CONFIG)
@@ -93,6 +108,7 @@ data MPE_EXCEL_CONFIG;
set &mpelib..MPE_EXCEL_CONFIG;
where &dc_dttmtfmt. le tx_to;
drop tx_: ;
if xl_libref="&mpelib" then xl_libref="&newlib";
run;
%conditional_export(MPE_EXCEL_CONFIG)
@@ -107,6 +123,7 @@ data MPE_ROW_LEVEL_SECURITY;
set &mpelib..MPE_ROW_LEVEL_SECURITY;
where &dc_dttmtfmt. le tx_to;
drop tx_: ;
if rls_libref="&mpelib" then rls_libref="&newlib";
run;
%conditional_export(MPE_ROW_LEVEL_SECURITY)
@@ -115,6 +132,7 @@ data MPE_SECURITY;
set &mpelib..MPE_SECURITY;
where &dc_dttmtfmt. le TX_TO;
drop tx_: ;
if libref="&mpelib" then libref="&newlib";
run;
%conditional_export(MPE_SECURITY)
@@ -142,6 +160,23 @@ data MPE_VALIDATIONS;
run;
%conditional_export(MPE_VALIDATIONS)
data MPE_XLMAP_INFO;
set &mpelib..MPE_XLMAP_INFO;
where &dc_dttmtfmt. le TX_TO;
drop tx_: ;
if XLMAP_TARGETLIBDS=:"&mpelib.." then
XLMAP_TARGETLIBDS=tranwrd(XLMAP_TARGETLIBDS,"&mpelib..","&newlib..");
run;
%conditional_export(MPE_XLMAP_INFO)
data MPE_XLMAP_RULES;
set &mpelib..MPE_XLMAP_RULES;
where &dc_dttmtfmt. le TX_TO;
drop tx_: ;
run;
%conditional_export(MPE_XLMAP_RULES)
/* finish up zip file */
ods package(ProdOutput) publish archive properties
(archive_name="DCBACKUP.zip" archive_path="&work");
+2 -1
View File
@@ -84,7 +84,8 @@ data work.reject;
REVIEW_STATUS_ID="REJECTED";
REVIEWED_BY_NM="&user";
REVIEWED_ON_DTTM=&now;
REVIEW_REASON_TXT=symget('STP_REASON');
/* sanitise message to prevent code injection */
REVIEW_REASON_TXT=compress(symget('STP_REASON'), '&%;');
run;
%mp_lockanytable(LOCK,
+4
View File
@@ -19,6 +19,7 @@
<h4> SAS Macros </h4>
@li bitemporal_dataloader.sas
@li dc_assignlib.sas
@li dc_cassave.sas
@li mf_existds.sas
@li mf_existvar.sas
@li mf_getattrn.sas
@@ -669,6 +670,9 @@ run;
ctl_ds=&mpelib..mpe_lockanytable
)
/* save table to disk (if viya + cas) */
%dc_cassave(&libds)
/* run post-approve hook */
%mpe_runhook(POST_APPROVE_HOOK)
+6 -4
View File
@@ -24,10 +24,10 @@
<h5> cols </h5>
Contains column level attributes.
@li NAME - column name
@li VARNUM - variable position. Source: https://core.sasjs.io/mp__getcols_8sas.html
@li LABEL - variable label. Source: https://core.sasjs.io/mp__getcols_8sas.html
@li FMTNAME - derived format name. Source: https://core.sasjs.io/mp__getcols_8sas.html
@li DDTYPE - derived dropdown type. Source: https://core.sasjs.io/mp__getcols_8sas.html
@li VARNUM - var position. https://core.sasjs.io/mp__getcols_8sas.html
@li LABEL - var label. https://core.sasjs.io/mp__getcols_8sas.html
@li FMTNAME - derived format. https://core.sasjs.io/mp__getcols_8sas.html
@li DDTYPE - derived dropdown. https://core.sasjs.io/mp__getcols_8sas.html
@li CLS_RULE - values include:
- EDIT - the column is editable
- READ - the column should be readonly
@@ -47,6 +47,7 @@
<h4> SAS Macros </h4>
@li dc_assignlib.sas
@li dc_casload.sas
@li dc_getgroupmembers.sas
@li mf_existvar.sas
@li mf_getattrn.sas
@@ -142,6 +143,7 @@ run;
%let libref=%upcase(%scan(&libds,1,.));
%let dsn=%upcase(%scan(&libds,2,.));
%dc_assignlib(WRITE,&libref)
%dc_casload(&libds)
/**
* First check user has access permission to edit the table
+2
View File
@@ -51,6 +51,8 @@
data _null_;
set work.sascontroltable;
call symputx('action',action);
/* sanitise message to prevent code injection */
message=compress(message, '&%;');
call symputx('message',message);
libds=upcase(libds);
call symputx('orig_libds',libds);
@@ -19,6 +19,11 @@
data work.staging_ds;
set work.staging_ds;
LIBREF=upcase(LIBREF);
if LIBREF in ('WORK','CASUSER','SASUSER') then do;
putlog "ERR" +(-1) "OR: invalid LIBREF - " LIBREF;
call symputx('errval',1);
call symputx('errmsg',"Invalid LIBREF: "!!LIBREF);
end;
DSN=upcase(DSN);
ACCESS_LEVEL=upcase(ACCESS_LEVEL);
if ACCESS_LEVEL not in ('EDIT','APPROVE','VIEW','SIGNOFF','AUDIT') then do;
@@ -39,6 +39,13 @@ data work.staging_ds;
audit_libds=upcase(audit_libds);
rk_underlying=upcase(rk_underlying);
/* do not accept certain librefs */
if LIBREF in ('WORK','CASUSER','SASUSER')
then do;
call symputx('errmsg',"Invalid LIBREF: "!!LIBREF);
call symputx('errflag',1);
end;
/* check for valid loadtype */
if LOADTYPE not in ('UPDATE','TXTEMPORAL','FORMAT_CAT','BITEMPORAL','REPLACE')
then do;
@@ -113,6 +113,16 @@ run;
and &dc_dttmtfmt. lt b.tx_to
and b.ACCESS_LEVEL in ('EDIT')
and b.SAS_GROUP in (select groupname from groups)
union
select distinct a.libref,a.dsn
from &mpelib..mpe_tables a
left join &mpelib..mpe_security b
on a.libref=b.libref
where &dc_dttmtfmt. lt a.tx_to
and &dc_dttmtfmt. lt b.tx_to
and b.ACCESS_LEVEL in ('EDIT')
and b.DSN='*ALL*'
and b.SAS_GROUP in (select groupname from groups)
order by 1;
%end;
%mend mstp_mpeditorstartup;
@@ -1,21 +1,24 @@
/**
@file
@brief testing gethistory service
@brief testing startupservice service
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mp_assertdsobs.sas
@li mp_testservice.sas
@li mpe_getpath2settings.sas
@li mx_append2pgm.sas
@li mx_testservice.sas
**/
%let _program=&appLoc/services/public/startupservice;
%mp_testservice(&_program,
viyacontext=&defaultcontext,
outlib=webout
%mx_testservice(&_program,
mdebug=&sasjs_mdebug,
outlib=webout,
viyacontext=&defaultcontext
)
data work.globvars;
set webout.globvars;
putlog (_all_)(=);
@@ -36,4 +39,92 @@ run;
desc=xlmaps table returned,
test=HASOBS,
outds=work.test_results
)
)
/* test mpe_security table */
%let testlib=%upcase(%mf_getuniquefileref());
/* remove the admin group */
filename append temp;
data _null_;
file append;
put '%let dc_admin_group=xxx;';
put " libname &testlib '%sysfunc(pathname(&dc_libref))';";
run;
%let settingspath=%mpe_getpath2settings();
%mx_append2pgm(&settingspath, inref=append)
/* insert single approved table in mpe_security */
data work.append;
set &DC_LIBREF..mpe_security;
LIBREF="&testlib";
DSN='MPE_X_TEST';
ACCESS_LEVEL='EDIT';
SAS_GROUP="&dc_admin_group";
tx_from=0;
tx_to='31DEC9999:23:59:59'dt;
output;
stop;
run;
proc append base=&dc_libref..mpe_security data=work.append;
run;
/* add to MPE_TABLES also */
data work.append2 ;
set &dc_libref..MPE_TABLES;
where libref="&dc_libref" and %sysfunc(datetime()) < tx_to;
libref="&testlib";
tx_from=0;
tx_to='31DEC9999:23:59:59'dt;
run;
proc sort data=work.append2 nodupkey; by libref dsn;run;
proc append base=&dc_libref..mpe_tables data=work.append2;run;
%mx_testservice(&_program,
mdebug=&sasjs_mdebug,
outlib=webout2,
viyacontext=&defaultcontext
)
data work.sasdatasets2;
set webout2.sasdatasets;
putlog (_all_)(=);
if libref="&testlib";
run;
%mp_assertdsobs(work.sasdatasets2,
desc=Only 1 table shown,
test=EQUALS 1
)
/* now try all tables */
data work.append3;
set &DC_LIBREF..mpe_security;
where libref="&testlib" and SAS_GROUP="&dc_admin_group";
DSN='*ALL*';
run;
proc append base=&dc_libref..mpe_security data=work.append3;
run;
%mx_testservice(&_program,
mdebug=&sasjs_mdebug,
outlib=webout3,
viyacontext=&defaultcontext
)
data work.sasdatasets3;
set webout3.sasdatasets;
putlog (_all_)(=);
if libref="&testlib";
run;
%mp_assertdsobs(work.sasdatasets3,
desc=Only 1 table shown,
test=ATLEAST 10
)
/* revert the admin group back */
filename appback temp;
data _null_;
file appback;
put '%let dc_admin_group=' "&dc_admin_group;";
run;
%mx_append2pgm(&settingspath, inref=appback)
+2
View File
@@ -39,6 +39,7 @@
<h4> SAS Macros </h4>
@li dc_assignlib.sas
@li dc_casload.sas
@li dc_createdataset.sas
@li dc_gettableid.sas
@li mf_existds.sas
@@ -144,6 +145,7 @@ run;
* assign the Library
*/
%dc_assignlib(READ,%scan(&LIBDS,1,.))
%dc_casload(&libds)
/* abort if looking for a format and the catalog doesn't exist */
%mp_abort(iftrue= (&fmt_ind=1 and %sysfunc(exist(&libds,CATALOG))=0)
@@ -0,0 +1,18 @@
/**
@file
@brief Loads a CAS table into memory
@details There are three versions of this macro, one per build
target. The interface is the same. This version is META and
is a no-op as CAS is not available on this platform.
@param [in] libds library.dataset of the CAS table to load
@param [in] mdebug= (0) Set to 1 to enable verbose logging
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_casload(libds, mdebug=0);
%mend dc_casload;
@@ -0,0 +1,18 @@
/**
@file
@brief Saves an in-memory CAS table back to persistent storage
@details There are three versions of this macro, one per build
target. The interface is the same. This version is META and
is a no-op as CAS is not available on this platform.
@param [in] libds library.dataset of the CAS table to save
@param [in] mdebug= (0) Set to 1 to enable verbose logging
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_cassave(libds, mdebug=0);
%mend dc_cassave;
@@ -0,0 +1,18 @@
/**
@file
@brief Loads a CAS table into memory
@details There are three versions of this macro, one per build
target. The interface is the same. This version is SERVER and
is a no-op as CAS is not available on this platform.
@param [in] libds library.dataset of the CAS table to load
@param [in] mdebug= (0) Set to 1 to enable verbose logging
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_casload(libds, mdebug=0);
%mend dc_casload;
@@ -0,0 +1,18 @@
/**
@file
@brief Saves an in-memory CAS table back to persistent storage
@details There are three versions of this macro, one per build
target. The interface is the same. This version is SERVER and
is a no-op as CAS is not available on this platform.
@param [in] libds library.dataset of the CAS table to save
@param [in] mdebug= (0) Set to 1 to enable verbose logging
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_cassave(libds, mdebug=0);
%mend dc_cassave;
@@ -0,0 +1,83 @@
/**
@file
@brief Loads a CAS table into memory
@details There are three versions of this macro, one per build
target. The interface is the same. The macro loads the source table
to memory (if not loaded) and promotes it.
Note that we cannot collect metadata from the APIs (like in
mv_castabload) because the server info may be inacessible to
the logged in user
Running SAS code under a system account (like proc util) DOES
work, so we just make the assumption that the source file and
library matches the libds.
@param [in] libds library.dataset of the CAS table to load
@param [in] mdebug= (0) Set to 1 to enable verbose logging
<h4> SAS Macros </h4>
@li mf_getengine.sas
@li mfv_getcaslib.sas
@li mp_abort.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_casload(libds, mdebug=0);
%local lib eng caslib ds _exists;
%mp_abort(
iftrue=(&syscc ne 0),
msg=%str(syscc=&syscc on macro entry)
)
%let lib=%scan(&libds,1,.);
%let eng=%mf_getengine(&lib);
%mp_abort(iftrue= (X&eng.X=XX)
,mac=&_program
,msg=%str(Library &lib is not assigned)
)
%if &eng ne CAS %then %return;
%let caslib=%mfv_getcaslib(lib=&lib);
%let ds=%scan(&libds,2,.);
%if &mdebug=1 %then %put _local_;
/* ---- existence check ------------------------------------------------- */
proc cas;
table.tableExists result=r /
caslib="&caslib"
name="&ds";
%if &mdebug=1 %then %do;
print r;
%end;
if r.exists > 0 then call symputx('_exists', '1', 'L');
else call symputx('_exists', '0', 'L');
quit;
/* ---- already loaded: skip -------------------------------------------- */
%if &_exists=1 %then %do;
%put NOTE: Table &caslib..&ds already loaded - skipping;
%return;
%end;
proc casutil;
load casdata="&ds"
incaslib="&caslib"
casout="&ds"
outcaslib="&caslib"
promote;
quit;
%mp_abort(
iftrue=(&syscc ne 0),
msg=%str(Load failed for &caslib..&ds)
)
%put NOTE: Table &caslib..&ds loaded and promoted;
%mend dc_casload;
@@ -0,0 +1,50 @@
/**
@file
@brief Saves an in-memory CAS table back to persistent storage
@details There are three versions of this macro, one per build
target. The interface is the same. This version is VIYA and
saves the named table back to its original source file.
Note that we cannot collect metadata from the APIs (like in
mv_castabsave) because the server info may be inacessible to
the logged in user
Running SAS code under a system account (like proc util) DOES
work, so we just make the assumption that the source file and
library matches the libds.
@param [in] libds library.dataset of the CAS table to save
@param [in] mdebug= (0) Set to 1 to enable verbose logging
<h4> SAS Macros </h4>
@li mf_getengine.sas
@li mfv_getcaslib.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data
Controller and may not be re-distributed or re-sold without the
express permission of 4GL Apps Ltd.
**/
%macro dc_cassave(libds, mdebug=0);
%local lib eng caslib ds;
%let lib=%scan(&libds,1,.);
%let eng=%mf_getengine(&lib);
%if &eng ne CAS %then %return;
%let caslib=%mfv_getcaslib(lib=&lib);
%let ds=%scan(&libds,2,.);
%if &mdebug=1 %then %put _local_;
/* ---- save to disk -------------------------------------------------- */
proc casutil;
save casdata="&ds"
incaslib="&caslib"
casout="&ds"
outcaslib="&caslib"
replace;
quit;
%put NOTE: Table &caslib..&ds saved;
%mend dc_cassave;
@@ -21,7 +21,7 @@ create table &outds as
,engine
,'' as libraryid length=17
from dictionary.libnames
where libname not in ('WORK','SASUSER');
where libname not in ('WORK','SASUSER','CASUSER');
insert into &syslast values ("&DC_LIBREF", "&DC_LIBNAME",'','V9');
%mend dc_getlibs;
@@ -124,6 +124,9 @@ data _null_;
put '/* This physical location is used for staging data and audit history */';
put '%let dc_staging_area=' "&dcpath/dc_staging;";
put ' ';
put 'cas dcsession sessopts=(caslib=casuser);';
put 'caslib _all_ assign;';
put ' ';
if &syssite in (70221618,70253615) then do;
put "libname dcdemo '&dcpath/dc_demo';";
end;
+4
View File
@@ -60,6 +60,10 @@ run;
%let testloc=%sysfunc(pathname(&DC_LIBREF))/fmt%mf_getuniquefileref();
%mf_mkdir(&testloc)
libname dctest "&testloc";
data dctest.mpe_x_test;
set &DC_LIBREF..mpe_x_test;
run;
/* test library with only one format catalog */
%mf_mkdir(&testloc/fmtonly)
libname fmtonly "&testloc/fmtonly";
-6
View File
@@ -12,12 +12,6 @@
options noquotelenmax ps=max;
cas dcsession sessopts=(caslib=casuser);
caslib _all_ assign;
libname casuser cas caslib=casuser;
/*caslib casmusic path='/opt/sas/viya/cascache/tracks' libref=casmusic ;*/
%let syscc=0;