Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bed21122ce | |||
| ea8cf71101 | |||
| f1a26e132e | |||
| 1db6984de3 | |||
| 636ff237dd | |||
| 02963ab6d5 | |||
| d40f61292a | |||
| 7d94cb2ae4 | |||
| bb80476767 | |||
| 1635bc9c45 | |||
| f031b4eb89 | |||
| 93d4ab65ac | |||
| ce921a032a | |||
| 322f904b4b | |||
| 982eeac58c | |||
| 0ab9717556 | |||
| 24a85de8e1 | |||
| 65f0b979a4 | |||
| 947f34a0ad | |||
| 0f60fd7181 | |||
| 251062e42e | |||
| 05a328976e | |||
| 503cb08b2f | |||
| f71be20476 | |||
| e6397cecc1 | |||
| 80ce80ece4 | |||
| 9546fcd631 | |||
| b79aaf4327 | |||
| 76f9198f73 | |||
| d60029deae | |||
| d26f7d2511 | |||
| 33efe09b50 | |||
| e0aef9bf00 | |||
| 02d1a2e0b1 | |||
| 4e3154e929 | |||
| 32c0713256 | |||
| defe15bcec | |||
| 6f8e471f16 | |||
| dc35abfd85 | |||
| 04a8c5d52a | |||
| 2cb370053d | |||
| 1707f3802a | |||
| c87ba660ca | |||
| ef8a2dbc38 | |||
| 40d04a53c4 | |||
| d5ebb01ce3 | |||
| ec66631a33 | |||
| d66eb5dfc2 | |||
| 731b589ed8 | |||
| fe92d5fc36 | |||
| a335b400f1 | |||
| f63e507ddf | |||
| 991cc0567d | |||
| 52d58036a4 | |||
| 26bff85792 | |||
| 2ccf0d1100 | |||
| 3be33186bc | |||
| 1a7f950ae2 | |||
| 8924dc8ab1 | |||
| 0b0db1c543 | |||
| 80039f4876 | |||
| 326c26fddf |
+19
-15
@@ -3,7 +3,7 @@ run-name: Running Lint Check and Licence checker on Pull Request
|
|||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: '24.5.0'
|
NODE_VERSION: '24.15.0'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build-and-ng-test:
|
Build-and-ng-test:
|
||||||
@@ -22,30 +22,33 @@ jobs:
|
|||||||
apt install -y ./google-chrome*.deb
|
apt install -y ./google-chrome*.deb
|
||||||
|
|
||||||
- name: Write .npmrc file
|
- name: Write .npmrc file
|
||||||
run: echo "$NPMRC" > client/.npmrc
|
run: echo "$NPMRC" >> client/.npmrc
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
NPMRC: ${{ secrets.NPMRC}}
|
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
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
cd client
|
cd client
|
||||||
# Decrypt and Install sheet
|
# 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 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
|
- name: Licence checker
|
||||||
run: |
|
run: |
|
||||||
cd client
|
cd client
|
||||||
@@ -139,6 +142,7 @@ jobs:
|
|||||||
- name: Zip Cypress videos
|
- name: Zip Cypress videos
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
|
mkdir -p ./client/cypress/videos
|
||||||
zip -r cypress-videos ./client/cypress/videos
|
zip -r cypress-videos ./client/cypress/videos
|
||||||
|
|
||||||
- name: Add cypress videos artifacts
|
- name: Add cypress videos artifacts
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ run-name: Running Lighthouse Performance and Accessibility Checks on Pull Reques
|
|||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: '24.5.0'
|
NODE_VERSION: '24.15.0'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lighthouse:
|
lighthouse:
|
||||||
@@ -48,7 +48,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd client
|
cd client
|
||||||
# Decrypt and Install sheet
|
# 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 ci
|
||||||
npm install -g replace-in-files-cli
|
npm install -g replace-in-files-cli
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ jobs:
|
|||||||
- name: Zip Cypress videos
|
- name: Zip Cypress videos
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
|
mkdir -p ./client/cypress/videos
|
||||||
zip -r cypress-videos ./client/cypress/videos
|
zip -r cypress-videos ./client/cypress/videos
|
||||||
|
|
||||||
- name: Add cypress videos artifacts
|
- name: Add cypress videos artifacts
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
legacy-peer-deps=true
|
legacy-peer-deps=true
|
||||||
|
ignore-scripts=true
|
||||||
|
save-exact=true
|
||||||
|
fund=false
|
||||||
@@ -1,3 +1,100 @@
|
|||||||
|
## [7.8.1](https://git.datacontroller.io/dc/dc/compare/v7.8.0...v7.8.1) (2026-05-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **sasjs:** enable runAsTask ([f1a26e1](https://git.datacontroller.io/dc/dc/commit/f1a26e132eba7fa2ac64754940b52ea46c6619b3))
|
||||||
|
|
||||||
|
# [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)
|
## [7.4.1](https://git.datacontroller.io/dc/dc/compare/v7.4.0...v7.4.1) (2026-03-12)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -62,7 +62,8 @@
|
|||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "src/images",
|
"input": "src/images",
|
||||||
"output": "images"
|
"output": "images",
|
||||||
|
"ignore": ["spinner.svg", "caret.svg"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": ["src/styles.scss"],
|
"styles": ["src/styles.scss"],
|
||||||
|
|||||||
+18
-17
@@ -1,13 +1,13 @@
|
|||||||
import { defineConfig } from "cypress";
|
import { defineConfig } from 'cypress'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
reporter: "mochawesome",
|
reporter: 'mochawesome',
|
||||||
|
|
||||||
reporterOptions: {
|
reporterOptions: {
|
||||||
reportDir: "cypress/results",
|
reportDir: 'cypress/results',
|
||||||
overwrite: false,
|
overwrite: false,
|
||||||
html: true,
|
html: true,
|
||||||
json: false,
|
json: false
|
||||||
},
|
},
|
||||||
viewportHeight: 900,
|
viewportHeight: 900,
|
||||||
viewportWidth: 1600,
|
viewportWidth: 1600,
|
||||||
@@ -16,24 +16,25 @@ export default defineConfig({
|
|||||||
defaultCommandTimeout: 30000,
|
defaultCommandTimeout: 30000,
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
hosturl: "http://localhost:4200",
|
hosturl: 'http://localhost:4200',
|
||||||
appLocation: "",
|
appLocation: '',
|
||||||
site_id_SAS9: "70221618",
|
site_id_SAS9: '70221618',
|
||||||
site_id_SASVIYA: "70253615",
|
site_id_SASVIYA: '70253615',
|
||||||
site_id_SASJS: "123",
|
site_id_SASJS: '123',
|
||||||
serverType: "SASJS",
|
serverType: 'SASJS',
|
||||||
libraryToOpenIncludes_SASVIYA: "viya",
|
libraryToOpenIncludes_SASVIYA: 'viya',
|
||||||
libraryToOpenIncludes_SAS9: "dc",
|
libraryToOpenIncludes_SAS9: 'dc',
|
||||||
libraryToOpenIncludes_SASJS: "dc",
|
libraryToOpenIncludes_SASJS: 'dc',
|
||||||
debug: false,
|
debug: false,
|
||||||
screenshotOnRunFailure: false,
|
screenshotOnRunFailure: false,
|
||||||
longerCommandTimeout: 50000,
|
longerCommandTimeout: 50000,
|
||||||
testLicenceUserLimits: false,
|
testLicenceUserLimits: false
|
||||||
},
|
},
|
||||||
|
|
||||||
e2e: {
|
e2e: {
|
||||||
|
video: true,
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
// implement node event listeners here
|
// implement node event listeners here
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const check = (cwd) => {
|
|||||||
onlyAllow:
|
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;',
|
'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:
|
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) => {
|
(error, json) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
Generated
+5343
-6471
File diff suppressed because it is too large
Load Diff
+22
-19
@@ -23,7 +23,7 @@
|
|||||||
"watch": "ng test watch=true",
|
"watch": "ng test watch=true",
|
||||||
"pree2e": "webdriver-manager update",
|
"pree2e": "webdriver-manager update",
|
||||||
"e2e": "protractor protractor.config.js",
|
"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",
|
"add-githook": "[ -d ../.git ] && git config core.hooksPath ./.git-hooks || true",
|
||||||
"cypress": "cypress open",
|
"cypress": "cypress open",
|
||||||
"cy:run": "cypress run",
|
"cy:run": "cypress run",
|
||||||
@@ -37,21 +37,21 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.2.18",
|
"@angular/animations": "^19.2.20",
|
||||||
"@angular/cdk": "^19.2.19",
|
"@angular/cdk": "^19.2.19",
|
||||||
"@angular/common": "^19.2.18",
|
"@angular/common": "^19.2.20",
|
||||||
"@angular/compiler": "^19.2.18",
|
"@angular/compiler": "^19.2.20",
|
||||||
"@angular/core": "^19.2.18",
|
"@angular/core": "^19.2.20",
|
||||||
"@angular/forms": "^19.2.18",
|
"@angular/forms": "^19.2.20",
|
||||||
"@angular/platform-browser": "^19.2.18",
|
"@angular/platform-browser": "^19.2.20",
|
||||||
"@angular/platform-browser-dynamic": "^19.2.18",
|
"@angular/platform-browser-dynamic": "^19.2.20",
|
||||||
"@angular/router": "^19.2.18",
|
"@angular/router": "^19.2.20",
|
||||||
"@cds/core": "^6.15.1",
|
"@cds/core": "^6.15.1",
|
||||||
"@clr/angular": "file:libraries/clr-angular-17.9.0.tgz",
|
"@clr/angular": "file:libraries/clr-angular-17.9.0.tgz",
|
||||||
"@clr/icons": "^13.0.2",
|
"@clr/icons": "^13.0.2",
|
||||||
"@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
|
"@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
|
||||||
"@handsontable/angular-wrapper": "16.0.1",
|
"@handsontable/angular-wrapper": "16.0.1",
|
||||||
"@sasjs/adapter": "^4.16.3",
|
"@sasjs/adapter": "^4.17.0",
|
||||||
"@sasjs/utils": "^3.5.3",
|
"@sasjs/utils": "^3.5.3",
|
||||||
"@sheet/crypto": "file:libraries/sheet-crypto.tgz",
|
"@sheet/crypto": "file:libraries/sheet-crypto.tgz",
|
||||||
"@types/d3-graphviz": "^2.6.7",
|
"@types/d3-graphviz": "^2.6.7",
|
||||||
@@ -86,18 +86,18 @@
|
|||||||
"zone.js": "~0.15.1"
|
"zone.js": "~0.15.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^19.2.19",
|
"@angular-devkit/build-angular": "^19.2.24",
|
||||||
"@angular-eslint/builder": "19.8.1",
|
"@angular-eslint/builder": "19.8.1",
|
||||||
"@angular-eslint/eslint-plugin": "19.8.1",
|
"@angular-eslint/eslint-plugin": "19.8.1",
|
||||||
"@angular-eslint/eslint-plugin-template": "19.8.1",
|
"@angular-eslint/eslint-plugin-template": "19.8.1",
|
||||||
"@angular-eslint/schematics": "19.8.1",
|
"@angular-eslint/schematics": "19.8.1",
|
||||||
"@angular-eslint/template-parser": "19.8.1",
|
"@angular-eslint/template-parser": "19.8.1",
|
||||||
"@angular/cli": "^19.2.19",
|
"@angular/cli": "^19.2.24",
|
||||||
"@angular/compiler-cli": "^19.2.18",
|
"@angular/compiler-cli": "^19.2.20",
|
||||||
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
||||||
"@compodoc/compodoc": "^1.1.21",
|
"@compodoc/compodoc": "^1.2.1",
|
||||||
"@cypress/webpack-preprocessor": "^5.17.1",
|
"@cypress/webpack-preprocessor": "^5.17.1",
|
||||||
"@lhci/cli": "^0.12.0",
|
"@lhci/cli": "^0.15.1",
|
||||||
"@types/core-js": "^2.5.5",
|
"@types/core-js": "^2.5.5",
|
||||||
"@types/crypto-js": "^4.2.1",
|
"@types/crypto-js": "^4.2.1",
|
||||||
"@types/es6-shim": "^0.31.39",
|
"@types/es6-shim": "^0.31.39",
|
||||||
@@ -105,15 +105,15 @@
|
|||||||
"@types/lodash-es": "^4.17.3",
|
"@types/lodash-es": "^4.17.3",
|
||||||
"@types/marked": "^4.3.0",
|
"@types/marked": "^4.3.0",
|
||||||
"@types/node": "12.20.50",
|
"@types/node": "12.20.50",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
"@typescript-eslint/eslint-plugin": "8.31.1",
|
||||||
"@typescript-eslint/parser": "^5.29.0",
|
"@typescript-eslint/parser": "8.31.1",
|
||||||
"core-js": "^2.5.4",
|
"core-js": "^2.5.4",
|
||||||
"cypress": "12.17.1",
|
"cypress": "^15.14.2",
|
||||||
"cypress-file-upload": "^5.0.8",
|
"cypress-file-upload": "^5.0.8",
|
||||||
"cypress-plugin-tab": "^1.0.5",
|
"cypress-plugin-tab": "^1.0.5",
|
||||||
"cypress-real-events": "^1.8.1",
|
"cypress-real-events": "^1.8.1",
|
||||||
"es6-shim": "^0.35.5",
|
"es6-shim": "^0.35.5",
|
||||||
"eslint": "^8.33.0",
|
"eslint": "8.57.1",
|
||||||
"git-describe": "^4.0.4",
|
"git-describe": "^4.0.4",
|
||||||
"jasmine-core": "~5.1.2",
|
"jasmine-core": "~5.1.2",
|
||||||
"karma": "~6.4.3",
|
"karma": "~6.4.3",
|
||||||
@@ -132,5 +132,8 @@
|
|||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
"wait-on": "^6.0.1",
|
"wait-on": "^6.0.1",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"ajv": "8.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)`)
|
||||||
|
}
|
||||||
@@ -209,6 +209,7 @@ export class AppComponent {
|
|||||||
dcPath: getAppAttribute('dcPath') || '',
|
dcPath: getAppAttribute('dcPath') || '',
|
||||||
debug: getAppAttribute('debug') === 'true' || false,
|
debug: getAppAttribute('debug') === 'true' || false,
|
||||||
useComputeApi: this.parseComputeApi(getAppAttribute('useComputeApi')),
|
useComputeApi: this.parseComputeApi(getAppAttribute('useComputeApi')),
|
||||||
|
runAsTask: getAppAttribute('runAsTask') === 'true' || false,
|
||||||
contextName: getAppAttribute('contextName') || '',
|
contextName: getAppAttribute('contextName') || '',
|
||||||
hotLicenceKey: getAppAttribute('hotLicenceKey') || ''
|
hotLicenceKey: getAppAttribute('hotLicenceKey') || ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ export class AutomaticComponent implements OnInit {
|
|||||||
let contextname = `&_contextname=${params.contextName}`
|
let contextname = `&_contextname=${params.contextName}`
|
||||||
let admin = `&admin=${params.admin}`
|
let admin = `&admin=${params.admin}`
|
||||||
let dcPath = `&dcpath=${params.dcPath}`
|
let dcPath = `&dcpath=${params.dcPath}`
|
||||||
let debug = `&_debug=131`
|
let debug = this.sasService.getDebugUrlParam()
|
||||||
|
|
||||||
let programUrl =
|
let programUrl =
|
||||||
serverUrl +
|
serverUrl +
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ export class ManualComponent implements OnInit {
|
|||||||
this.selectedAdminGroup +
|
this.selectedAdminGroup +
|
||||||
'&DCPATH=' +
|
'&DCPATH=' +
|
||||||
this.dcPath +
|
this.dcPath +
|
||||||
'&_debug=131'
|
this.sasService.getDebugUrlParam()
|
||||||
|
|
||||||
window.open(url, '_blank')
|
window.open(url, '_blank')
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import Handsontable from 'handsontable'
|
import Handsontable from 'handsontable'
|
||||||
import { Subject, Subscription } from 'rxjs'
|
import { Subject, Subscription } from 'rxjs'
|
||||||
|
import { sanitiseForSas } from '../shared/utils/sanitise'
|
||||||
import { SasStoreService } from '../services/sas-store.service'
|
import { SasStoreService } from '../services/sas-store.service'
|
||||||
|
|
||||||
type AOA = any[][]
|
type AOA = any[][]
|
||||||
@@ -1669,7 +1670,7 @@ export class EditorComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.submit = true
|
this.submit = true
|
||||||
const updateParams: any = {}
|
const updateParams: any = {}
|
||||||
updateParams.ACTION = 'LOAD'
|
updateParams.ACTION = 'LOAD'
|
||||||
this.message = this.message.replace(/\n/g, '. ')
|
this.message = sanitiseForSas(this.message.replace(/\n/g, '. '))
|
||||||
updateParams.MESSAGE = this.message
|
updateParams.MESSAGE = this.message
|
||||||
// updateParams.APPROVER = this.approver;
|
// updateParams.APPROVER = this.approver;
|
||||||
updateParams.LIBDS = this.libds
|
updateParams.LIBDS = this.libds
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ActivatedRoute } from '@angular/router'
|
import { ActivatedRoute } from '@angular/router'
|
||||||
|
import { sanitiseForSas } from '../../shared/utils/sanitise'
|
||||||
import { SasStoreService } from '../../services/sas-store.service'
|
import { SasStoreService } from '../../services/sas-store.service'
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
@@ -136,7 +137,7 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
public async rejecting() {
|
public async rejecting() {
|
||||||
this.rejectLoading = true
|
this.rejectLoading = true
|
||||||
this.submitReason = this.submitReason.replace(/\n/g, '. ')
|
this.submitReason = sanitiseForSas(this.submitReason.replace(/\n/g, '. '))
|
||||||
|
|
||||||
let rejParams = {
|
let rejParams = {
|
||||||
STP_ACTION: 'REJECT_TABLE',
|
STP_ACTION: 'REJECT_TABLE',
|
||||||
|
|||||||
@@ -641,6 +641,23 @@ export class SasService {
|
|||||||
this.sasjsAdapter.setDebugState(state)
|
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() {
|
public getSasjsInstance() {
|
||||||
return this.sasjsAdapter
|
return this.sasjsAdapter
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,10 +284,18 @@ export class DcValidator {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (source.length > 0) {
|
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].source = source
|
||||||
this.rules[i].type = 'autocomplete'
|
|
||||||
this.rules[i].editor = 'autocomplete.custom'
|
this.rules[i].editor = 'autocomplete.custom'
|
||||||
|
this.rules[i].renderer = 'autocomplete'
|
||||||
this.rules[i].filter = false
|
this.rules[i].filter = false
|
||||||
|
|
||||||
|
if (this.rules[i].sasType !== 'num') {
|
||||||
|
this.rules[i].type = 'autocomplete'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasDqRules(ruleColName, ['SOFTSELECT'])) {
|
if (this.hasDqRules(ruleColName, ['SOFTSELECT'])) {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ export interface DcColumnSettings {
|
|||||||
valid?: boolean
|
valid?: boolean
|
||||||
desc?: string
|
desc?: string
|
||||||
clsRule?: 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 {}
|
export interface DcValidation extends HotColumnSettings, DcColumnSettings {}
|
||||||
|
|||||||
@@ -38,11 +38,52 @@ describe('DC Validator - merge spec rules', () => {
|
|||||||
data: 'test_col',
|
data: 'test_col',
|
||||||
desc: 'test_desc',
|
desc: 'test_desc',
|
||||||
clsRule: 'cls_rule',
|
clsRule: 'cls_rule',
|
||||||
length: 8
|
length: 8,
|
||||||
|
sasType: 'test_type'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
expect(mergeColsRules(cols, rules, $dataFormats)).toEqual(expected)
|
expect(mergeColsRules(cols, rules, $dataFormats)).toEqual(expected)
|
||||||
expect(cols[0].TYPE).toEqual('test_type')
|
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 && col.DESC) rule.desc = col.DESC
|
||||||
if (rule && colFormats.length) rule.length = parseInt(colFormats.length)
|
if (rule && colFormats.length) rule.length = parseInt(colFormats.length)
|
||||||
if (rule && col.CLS_RULE) rule.clsRule = col.CLS_RULE
|
if (rule && col.CLS_RULE) rule.clsRule = col.CLS_RULE
|
||||||
|
if (rule && colFormats?.type) rule.sasType = colFormats.type
|
||||||
}
|
}
|
||||||
|
|
||||||
return rules
|
return rules
|
||||||
|
|||||||
@@ -80,15 +80,13 @@ export class SidebarComponent implements OnInit {
|
|||||||
public resizeStart() {
|
public resizeStart() {
|
||||||
this.resizing = true
|
this.resizing = true
|
||||||
|
|
||||||
let body = document.getElementsByTagName('body')[0]
|
document.body.classList.add('select-none')
|
||||||
body.style.cssText = 'user-select: none'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public resizeEnd() {
|
public resizeEnd() {
|
||||||
this.resizing = false
|
this.resizing = false
|
||||||
|
|
||||||
let body = document.getElementsByTagName('body')[0]
|
document.body.classList.remove('select-none')
|
||||||
body.style.cssText = ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('document:mousemove', ['$event'])
|
@HostListener('document:mousemove', ['$event'])
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Strips characters that could cause SAS macro injection (& % ;).
|
||||||
|
*/
|
||||||
|
export function sanitiseForSas(input: string): string {
|
||||||
|
return input.replace(/[%&;]/g, '')
|
||||||
|
}
|
||||||
@@ -236,14 +236,31 @@
|
|||||||
<div class="admin-action">
|
<div class="admin-action">
|
||||||
Download Configuration
|
Download Configuration
|
||||||
|
|
||||||
<input
|
<div class="libref-group">
|
||||||
type="text"
|
<clr-tooltip class="libref-tooltip">
|
||||||
class="clr-input libref-input"
|
<label clrTooltipTrigger class="libref-label">
|
||||||
maxlength="8"
|
Target DC Library
|
||||||
[ngModel]="dcLib"
|
<cds-icon shape="info-circle" size="16"></cds-icon>
|
||||||
(ngModelChange)="targetLibref = $event.toUpperCase()"
|
</label>
|
||||||
placeholder="Target Libref"
|
<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
|
<button
|
||||||
(click)="downloadConfiguration()"
|
(click)="downloadConfiguration()"
|
||||||
[disabled]="targetLibref !== dcLib && !isValidLibref(targetLibref)"
|
[disabled]="targetLibref !== dcLib && !isValidLibref(targetLibref)"
|
||||||
|
|||||||
@@ -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 {
|
.libref-input {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
margin: 0 8px;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -49,7 +49,8 @@
|
|||||||
serverType="SASJS"
|
serverType="SASJS"
|
||||||
loginMechanism="Redirected"
|
loginMechanism="Redirected"
|
||||||
debug="false"
|
debug="false"
|
||||||
useComputeApi="true"
|
useComputeApi="null"
|
||||||
|
runAsTask="true"
|
||||||
contextName="SAS Job Execution compute context"
|
contextName="SAS Job Execution compute context"
|
||||||
adminGroup="SASAdministrators"
|
adminGroup="SASAdministrators"
|
||||||
dcPath="/tmp/dc"
|
dcPath="/tmp/dc"
|
||||||
|
|||||||
+31
-14
@@ -9,9 +9,39 @@
|
|||||||
|
|
||||||
@import './colors.scss';
|
@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-face {
|
||||||
font-family: text-security-disc;
|
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
|
// 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-"] {
|
pre[class*="language-"] {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|||||||
Generated
+1890
-2359
File diff suppressed because it is too large
Load Diff
+8
-5
@@ -1,17 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "dcfrontend",
|
"name": "dcfrontend",
|
||||||
"version": "7.4.1",
|
"version": "7.8.1",
|
||||||
"description": "Data Controller",
|
"description": "Data Controller",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@saithodev/semantic-release-gitea": "^2.1.0",
|
"@saithodev/semantic-release-gitea": "^2.1.0",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@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/git": "^10.0.1",
|
||||||
"@semantic-release/npm": "11.0.0",
|
"@semantic-release/npm": "13.1.5",
|
||||||
"@semantic-release/release-notes-generator": "^11.0.4",
|
"@semantic-release/release-notes-generator": "14.1.0",
|
||||||
"commit-and-tag-version": "^11.2.2",
|
"commit-and-tag-version": "12.7.1",
|
||||||
"prettier": "^3.7.4"
|
"prettier": "^3.7.4"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"got": "11.8.6"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install": "cd client && npm i && cd ../sas && npm i",
|
"install": "cd client && npm i && cd ../sas && npm i",
|
||||||
"build-frontend": "cd client && npm run build",
|
"build-frontend": "cd client && npm run build",
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ignore-scripts=true
|
||||||
|
save-exact=true
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"fromjs": [
|
"fromjs": [
|
||||||
{
|
{
|
||||||
"ADMIN": "DCDEFAULT",
|
"ADMIN": "AllUsers",
|
||||||
"DCPATH": "/tmp/dcdata"
|
"DCPATH": "/tmp/dcdata"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Generated
+43
-37
@@ -6,8 +6,8 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "dc-sas",
|
"name": "dc-sas",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/cli": "^4.15.0",
|
"@sasjs/cli": "4.16.2",
|
||||||
"@sasjs/core": "^4.62.0"
|
"@sasjs/core": "4.67.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@asamuzakjp/css-color": {
|
"node_modules/@asamuzakjp/css-color": {
|
||||||
@@ -124,7 +124,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
@@ -147,7 +146,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -202,13 +200,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/adapter": {
|
"node_modules/@sasjs/adapter": {
|
||||||
"version": "4.16.3",
|
"version": "4.16.7",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.16.3.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.16.7.tgz",
|
||||||
"integrity": "sha512-xcoZT9qZhF6pXvXx4bHxbmauLdEHng8pSlTK4F6asUkHNR5uzeSvY6znA1yJqK+8FFtsVILyvMQyGyhWw6WsOA==",
|
"integrity": "sha512-pOKAhOPijr663PFWGx+JEcWaMOGwICMA0w8LeXHPHQwvbHVGPCJKV5QroGqrjTO62HlhsHzow4Vb+DjIui1jgQ==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/utils": "3.5.6",
|
"@sasjs/utils": "^3.5.6",
|
||||||
"axios": "^1.13.5",
|
"axios": "1.16.0",
|
||||||
"axios-cookiejar-support": "5.0.5",
|
"axios-cookiejar-support": "5.0.5",
|
||||||
"form-data": "4.0.4",
|
"form-data": "4.0.4",
|
||||||
"https": "1.0.0",
|
"https": "1.0.0",
|
||||||
@@ -216,9 +214,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/adapter/node_modules/@sasjs/utils": {
|
"node_modules/@sasjs/adapter/node_modules/@sasjs/utils": {
|
||||||
"version": "3.5.6",
|
"version": "3.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.8.tgz",
|
||||||
"integrity": "sha512-jx8zWSOysDD66vTjA0BWiZ8bcFqmqh8F+56fUCgLmJhm89eDbKrGF3mDKMQx3UE7d2+gxp9xYhJCdaBWz0Dlxw==",
|
"integrity": "sha512-rR2nCJG5AsuLj+nonpVO4PvA5OW8pUhDivY/25E4PCrQYLAmOaWQyIRne1gvSLL5ELzsOwRZWz6Zf6a02uNayA==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fast-csv/format": "4.3.5",
|
"@fast-csv/format": "4.3.5",
|
||||||
@@ -251,15 +249,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/cli": {
|
"node_modules/@sasjs/cli": {
|
||||||
"version": "4.15.0",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.16.2.tgz",
|
||||||
"integrity": "sha512-lVKzm8+4b9VSqbchfLnzyNm53cKDZfqSM8KU7izD/JDBsuATSZtjLo61iNenZaPg9d3WXglb1jf2ASbVKbXxUQ==",
|
"integrity": "sha512-hIyIK8reud8zS6A40R4kgE7Uh0X2Ppaqn3jWt5JuNoZLqfooVBv/2kuqJX+CNkOW5QAaGhoPHCvj99Ujvk4ExQ==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/adapter": "4.16.3",
|
"@sasjs/adapter": "4.16.7",
|
||||||
"@sasjs/core": "4.62.0",
|
"@sasjs/core": "4.64.1",
|
||||||
"@sasjs/lint": "2.4.3",
|
"@sasjs/lint": "2.4.3",
|
||||||
"@sasjs/utils": "3.5.6",
|
"@sasjs/utils": "3.5.8",
|
||||||
"adm-zip": "0.5.10",
|
"adm-zip": "0.5.10",
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"dotenv": "16.0.3",
|
"dotenv": "16.0.3",
|
||||||
@@ -281,10 +279,16 @@
|
|||||||
"sasjs": "build/index.js"
|
"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": {
|
"node_modules/@sasjs/cli/node_modules/@sasjs/utils": {
|
||||||
"version": "3.5.6",
|
"version": "3.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.8.tgz",
|
||||||
"integrity": "sha512-jx8zWSOysDD66vTjA0BWiZ8bcFqmqh8F+56fUCgLmJhm89eDbKrGF3mDKMQx3UE7d2+gxp9xYhJCdaBWz0Dlxw==",
|
"integrity": "sha512-rR2nCJG5AsuLj+nonpVO4PvA5OW8pUhDivY/25E4PCrQYLAmOaWQyIRne1gvSLL5ELzsOwRZWz6Zf6a02uNayA==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fast-csv/format": "4.3.5",
|
"@fast-csv/format": "4.3.5",
|
||||||
@@ -317,9 +321,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/core": {
|
"node_modules/@sasjs/core": {
|
||||||
"version": "4.62.0",
|
"version": "4.67.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.67.1.tgz",
|
||||||
"integrity": "sha512-xMWeZbxlvuCP0B9fnSTgSFbSiA0hiKDpTua8wb0ghMUOl+dnh/XF+BYgrHhWhPL9j0+k5d8mJejLmf/l/txpzg==",
|
"integrity": "sha512-yb4xW8JxsWWY3ZTN4yj/mP8ZasPIHSQVjHESLui3xS0HNatBw96H9ZYGJO3LcrkDx+X5xJz45f6sdHAJYxVeSA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/lint": {
|
"node_modules/@sasjs/lint": {
|
||||||
@@ -462,14 +466,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.13.5",
|
"version": "1.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
|
||||||
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
|
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.11",
|
"follow-redirects": "^1.16.0",
|
||||||
"form-data": "^4.0.5",
|
"form-data": "^4.0.5",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios-cookiejar-support": {
|
"node_modules/axios-cookiejar-support": {
|
||||||
@@ -1013,9 +1017,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.11",
|
"version": "1.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -1845,10 +1849,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/psl": {
|
"node_modules/psl": {
|
||||||
"version": "1.15.0",
|
"version": "1.15.0",
|
||||||
@@ -2168,7 +2175,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/cli": "^4.15.0",
|
"@sasjs/cli": "4.16.2",
|
||||||
"@sasjs/core": "^4.62.0"
|
"@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';
|
||||||
@@ -127,6 +127,11 @@ run;
|
|||||||
filename __out email (&emails)
|
filename __out email (&emails)
|
||||||
subject="Table &alert_lib..&alert_ds has been &alert_event";
|
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;
|
%local SUBMITTED_TXT;
|
||||||
%if &alert_event=SUBMITTED %then %do;
|
%if &alert_event=SUBMITTED %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -136,30 +141,54 @@ filename __out email (&emails)
|
|||||||
run;
|
run;
|
||||||
data _null_;
|
data _null_;
|
||||||
File __out lrecl=32000;
|
File __out lrecl=32000;
|
||||||
|
length txt $2048;
|
||||||
|
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
|
||||||
put 'Dear user,';
|
put 'Dear user,';
|
||||||
put ' ';
|
put ' ';
|
||||||
put "Please be advised that a change to table &alert_lib..&alert_ds has "
|
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 " ";
|
put " ";
|
||||||
length txt $2048;
|
|
||||||
txt=symget('SUBMITTED_TXT');
|
txt=symget('SUBMITTED_TXT');
|
||||||
put "Reason provided: " txt;
|
put "Reason provided: " txt;
|
||||||
put " ";
|
put " ";
|
||||||
put "This is an automated email by Data Controller for SAS. For "
|
put "This is an automated email by Data Controller for SAS. For "
|
||||||
"documentation, please visit https://docs.datacontroller.io";
|
"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;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &alert_event=APPROVED %then %do;
|
%else %if &alert_event=APPROVED %then %do;
|
||||||
/* there is no approval message */
|
/* there is no approval message */
|
||||||
data _null_;
|
data _null_;
|
||||||
File __out lrecl=32000;
|
File __out lrecl=32000;
|
||||||
|
length txt $2048;
|
||||||
|
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
|
||||||
|
/* fallback message */
|
||||||
put 'Dear user,';
|
put 'Dear user,';
|
||||||
put ' ';
|
put ' ';
|
||||||
put "Please be advised that a change to table &alert_lib..&alert_ds has "
|
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 " ";
|
||||||
put "This is an automated email by Data Controller for SAS. For "
|
put "This is an automated email by Data Controller for SAS. For "
|
||||||
"documentation, please visit https://docs.datacontroller.io";
|
"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;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &alert_event=REJECTED %then %do;
|
%else %if &alert_event=REJECTED %then %do;
|
||||||
@@ -170,17 +199,29 @@ filename __out email (&emails)
|
|||||||
run;
|
run;
|
||||||
data _null_;
|
data _null_;
|
||||||
File __out lrecl=32000;
|
File __out lrecl=32000;
|
||||||
|
length txt $2048;
|
||||||
|
%if %mf_getattrn(alertmessage,NLOBS)=0 %then %do;
|
||||||
|
/* fallback message */
|
||||||
put 'Dear user,';
|
put 'Dear user,';
|
||||||
put ' ';
|
put ' ';
|
||||||
put "Please be advised that a change to table &alert_lib..&alert_ds has "
|
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 " ";
|
put " ";
|
||||||
length txt $2048;
|
|
||||||
txt=symget('REVIEW_REASON_TXT');
|
txt=symget('REVIEW_REASON_TXT');
|
||||||
put "Reason provided: " txt;
|
put "Reason provided: " txt;
|
||||||
put " ";
|
put " ";
|
||||||
put "This is an automated email by Data Controller for SAS. For "
|
put "This is an automated email by Data Controller for SAS. For "
|
||||||
"documentation, please visit https://docs.datacontroller.io";
|
"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;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -201,6 +201,44 @@ insert into &lib..mpe_config set
|
|||||||
,var_value=' '
|
,var_value=' '
|
||||||
,var_active=1
|
,var_active=1
|
||||||
,var_desc='Activation Key';
|
,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
|
insert into &lib..mpe_datadictionary set
|
||||||
@@ -213,7 +251,6 @@ insert into &lib..mpe_datadictionary set
|
|||||||
,DD_RESPONSIBLE="&sysuserid"
|
,DD_RESPONSIBLE="&sysuserid"
|
||||||
,DD_SENSITIVITY="Low"
|
,DD_SENSITIVITY="Low"
|
||||||
,tx_to='31DEC5999:23:59:59'dt;
|
,tx_to='31DEC5999:23:59:59'dt;
|
||||||
|
|
||||||
insert into &lib..mpe_datadictionary set
|
insert into &lib..mpe_datadictionary set
|
||||||
tx_from=0
|
tx_from=0
|
||||||
,DD_TYPE='TABLE'
|
,DD_TYPE='TABLE'
|
||||||
@@ -224,7 +261,6 @@ insert into &lib..mpe_datadictionary set
|
|||||||
,DD_RESPONSIBLE="&sysuserid"
|
,DD_RESPONSIBLE="&sysuserid"
|
||||||
,DD_SENSITIVITY="Low"
|
,DD_SENSITIVITY="Low"
|
||||||
,tx_to='31DEC5999:23:59:59'dt;
|
,tx_to='31DEC5999:23:59:59'dt;
|
||||||
|
|
||||||
insert into &lib..mpe_datadictionary set
|
insert into &lib..mpe_datadictionary set
|
||||||
tx_from=0
|
tx_from=0
|
||||||
,DD_TYPE='COLUMN'
|
,DD_TYPE='COLUMN'
|
||||||
@@ -235,7 +271,6 @@ insert into &lib..mpe_datadictionary set
|
|||||||
,DD_RESPONSIBLE="&sysuserid"
|
,DD_RESPONSIBLE="&sysuserid"
|
||||||
,DD_SENSITIVITY="Low"
|
,DD_SENSITIVITY="Low"
|
||||||
,tx_to='31DEC5999:23:59:59'dt;
|
,tx_to='31DEC5999:23:59:59'dt;
|
||||||
|
|
||||||
insert into &lib..mpe_datadictionary set
|
insert into &lib..mpe_datadictionary set
|
||||||
tx_from=0
|
tx_from=0
|
||||||
,DD_TYPE='DIRECTORY'
|
,DD_TYPE='DIRECTORY'
|
||||||
@@ -806,16 +841,16 @@ insert into &lib..mpe_selectbox set
|
|||||||
,select_lib="&lib"
|
,select_lib="&lib"
|
||||||
,select_ds="MPE_VALIDATIONS"
|
,select_ds="MPE_VALIDATIONS"
|
||||||
,base_column="RULE_TYPE"
|
,base_column="RULE_TYPE"
|
||||||
,selectbox_value="HARDSELECT"
|
,selectbox_value="NOTNULL"
|
||||||
,selectbox_order=4
|
,selectbox_order=4
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,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)
|
selectbox_rk=%mf_increment(rk)
|
||||||
,ver_from_dttm=0
|
,ver_from_dttm=0
|
||||||
,select_lib="&lib"
|
,select_lib="&lib"
|
||||||
,select_ds="MPE_VALIDATIONS"
|
,select_ds="MPE_VALIDATIONS"
|
||||||
,base_column="RULE_TYPE"
|
,base_column="RULE_TYPE"
|
||||||
,selectbox_value="SOFTSELECT"
|
,selectbox_value="HARDSELECT"
|
||||||
,selectbox_order=5
|
,selectbox_order=5
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
||||||
insert into &lib..mpe_selectbox set
|
insert into &lib..mpe_selectbox set
|
||||||
@@ -824,26 +859,53 @@ insert into &lib..mpe_selectbox set
|
|||||||
,select_lib="&lib"
|
,select_lib="&lib"
|
||||||
,select_ds="MPE_VALIDATIONS"
|
,select_ds="MPE_VALIDATIONS"
|
||||||
,base_column="RULE_TYPE"
|
,base_column="RULE_TYPE"
|
||||||
,selectbox_value="NOTNULL"
|
,selectbox_value="HARDSELECT_HOOK"
|
||||||
,selectbox_order=6
|
,selectbox_order=6
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,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
|
insert into &lib..mpe_selectbox set
|
||||||
selectbox_rk=%mf_increment(rk)
|
selectbox_rk=%mf_increment(rk)
|
||||||
,ver_from_dttm=0
|
,ver_from_dttm=0
|
||||||
,select_lib="&lib"
|
,select_lib="&lib"
|
||||||
,select_ds="MPE_SECURITY"
|
,select_ds="MPE_VALIDATIONS"
|
||||||
,base_column="DSN"
|
,base_column="RULE_TYPE"
|
||||||
,selectbox_value="SOME_DATASET"
|
,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
|
,selectbox_order=1
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,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
|
insert into &lib..mpe_selectbox set
|
||||||
selectbox_rk=%mf_increment(rk)
|
selectbox_rk=%mf_increment(rk)
|
||||||
,ver_from_dttm=0
|
,ver_from_dttm=0
|
||||||
,select_lib="&lib"
|
,select_lib="&lib"
|
||||||
,select_ds="MPE_SECURITY"
|
,select_ds="MPE_SECURITY"
|
||||||
,base_column="DSN"
|
,base_column="DSN"
|
||||||
,selectbox_value="EXAMPLE"
|
,selectbox_value="*ALL*"
|
||||||
,selectbox_order=2
|
,selectbox_order=1
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,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)
|
selectbox_rk=%mf_increment(rk)
|
||||||
@@ -908,24 +970,6 @@ insert into &lib..mpe_selectbox set
|
|||||||
,selectbox_value='AUDIT'
|
,selectbox_value='AUDIT'
|
||||||
,selectbox_order=4
|
,selectbox_order=4
|
||||||
,ver_to_dttm='31DEC5999:23:59:59'dt;
|
,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
|
insert into &lib..mpe_selectbox set
|
||||||
selectbox_rk=%mf_increment(rk)
|
selectbox_rk=%mf_increment(rk)
|
||||||
,ver_from_dttm=0
|
,ver_from_dttm=0
|
||||||
|
|||||||
@@ -143,17 +143,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "vtest",
|
"name": "vtest",
|
||||||
"appLoc": "/30.SASApps/app/vtest",
|
"appLoc": "/Users/&sysuserid/dctest",
|
||||||
"serverType": "SASVIYA",
|
"serverType": "SASVIYA",
|
||||||
"serverUrl": "https://sas.4gl.io",
|
"serverUrl": "https://sas.4gl.io",
|
||||||
"contextName": "Datacontroller compute context",
|
"contextName": "Compute Reusable",
|
||||||
"testConfig": {
|
"testConfig": {
|
||||||
"testSetUp": "sasjs/tests/testsetup.sas"
|
"testSetUp": "sasjs/tests/testsetup.sas"
|
||||||
},
|
},
|
||||||
"serviceConfig": {
|
"serviceConfig": {
|
||||||
"initProgram": "sasjs/utils/serviceinitviya.sas",
|
"initProgram": "sasjs/utils/serviceinitviya.sas",
|
||||||
"serviceFolders": [
|
"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/admin",
|
||||||
"sasjs/targets/viya/services_viya/public"
|
"sasjs/targets/viya/services_viya/public"
|
||||||
]
|
]
|
||||||
@@ -166,6 +166,9 @@
|
|||||||
],
|
],
|
||||||
"deployConfig": {
|
"deployConfig": {
|
||||||
"deployServicePack": true
|
"deployServicePack": true
|
||||||
|
},
|
||||||
|
"streamConfig": {
|
||||||
|
"streamWeb": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,10 +9,12 @@
|
|||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getuser.sas
|
@li mf_getuser.sas
|
||||||
@li mf_nobs.sas
|
@li mf_nobs.sas
|
||||||
@li mp_ds2cards.sas
|
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@li mp_binarycopy.sas
|
@li mp_binarycopy.sas
|
||||||
|
@li mp_ds2cards.sas
|
||||||
|
@li mp_ds2csv.sas
|
||||||
@li mp_streamfile.sas
|
@li mp_streamfile.sas
|
||||||
|
@li mp_validatecol.sas
|
||||||
|
|
||||||
@author 4GL Apps Ltd
|
@author 4GL Apps Ltd
|
||||||
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
||||||
@@ -21,23 +23,33 @@
|
|||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
%global dclib islib newlib;
|
||||||
%mpeinit()
|
%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));
|
%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 mime=application/csv;
|
||||||
%let dbms=CSV;
|
%let dbms=CSV;
|
||||||
%let ext=csv;
|
%let ext=csv;
|
||||||
|
|
||||||
%macro conditional_export(ds);
|
%macro conditional_export(ds);
|
||||||
%if %mf_nobs(&ds)>0 %then %do;
|
%if %mf_nobs(&ds)>0 %then %do;
|
||||||
PROC EXPORT DATA= &ds OUTFILE= "&work/&ds..&ext"
|
/* cannot use PROC EXPORT as we need to wrap all csv char values in quotes */
|
||||||
DBMS=&dbms REPLACE;
|
/* cannot use excel as it does not work consistently in all SAS envs */
|
||||||
RUN;
|
%mp_ds2csv(&ds,outfile="&work/&newlib..&ds..csv",headerformat=NAME)
|
||||||
ods package(ProdOutput) add file="&work/&ds..&ext" mimetype="&mime";
|
ods package(ProdOutput) add file="&work/&newlib..&ds..&ext" mimetype="&mime";
|
||||||
%end;
|
%end;
|
||||||
%mp_abort(iftrue= (&syscc ne 0)
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
,mac=&_program
|
,mac=&_program
|
||||||
@@ -52,6 +64,7 @@ data MPE_ALERTS;
|
|||||||
set &mpelib..MPE_ALERTS;
|
set &mpelib..MPE_ALERTS;
|
||||||
where &dc_dttmtfmt. le tx_to;
|
where &dc_dttmtfmt. le tx_to;
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
if alert_lib="&mpelib" then alert_lib="&newlib";
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_ALERTS)
|
%conditional_export(MPE_ALERTS)
|
||||||
|
|
||||||
@@ -61,6 +74,7 @@ data MPE_COLUMN_LEVEL_SECURITY;
|
|||||||
where &dc_dttmtfmt. le tx_to;
|
where &dc_dttmtfmt. le tx_to;
|
||||||
where also CLS_LIBREF ne "&mpelib";
|
where also CLS_LIBREF ne "&mpelib";
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
CLS_LIBREF="&newlib";
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_COLUMN_LEVEL_SECURITY)
|
%conditional_export(MPE_COLUMN_LEVEL_SECURITY)
|
||||||
|
|
||||||
@@ -68,6 +82,7 @@ data MPE_CONFIG;
|
|||||||
set &mpelib..MPE_CONFIG;
|
set &mpelib..MPE_CONFIG;
|
||||||
where &dc_dttmtfmt. le tx_to;
|
where &dc_dttmtfmt. le tx_to;
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
if var_name='DC_MACROS' then var_value=tranwrd(var_value,"&mpelib","&newlib");
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_CONFIG)
|
%conditional_export(MPE_CONFIG)
|
||||||
|
|
||||||
@@ -93,6 +108,7 @@ data MPE_EXCEL_CONFIG;
|
|||||||
set &mpelib..MPE_EXCEL_CONFIG;
|
set &mpelib..MPE_EXCEL_CONFIG;
|
||||||
where &dc_dttmtfmt. le tx_to;
|
where &dc_dttmtfmt. le tx_to;
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
if xl_libref="&mpelib" then xl_libref="&newlib";
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_EXCEL_CONFIG)
|
%conditional_export(MPE_EXCEL_CONFIG)
|
||||||
|
|
||||||
@@ -107,6 +123,7 @@ data MPE_ROW_LEVEL_SECURITY;
|
|||||||
set &mpelib..MPE_ROW_LEVEL_SECURITY;
|
set &mpelib..MPE_ROW_LEVEL_SECURITY;
|
||||||
where &dc_dttmtfmt. le tx_to;
|
where &dc_dttmtfmt. le tx_to;
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
if rls_libref="&mpelib" then rls_libref="&newlib";
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_ROW_LEVEL_SECURITY)
|
%conditional_export(MPE_ROW_LEVEL_SECURITY)
|
||||||
|
|
||||||
@@ -115,6 +132,7 @@ data MPE_SECURITY;
|
|||||||
set &mpelib..MPE_SECURITY;
|
set &mpelib..MPE_SECURITY;
|
||||||
where &dc_dttmtfmt. le TX_TO;
|
where &dc_dttmtfmt. le TX_TO;
|
||||||
drop tx_: ;
|
drop tx_: ;
|
||||||
|
if libref="&mpelib" then libref="&newlib";
|
||||||
run;
|
run;
|
||||||
%conditional_export(MPE_SECURITY)
|
%conditional_export(MPE_SECURITY)
|
||||||
|
|
||||||
@@ -142,6 +160,23 @@ data MPE_VALIDATIONS;
|
|||||||
run;
|
run;
|
||||||
%conditional_export(MPE_VALIDATIONS)
|
%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 */
|
/* finish up zip file */
|
||||||
ods package(ProdOutput) publish archive properties
|
ods package(ProdOutput) publish archive properties
|
||||||
(archive_name="DCBACKUP.zip" archive_path="&work");
|
(archive_name="DCBACKUP.zip" archive_path="&work");
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ data work.reject;
|
|||||||
REVIEW_STATUS_ID="REJECTED";
|
REVIEW_STATUS_ID="REJECTED";
|
||||||
REVIEWED_BY_NM="&user";
|
REVIEWED_BY_NM="&user";
|
||||||
REVIEWED_ON_DTTM=&now;
|
REVIEWED_ON_DTTM=&now;
|
||||||
REVIEW_REASON_TXT=symget('STP_REASON');
|
/* sanitise message to prevent code injection */
|
||||||
|
REVIEW_REASON_TXT=compress(symget('STP_REASON'), '&%;');
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%mp_lockanytable(LOCK,
|
%mp_lockanytable(LOCK,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li bitemporal_dataloader.sas
|
@li bitemporal_dataloader.sas
|
||||||
@li dc_assignlib.sas
|
@li dc_assignlib.sas
|
||||||
|
@li dc_cassave.sas
|
||||||
@li mf_existds.sas
|
@li mf_existds.sas
|
||||||
@li mf_existvar.sas
|
@li mf_existvar.sas
|
||||||
@li mf_getattrn.sas
|
@li mf_getattrn.sas
|
||||||
@@ -669,6 +670,9 @@ run;
|
|||||||
ctl_ds=&mpelib..mpe_lockanytable
|
ctl_ds=&mpelib..mpe_lockanytable
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* save table to disk (if viya + cas) */
|
||||||
|
%dc_cassave(&libds)
|
||||||
|
|
||||||
/* run post-approve hook */
|
/* run post-approve hook */
|
||||||
%mpe_runhook(POST_APPROVE_HOOK)
|
%mpe_runhook(POST_APPROVE_HOOK)
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@
|
|||||||
<h5> cols </h5>
|
<h5> cols </h5>
|
||||||
Contains column level attributes.
|
Contains column level attributes.
|
||||||
@li NAME - column name
|
@li NAME - column name
|
||||||
@li VARNUM - variable position. Source: https://core.sasjs.io/mp__getcols_8sas.html
|
@li VARNUM - var position. https://core.sasjs.io/mp__getcols_8sas.html
|
||||||
@li LABEL - variable label. Source: https://core.sasjs.io/mp__getcols_8sas.html
|
@li LABEL - var label. https://core.sasjs.io/mp__getcols_8sas.html
|
||||||
@li FMTNAME - derived format name. Source: https://core.sasjs.io/mp__getcols_8sas.html
|
@li FMTNAME - derived format. https://core.sasjs.io/mp__getcols_8sas.html
|
||||||
@li DDTYPE - derived dropdown type. Source: 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:
|
@li CLS_RULE - values include:
|
||||||
- EDIT - the column is editable
|
- EDIT - the column is editable
|
||||||
- READ - the column should be readonly
|
- READ - the column should be readonly
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li dc_assignlib.sas
|
@li dc_assignlib.sas
|
||||||
|
@li dc_casload.sas
|
||||||
@li dc_getgroupmembers.sas
|
@li dc_getgroupmembers.sas
|
||||||
@li mf_existvar.sas
|
@li mf_existvar.sas
|
||||||
@li mf_getattrn.sas
|
@li mf_getattrn.sas
|
||||||
@@ -142,6 +143,7 @@ run;
|
|||||||
%let libref=%upcase(%scan(&libds,1,.));
|
%let libref=%upcase(%scan(&libds,1,.));
|
||||||
%let dsn=%upcase(%scan(&libds,2,.));
|
%let dsn=%upcase(%scan(&libds,2,.));
|
||||||
%dc_assignlib(WRITE,&libref)
|
%dc_assignlib(WRITE,&libref)
|
||||||
|
%dc_casload(&libds)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First check user has access permission to edit the table
|
* First check user has access permission to edit the table
|
||||||
|
|||||||
@@ -51,6 +51,8 @@
|
|||||||
data _null_;
|
data _null_;
|
||||||
set work.sascontroltable;
|
set work.sascontroltable;
|
||||||
call symputx('action',action);
|
call symputx('action',action);
|
||||||
|
/* sanitise message to prevent code injection */
|
||||||
|
message=compress(message, '&%;');
|
||||||
call symputx('message',message);
|
call symputx('message',message);
|
||||||
libds=upcase(libds);
|
libds=upcase(libds);
|
||||||
call symputx('orig_libds',libds);
|
call symputx('orig_libds',libds);
|
||||||
|
|||||||
@@ -19,6 +19,11 @@
|
|||||||
data work.staging_ds;
|
data work.staging_ds;
|
||||||
set work.staging_ds;
|
set work.staging_ds;
|
||||||
LIBREF=upcase(LIBREF);
|
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);
|
DSN=upcase(DSN);
|
||||||
ACCESS_LEVEL=upcase(ACCESS_LEVEL);
|
ACCESS_LEVEL=upcase(ACCESS_LEVEL);
|
||||||
if ACCESS_LEVEL not in ('EDIT','APPROVE','VIEW','SIGNOFF','AUDIT') then do;
|
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);
|
audit_libds=upcase(audit_libds);
|
||||||
rk_underlying=upcase(rk_underlying);
|
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 */
|
/* check for valid loadtype */
|
||||||
if LOADTYPE not in ('UPDATE','TXTEMPORAL','FORMAT_CAT','BITEMPORAL','REPLACE')
|
if LOADTYPE not in ('UPDATE','TXTEMPORAL','FORMAT_CAT','BITEMPORAL','REPLACE')
|
||||||
then do;
|
then do;
|
||||||
|
|||||||
@@ -113,6 +113,16 @@ run;
|
|||||||
and &dc_dttmtfmt. lt b.tx_to
|
and &dc_dttmtfmt. lt b.tx_to
|
||||||
and b.ACCESS_LEVEL in ('EDIT')
|
and b.ACCESS_LEVEL in ('EDIT')
|
||||||
and b.SAS_GROUP in (select groupname from groups)
|
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;
|
order by 1;
|
||||||
%end;
|
%end;
|
||||||
%mend mstp_mpeditorstartup;
|
%mend mstp_mpeditorstartup;
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief testing gethistory service
|
@brief testing startupservice service
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
@li mp_assertdsobs.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;
|
%let _program=&appLoc/services/public/startupservice;
|
||||||
|
|
||||||
%mp_testservice(&_program,
|
%mx_testservice(&_program,
|
||||||
viyacontext=&defaultcontext,
|
mdebug=&sasjs_mdebug,
|
||||||
outlib=webout
|
outlib=webout,
|
||||||
|
viyacontext=&defaultcontext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
data work.globvars;
|
data work.globvars;
|
||||||
set webout.globvars;
|
set webout.globvars;
|
||||||
putlog (_all_)(=);
|
putlog (_all_)(=);
|
||||||
@@ -36,4 +39,92 @@ run;
|
|||||||
desc=xlmaps table returned,
|
desc=xlmaps table returned,
|
||||||
test=HASOBS,
|
test=HASOBS,
|
||||||
outds=work.test_results
|
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)
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li dc_assignlib.sas
|
@li dc_assignlib.sas
|
||||||
|
@li dc_casload.sas
|
||||||
@li dc_createdataset.sas
|
@li dc_createdataset.sas
|
||||||
@li dc_gettableid.sas
|
@li dc_gettableid.sas
|
||||||
@li mf_existds.sas
|
@li mf_existds.sas
|
||||||
@@ -144,6 +145,7 @@ run;
|
|||||||
* assign the Library
|
* assign the Library
|
||||||
*/
|
*/
|
||||||
%dc_assignlib(READ,%scan(&LIBDS,1,.))
|
%dc_assignlib(READ,%scan(&LIBDS,1,.))
|
||||||
|
%dc_casload(&libds)
|
||||||
|
|
||||||
/* abort if looking for a format and the catalog doesn't exist */
|
/* abort if looking for a format and the catalog doesn't exist */
|
||||||
%mp_abort(iftrue= (&fmt_ind=1 and %sysfunc(exist(&libds,CATALOG))=0)
|
%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
|
,engine
|
||||||
,'' as libraryid length=17
|
,'' as libraryid length=17
|
||||||
from dictionary.libnames
|
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');
|
insert into &syslast values ("&DC_LIBREF", "&DC_LIBNAME",'','V9');
|
||||||
|
|
||||||
%mend dc_getlibs;
|
%mend dc_getlibs;
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ data _null_;
|
|||||||
put '/* This physical location is used for staging data and audit history */';
|
put '/* This physical location is used for staging data and audit history */';
|
||||||
put '%let dc_staging_area=' "&dcpath/dc_staging;";
|
put '%let dc_staging_area=' "&dcpath/dc_staging;";
|
||||||
put ' ';
|
put ' ';
|
||||||
|
put 'cas dcsession sessopts=(caslib=casuser);';
|
||||||
|
put 'caslib _all_ assign;';
|
||||||
|
put ' ';
|
||||||
if &syssite in (70221618,70253615) then do;
|
if &syssite in (70221618,70253615) then do;
|
||||||
put "libname dcdemo '&dcpath/dc_demo';";
|
put "libname dcdemo '&dcpath/dc_demo';";
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ run;
|
|||||||
%let testloc=%sysfunc(pathname(&DC_LIBREF))/fmt%mf_getuniquefileref();
|
%let testloc=%sysfunc(pathname(&DC_LIBREF))/fmt%mf_getuniquefileref();
|
||||||
%mf_mkdir(&testloc)
|
%mf_mkdir(&testloc)
|
||||||
libname dctest "&testloc";
|
libname dctest "&testloc";
|
||||||
|
data dctest.mpe_x_test;
|
||||||
|
set &DC_LIBREF..mpe_x_test;
|
||||||
|
run;
|
||||||
|
|
||||||
/* test library with only one format catalog */
|
/* test library with only one format catalog */
|
||||||
%mf_mkdir(&testloc/fmtonly)
|
%mf_mkdir(&testloc/fmtonly)
|
||||||
libname fmtonly "&testloc/fmtonly";
|
libname fmtonly "&testloc/fmtonly";
|
||||||
|
|||||||
@@ -12,12 +12,6 @@
|
|||||||
|
|
||||||
options noquotelenmax ps=max;
|
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 ;*/
|
/*caslib casmusic path='/opt/sas/viya/cascache/tracks' libref=casmusic ;*/
|
||||||
|
|
||||||
%let syscc=0;
|
%let syscc=0;
|
||||||
|
|||||||
Reference in New Issue
Block a user