102 Commits

Author SHA1 Message Date
8c60473c15 chore(release): 7.0.0 [skip ci]
# [7.0.0](https://git.datacontroller.io/dc/dc/compare/v6.16.2...v7.0.0) (2025-06-11)

### Bug Fixes

* bumping adapter to re-enable JES API method ([e874143](e874143a95))
* commit git hooks checking lint ([69f687a](69f687a85f))
* ensuring apploc is not case sensitive. Closes [#171](#171) ([24545f2](24545f2acd))
* export unregistered formats ([f6d7d6f](f6d7d6f90c)), closes [#158](#158)
* reload startupservice after user approves the MPE_TABLES page ([e5f8e50](e5f8e500c1))
* showing catalog_cnt in libinfo ([e44a25d](e44a25dcc3)), closes [#160](#160)

### Features

* adding 4 new tables for catalogs ([e4dbab8](e4dbab8b16))
* capturing catalog specific information, closes [#159](#159) ([b4c586a](b4c586a859))
* viewer added catalog_cnt ([2aa19d1](2aa19d1dca))

### BREAKING CHANGES

* Introduction of 4 new tables for capturing information related to catalogs and their objects.  Migration script prepared and available in the DB folder (usual place)
2025-06-11 13:46:10 +00:00
bb126eba5b Merge pull request 'Reload startupservice after user approves the MPE_TABLES changes' (#170) from issue157 into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m8s
Release / Build-and-test-development (push) Successful in 8m47s
Release / release (push) Successful in 8m50s
Reviewed-on: #170
2025-06-11 13:16:22 +00:00
d1998422d2 chore: fix for mpe_datastatus_libs
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m19s
Build / Build-and-test-development (pull_request) Successful in 8m45s
2025-06-11 14:15:50 +01:00
69f687a85f fix: commit git hooks checking lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m11s
Build / Build-and-test-development (pull_request) Successful in 8m34s
2025-06-11 13:11:30 +02:00
2aa19d1dca feat: viewer added catalog_cnt
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 48s
Build / Build-and-test-development (pull_request) Successful in 8m49s
2025-06-11 12:57:10 +02:00
e44a25dcc3 fix: showing catalog_cnt in libinfo
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m19s
Build / Build-and-test-development (pull_request) Successful in 8m53s
Closes #160
2025-06-11 10:06:52 +01:00
efb5ffa906 chore: reverting accidental change
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m4s
Build / Build-and-test-development (pull_request) Successful in 8m33s
2025-06-10 22:45:39 +01:00
b4c586a859 feat: capturing catalog specific information, closes #159
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m12s
Build / Build-and-test-development (pull_request) Successful in 8m35s
BREAKING CHANGE:  Introduction of 4 new tables for capturing information related to catalogs and their objects.  Migration script prepared and available in the DB folder (usual place)
2025-06-10 22:40:09 +01:00
e874143a95 fix: bumping adapter to re-enable JES API method 2025-06-10 16:18:56 +01:00
e4dbab8b16 feat: adding 4 new tables for catalogs 2025-06-10 16:18:30 +01:00
f6d7d6f90c fix: export unregistered formats
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m14s
Build / Build-and-test-development (pull_request) Successful in 9m0s
Closes #158
2025-06-10 09:41:18 +01:00
063c90caf4 chore(docs): readme fix
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m3s
Build / Build-and-test-development (pull_request) Successful in 8m38s
2025-06-06 23:24:35 +01:00
2011c2eee7 chore(docs): updating README with viya deploy details
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m0s
Build / Build-and-test-development (pull_request) Successful in 8m28s
2025-06-06 23:23:47 +01:00
24545f2acd fix: ensuring apploc is not case sensitive. Closes #171
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m6s
Build / Build-and-test-development (pull_request) Successful in 8m38s
2025-06-06 21:05:08 +01:00
a7c81245ff Merge branch 'main' into issue157
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m6s
Build / Build-and-test-development (pull_request) Successful in 8m45s
2025-06-06 13:17:17 +00:00
4f2c993b2d style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m3s
Build / Build-and-test-development (pull_request) Successful in 8m35s
2025-06-06 15:03:51 +02:00
e5f8e500c1 fix: reload startupservice after user approves the MPE_TABLES page 2025-06-06 15:03:36 +02:00
a61e2de140 chore(release): 6.16.2 [skip ci]
## [6.16.2](https://git.datacontroller.io/dc/dc/compare/v6.16.1...v6.16.2) (2025-06-06)

### Bug Fixes

* streaming viya deploy `isStreaming` function stability fix ([4830c6d](4830c6d219))
2025-06-06 11:36:00 +00:00
881d2b060e Merge pull request 'fix: streaming viya deploy isStreaming function stability fix' (#169) from viya-deploy into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m53s
Release / Build-and-test-development (push) Successful in 8m36s
Release / release (push) Successful in 8m18s
Reviewed-on: #169
2025-06-06 11:08:03 +00:00
4830c6d219 fix: streaming viya deploy isStreaming function stability fix
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m59s
Build / Build-and-test-development (pull_request) Successful in 8m30s
2025-06-06 13:06:55 +02:00
4c3c9ac88c chore(release): 6.16.1 [skip ci]
## [6.16.1](https://git.datacontroller.io/dc/dc/compare/v6.16.0...v6.16.1) (2025-06-06)

### Bug Fixes

* viya deploy updating index html based on URL ([86134f4](86134f478a))
* viya streamed app deploy page flow fix ([89ab296](89ab296151))
2025-06-06 10:35:30 +00:00
7e1c610a4d Merge pull request 'Viya deploy, updating the compute context in index.html file, found based on URL' (#168) from viya-deploy into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m54s
Release / Build-and-test-development (push) Successful in 8m30s
Release / release (push) Successful in 8m19s
Reviewed-on: #168
2025-06-06 10:19:20 +00:00
8139f495ce style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m4s
Build / Build-and-test-development (pull_request) Successful in 8m33s
2025-06-06 12:06:10 +02:00
89ab296151 fix: viya streamed app deploy page flow fix 2025-06-06 12:05:52 +02:00
a0dc92c403 style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m15s
Build / Build-and-test-development (pull_request) Successful in 8m34s
2025-06-06 10:58:01 +02:00
86134f478a fix: viya deploy updating index html based on URL 2025-06-06 10:57:41 +02:00
9a2addc18e chore(release): 6.16.0 [skip ci]
# [6.16.0](https://git.datacontroller.io/dc/dc/compare/v6.15.2...v6.16.0) (2025-06-05)

### Bug Fixes

* adapter bump ([ca7caa2](ca7caa25b6))
* automatic viya deploy timing issue ([037a97b](037a97b6ff))
* bump core to ensure ff works on viya streaming deploy ([cbd69df](cbd69df708)), closes [#156](#156)
* viya deploy load data timing ([abdbb67](abdbb67471))

### Features

* viya deploy, update the index.html contextname ([7223955](72239558af))
2025-06-05 13:53:03 +00:00
9264ce2a60 Merge pull request 'Adapter bump, including getFileContent and updateFileContent' (#167) from adapter-bump into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m4s
Release / Build-and-test-development (push) Successful in 9m9s
Release / release (push) Successful in 8m19s
Reviewed-on: #167
2025-06-05 13:17:06 +00:00
cbd69df708 fix: bump core to ensure ff works on viya streaming deploy
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m3s
Build / Build-and-test-development (pull_request) Successful in 8m39s
closes #156 (along with previous releases)
2025-06-05 14:16:44 +01:00
ca7caa25b6 fix: adapter bump
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m9s
Build / Build-and-test-development (pull_request) Successful in 8m45s
2025-06-05 14:49:21 +02:00
c10330627f Merge pull request 'Viya smooth deploy' (#166) from deploy-context into main
Some checks failed
Release / Build-production-and-ng-test (push) Has been cancelled
Release / Build-and-test-development (push) Has been cancelled
Release / release (push) Has been cancelled
Reviewed-on: #166
2025-06-05 12:30:29 +00:00
d80c59afce Merge branch 'main' into deploy-context
Some checks failed
Build / Build-and-ng-test (pull_request) Has been cancelled
Build / Build-and-test-development (pull_request) Has been cancelled
2025-06-05 12:30:19 +00:00
abdbb67471 fix: viya deploy load data timing
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 4m0s
Build / Build-and-test-development (pull_request) Failing after 2h56m12s
2025-06-05 12:07:26 +02:00
037a97b6ff fix: automatic viya deploy timing issue 2025-06-04 17:37:44 +02:00
a0a529ad38 style: lint 2025-06-04 17:36:13 +02:00
72239558af feat: viya deploy, update the index.html contextname 2025-06-04 17:35:15 +02:00
d2097ad6dd chore(release): 6.15.2 [skip ci]
## [6.15.2](https://git.datacontroller.io/dc/dc/compare/v6.15.1...v6.15.2) (2025-06-04)

### Bug Fixes

* pipeline updates for DC.html ([624a7a8](624a7a8f37))
2025-06-04 14:26:44 +00:00
1bd542cddb Merge pull request 'fix: pipeline updates for DC.html' (#165) from issue156b into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m29s
Release / Build-and-test-development (push) Successful in 8m37s
Release / release (push) Successful in 8m17s
Reviewed-on: #165
2025-06-04 13:53:24 +00:00
fb1c1ee874 Merge branch 'main' into issue156b
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m1s
Build / Build-and-test-development (pull_request) Successful in 8m34s
2025-06-04 13:48:58 +00:00
624a7a8f37 fix: pipeline updates for DC.html
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m5s
Build / Build-and-test-development (pull_request) Successful in 8m42s
2025-06-04 14:41:36 +01:00
381378f532 chore(release): 6.15.1 [skip ci]
## [6.15.1](https://git.datacontroller.io/dc/dc/compare/v6.15.0...v6.15.1) (2025-06-04)

### Bug Fixes

* updating pipeline to default to streaming on viya ([4b55894](4b558948d9))
2025-06-04 12:57:08 +00:00
af05486c0e Merge pull request 'fix: updating pipeline to default to streaming on viya' (#164) from issue156b into main
Some checks failed
Release / Build-production-and-ng-test (push) Successful in 3m57s
Release / Build-and-test-development (push) Successful in 8m41s
Release / release (push) Failing after 7m35s
Reviewed-on: #164
2025-06-04 12:28:12 +00:00
4b558948d9 fix: updating pipeline to default to streaming on viya
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m4s
Build / Build-and-test-development (pull_request) Successful in 8m33s
Also added error captures on makedata
2025-06-04 13:27:28 +01:00
d9cff42f5c chore(release): 6.15.0 [skip ci]
# [6.15.0](https://git.datacontroller.io/dc/dc/compare/v6.14.10...v6.15.0) (2025-06-04)

### Bug Fixes

* makedata with context name ([da4d0b2](da4d0b28c7))

### Features

* viya deploy context ([6c96ef7](6c96ef7fb0))
2025-06-04 09:26:02 +00:00
2a3d2b8d0d Merge pull request 'feat: viya deploy context' (#163) from deploy-context into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m3s
Release / Build-and-test-development (push) Successful in 8m39s
Release / release (push) Successful in 8m30s
Reviewed-on: #163
2025-06-04 09:09:28 +00:00
d0f453d291 chore: typo
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m59s
Build / Build-and-test-development (pull_request) Successful in 8m31s
2025-06-04 09:41:06 +02:00
8e65dd0eae style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m59s
Build / Build-and-test-development (pull_request) Successful in 8m25s
2025-06-03 21:06:48 +02:00
da4d0b28c7 fix: makedata with context name
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 49s
Build / Build-and-test-development (pull_request) Successful in 8m32s
2025-06-03 21:00:54 +02:00
6c96ef7fb0 feat: viya deploy context
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 47s
Build / Build-and-test-development (pull_request) Successful in 8m35s
2025-06-03 20:22:39 +02:00
997f09adde chore(release): 6.14.10 [skip ci]
## [6.14.10](https://git.datacontroller.io/dc/dc/compare/v6.14.9...v6.14.10) (2025-06-02)

### Bug Fixes

* bump core ([0e8503e](0e8503ed2b))
* default to home directory for SAS Drive in Viya ([9682b54](9682b548e6))
2025-06-02 17:51:20 +00:00
0e8503ed2b fix: bump core
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m31s
Release / Build-and-test-development (push) Successful in 8m40s
Release / release (push) Successful in 8m20s
2025-06-02 18:32:33 +01:00
97dfcd79b1 Merge pull request 'issue156' (#161) from issue156 into main
Some checks failed
Release / Build-and-test-development (push) Has been cancelled
Release / release (push) Has been cancelled
Release / Build-production-and-ng-test (push) Has been cancelled
Reviewed-on: #161
2025-06-02 17:29:18 +00:00
9a12a2e41f Merge branch 'main' into issue156
Some checks failed
Build / Build-and-ng-test (pull_request) Successful in 4m9s
Build / Build-and-test-development (pull_request) Has been cancelled
2025-06-02 17:27:14 +00:00
5c114e562b chore(release): 6.14.9 [skip ci]
## [6.14.9](https://git.datacontroller.io/dc/dc/compare/v6.14.8...v6.14.9) (2025-06-02)

### Bug Fixes

* default DC path for viya ([f3125ff](f3125ff464))
2025-06-02 10:36:05 +00:00
ae696a0be0 Merge pull request 'Viya default DC Path by user name' (#162) from viya-smooth-deploy into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m56s
Release / Build-and-test-development (push) Successful in 8m33s
Release / release (push) Successful in 8m22s
Reviewed-on: #162
2025-06-02 10:19:51 +00:00
22d46a5dcc style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m8s
Build / Build-and-test-development (pull_request) Successful in 8m34s
2025-06-02 11:24:30 +02:00
f3125ff464 fix: default DC path for viya 2025-06-02 11:24:18 +02:00
9682b548e6 fix: default to home directory for SAS Drive in Viya
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m10s
Build / Build-and-test-development (pull_request) Successful in 8m35s
2025-05-29 15:05:18 +01:00
ec11a74265 chore(release): 6.14.8 [skip ci]
## [6.14.8](https://git.datacontroller.io/dc/dc/compare/v6.14.7...v6.14.8) (2025-05-28)

### Bug Fixes

* CSP issues, clarity local library build, fixed some style issues ([841201a](841201adab))
* deploy page, makedata error handling, added local build of clarity, to address clr-stack-view CSP issues (inline styles) ([7b5e7ae](7b5e7ae184))
* improved deploy flow for Viya ([9604661](9604661f3b))
* requests modal causing VIYA CSP errors ([1dc6934](1dc69341ca))
* sas viya service init timing issue ([9de04e9](9de04e9a0c))
* scss of components transferred to the global styles.scss so we do not cause CSP (inline styles) issues when streaming to Viya ([6c171a6](6c171a6394))
* viya deploy page improved flow ([4bd2154](4bd215491f))
2025-05-28 18:13:32 +00:00
4be0614604 Merge pull request 'chore: package-lock' (#155) from lockfile-fix into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m5s
Release / Build-and-test-development (push) Successful in 8m48s
Release / release (push) Successful in 8m32s
Reviewed-on: #155
2025-05-28 17:56:46 +00:00
27cbff2bc5 chore: remove package.json comment
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m13s
Build / Build-and-test-development (pull_request) Successful in 8m49s
2025-05-28 19:18:32 +02:00
c41c8963f2 chore: package.json comments
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 49s
Build / Build-and-test-development (pull_request) Failing after 50s
2025-05-28 19:03:54 +02:00
7249d4fa29 chore: package-lock
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m14s
Build / Build-and-test-development (pull_request) Successful in 8m50s
2025-05-28 19:01:16 +02:00
2e0c60cc0d chore: fix package-lock 2025-05-28 18:57:43 +02:00
7c5e47f5e4 Merge pull request 'Scss of components transferred to the global styles.scss so we do not cause CSP (inline styles) issues when streaming to Viya' (#153) from css-refactor into main
Some checks failed
Release / Build-production-and-ng-test (push) Failing after 43s
Release / Build-and-test-development (push) Has been skipped
Release / release (push) Has been skipped
Reviewed-on: #153
2025-05-28 16:57:20 +00:00
f9decbd366 style: lint
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 53s
Build / Build-and-test-development (pull_request) Failing after 50s
2025-05-26 15:39:48 +02:00
1dc69341ca fix: requests modal causing VIYA CSP errors 2025-05-26 15:39:28 +02:00
75ae19fa8e style: lint
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 1m11s
Build / Build-and-test-development (pull_request) Failing after 1m18s
2025-05-23 13:35:58 +02:00
9de04e9a0c fix: sas viya service init timing issue
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 48s
Build / Build-and-test-development (pull_request) Failing after 1m15s
2025-05-23 13:35:37 +02:00
983f59cd51 style: lint
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 1m11s
Build / Build-and-test-development (pull_request) Failing after 1m11s
2025-05-23 11:32:27 +02:00
7b5e7ae184 fix: deploy page, makedata error handling, added local build of clarity, to address clr-stack-view CSP issues (inline styles) 2025-05-23 11:30:15 +02:00
6e96b1daec style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m57s
Build / Build-and-test-development (pull_request) Successful in 8m28s
2025-05-22 10:47:46 +02:00
9604661f3b fix: improved deploy flow for Viya 2025-05-22 10:47:15 +02:00
4bd215491f fix: viya deploy page improved flow
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m10s
Build / Build-and-test-development (pull_request) Successful in 8m43s
2025-05-21 14:13:03 +02:00
6a7dd451b5 style: lint
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 49s
Build / Build-and-test-development (pull_request) Failing after 47s
2025-05-21 09:55:05 +02:00
841201adab fix: CSP issues, clarity local library build, fixed some style issues
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 49s
Build / Build-and-test-development (pull_request) Failing after 49s
2025-05-21 09:36:36 +02:00
e013e62776 chore(git): Merge branch 'main' into css-refactor
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 50s
Build / Build-and-test-development (pull_request) Successful in 8m48s
2025-05-13 15:59:08 +02:00
6c171a6394 fix: scss of components transferred to the global styles.scss so we do not cause CSP (inline styles) issues when streaming to Viya 2025-05-13 15:54:57 +02:00
a377f6e8d6 chore(release): 6.14.7 [skip ci]
## [6.14.7](https://git.datacontroller.io/dc/dc/compare/v6.14.6...v6.14.7) (2025-05-08)

### Bug Fixes

* updated hot, clarity and improved accessibility score. ([2844c70](2844c70f95))
2025-05-08 11:54:20 +00:00
0337318e0b Merge pull request 'Updated hot, clarity and improved accessibility score.' (#152) from hot-clarity-accessiblity-update into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m2s
Release / Build-and-test-development (push) Successful in 8m36s
Release / release (push) Successful in 8m19s
Reviewed-on: #152
Reviewed-by: allan <allan@4gl.io>
2025-05-08 11:37:55 +00:00
2844c70f95 fix: updated hot, clarity and improved accessibility score.
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m10s
Build / Build-and-test-development (pull_request) Successful in 8m41s
2025-05-06 15:58:30 +02:00
7e11c8f375 chore(release): 6.14.6 [skip ci]
## [6.14.6](https://git.datacontroller.io/dc/dc/compare/v6.14.5...v6.14.6) (2025-04-03)

### Bug Fixes

* history table modal links styling ([c63fcdd](c63fcdd465))
2025-04-03 08:32:36 +00:00
23cbbce964 Merge pull request 'History table modal links styling' (#151) from history-links into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m47s
Release / Build-and-test-development (push) Successful in 8m19s
Release / release (push) Successful in 7m55s
Reviewed-on: #151
2025-04-03 08:16:57 +00:00
c63fcdd465 fix: history table modal links styling
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m58s
Build / Build-and-test-development (pull_request) Successful in 8m24s
2025-04-02 19:15:29 +02:00
82412b2659 chore(release): 6.14.5 [skip ci]
## [6.14.5](https://git.datacontroller.io/dc/dc/compare/v6.14.4...v6.14.5) (2025-03-24)

### Bug Fixes

* improving accessibility lighthouse score ([7f3577c](7f3577c3ef))
* prevent errors when using sqlrc in a DI job in a HOOK ([d1f0879](d1f0879f0a))
* user profile style fix, new select library and table icons ([69f8830](69f883034f))
2025-03-24 23:10:35 +00:00
eef3832e40 Merge pull request 'User profile style fix, new select library and table icons, improved accessibility score' (#150) from styling into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m53s
Release / Build-and-test-development (push) Successful in 8m14s
Release / release (push) Successful in 8m14s
Reviewed-on: #150
2025-03-24 22:42:40 +00:00
63b75a1c61 Merge branch 'main' into styling
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m51s
Build / Build-and-test-development (pull_request) Successful in 8m14s
2025-03-24 22:42:31 +00:00
d1f0879f0a fix: prevent errors when using sqlrc in a DI job in a HOOK
Some checks failed
Release / release (push) Blocked by required conditions
Release / Build-production-and-ng-test (push) Successful in 3m54s
Release / Build-and-test-development (push) Has been cancelled
2025-03-24 21:35:17 +00:00
36416aab2e style: lint
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 3m53s
Build / Build-and-test-development (pull_request) Successful in 8m16s
2025-03-21 14:08:57 +01:00
7f3577c3ef fix: improving accessibility lighthouse score 2025-03-21 14:08:24 +01:00
69f883034f fix: user profile style fix, new select library and table icons
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 49s
Build / Build-and-test-development (pull_request) Successful in 8m21s
2025-03-20 17:33:35 +01:00
1c56af01d0 chore(release): 6.14.4 [skip ci]
## [6.14.4](https://git.datacontroller.io/dc/dc/compare/v6.14.3...v6.14.4) (2025-03-18)

### Bug Fixes

* removing cli dependency warnings2 ([43c0f73](43c0f73c21))
2025-03-18 14:11:11 +00:00
43c0f73c21 fix: removing cli dependency warnings2
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m57s
Release / Build-and-test-development (push) Successful in 8m16s
Release / release (push) Successful in 8m11s
2025-03-18 13:45:55 +00:00
e8cd3d63da chore: bumping CLI and core
Some checks failed
Release / Build-production-and-ng-test (push) Successful in 3m55s
Release / Build-and-test-development (push) Successful in 8m14s
Release / release (push) Failing after 3m39s
2025-03-18 11:38:16 +00:00
b7f564cb21 chore(release): 6.14.3 [skip ci]
## [6.14.3](https://git.datacontroller.io/dc/dc/compare/v6.14.2...v6.14.3) (2025-03-15)

### Bug Fixes

* NLDAT & NLDATM formats are now being staged ([3f5cb1e](3f5cb1e2de))
2025-03-15 23:06:45 +00:00
3f5cb1e2de fix: NLDAT & NLDATM formats are now being staged
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 3m54s
Release / Build-and-test-development (push) Successful in 8m17s
Release / release (push) Successful in 8m34s
2025-03-15 22:50:42 +00:00
7d8c0472f0 chore(release): 6.14.2 [skip ci]
## [6.14.2](https://git.datacontroller.io/dc/dc/compare/v6.14.1...v6.14.2) (2025-03-10)

### Bug Fixes

* improving instructions for setup ([83b3d77](83b3d775b6))
2025-03-10 16:13:24 +00:00
b8b516ba77 Merge pull request 'fix: improving instructions for setup' (#146) from intro into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 5m4s
Release / Build-and-test-development (push) Successful in 9m56s
Release / release (push) Successful in 10m43s
Reviewed-on: #146
2025-03-10 15:53:45 +00:00
83b3d775b6 fix: improving instructions for setup
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 5m14s
Build / Build-and-test-development (pull_request) Successful in 9m48s
2025-03-07 14:44:12 +00:00
aea252ccc6 chore(release): 6.14.1 [skip ci]
## [6.14.1](https://git.datacontroller.io/dc/dc/compare/v6.14.0...v6.14.1) (2025-03-05)

### Bug Fixes

* handle national language datetime formats ([149e318](149e318a87))
* updating logic to use NLDAT formats ([95289aa](95289aa952))
2025-03-05 15:28:45 +00:00
d8908f9c7f Merge pull request 'fix: handle national language datetime formats' (#144) from fix-nldatm into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m48s
Release / Build-and-test-development (push) Successful in 9m38s
Release / release (push) Successful in 10m26s
Reviewed-on: #144
2025-03-05 14:50:58 +00:00
95289aa952 fix: updating logic to use NLDAT formats
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 5m3s
Build / Build-and-test-development (pull_request) Successful in 9m47s
2025-03-05 14:49:56 +00:00
171 changed files with 9047 additions and 6756 deletions

View File

@ -1,11 +1,12 @@
#!/bin/sh #!/bin/sh
# Avoid commits to the master branch # Using `--silent` helps for showing any errs in the first line of the response
BRANCH=`git rev-parse --abbrev-ref HEAD` # The first line is picked up by the VS Code GIT UI popup when rc is not 0
REGEX="^(master|development)$"
if [[ "$BRANCH" =~ $REGEX ]]; then if npm run --silent lint:silent ; then
echo "You are on branch $BRANCH. Are you sure you want to commit to this branch?" exit 0
echo "If so, commit with -n to bypass the pre-commit hook." else
exit 1 npm run --silent lint:fix
echo "❌ Prettier check failed! We ran lint:fix for you. Please add & commit again."
exit 1
fi fi

View File

@ -237,20 +237,20 @@ jobs:
cd sas cd sas
sasjs c -t viya sasjs c -t viya
rm -rf sasjsbuild/tests rm -rf sasjsbuild/tests
sed -i -e 's/servertype="SASJS"/servertype="SASVIYA"/g' sasjsbuild/services/clickme.html sed -i -e 's/servertype="SASJS"/servertype="SASVIYA"/g' sasjsbuild/services/DC.html
sasjs b -t viya
cp sasjsbuild/viya.sas ./demostream_viya.sas
# compile Viya Full deploy (without web)
rm -rf sasjsbuild/services/web
rm sasjsbuild/services/clickme.html
sasjs b -t viya sasjs b -t viya
cp sasjsbuild/viya.sas ./viya.sas cp sasjsbuild/viya.sas ./viya.sas
cp sasjsbuild/viya.json ./viya.json # compile Viya Full deploy (without web)
rm -rf sasjsbuild/services/web
rm sasjsbuild/services/DC.html
sasjs b -t viya
cp sasjsbuild/viya.sas ./viya_noweb.sas
cp sasjsbuild/viya.json ./viya_noweb.json
- name: Zip Frontend (including viya.json for full viya deploy) - name: Zip Frontend (including viya.json for full viya deploy)
run: | run: |
cd sas cd sas
cp sasjsbuild/viya.json ../client/dist cp sasjsbuild/viya.json ../client/dist/viya.json
cd .. cd ..
zip -r frontend.zip ./client/dist zip -r frontend.zip ./client/dist
@ -277,8 +277,8 @@ jobs:
URL="https://git.datacontroller.io/api/v1/repos/dc/dc/releases/$RELEASE_ID/assets?access_token=${{ secrets.RELEASE_TOKEN }}" URL="https://git.datacontroller.io/api/v1/repos/dc/dc/releases/$RELEASE_ID/assets?access_token=${{ secrets.RELEASE_TOKEN }}"
curl -k $URL -F attachment=@frontend.zip curl -k $URL -F attachment=@frontend.zip
curl -k $URL -F attachment=@sas/demostream_sas9.sas curl -k $URL -F attachment=@sas/demostream_sas9.sas
curl -k $URL -F attachment=@sas/demostream_viya.sas curl -k $URL -F attachment=@sas/viya.sas
curl -k $URL -F attachment=@sas/sasjs_server.json.zip curl -k $URL -F attachment=@sas/sasjs_server.json.zip
curl -k $URL -F attachment=@sas/sas9.sas curl -k $URL -F attachment=@sas/sas9.sas
curl -k $URL -F attachment=@sas/viya.sas curl -k $URL -F attachment=@sas/viya_noweb.sas
curl -k $URL -F attachment=@sas/viya.json curl -k $URL -F attachment=@sas/viya_noweb.json

View File

@ -1,3 +1,163 @@
# [7.0.0](https://git.datacontroller.io/dc/dc/compare/v6.16.2...v7.0.0) (2025-06-11)
### Bug Fixes
* bumping adapter to re-enable JES API method ([e874143](https://git.datacontroller.io/dc/dc/commit/e874143a95d0ac2e56c0793e04b979c27f96d74b))
* commit git hooks checking lint ([69f687a](https://git.datacontroller.io/dc/dc/commit/69f687a85f1cc562346b6167813d617cb9bd3404))
* ensuring apploc is not case sensitive. Closes [#171](https://git.datacontroller.io/dc/dc/issues/171) ([24545f2](https://git.datacontroller.io/dc/dc/commit/24545f2acdd5bd73cbe062526f2bd043269cc6a3))
* export unregistered formats ([f6d7d6f](https://git.datacontroller.io/dc/dc/commit/f6d7d6f90c978ac8c071471dfb67a60834424de5)), closes [#158](https://git.datacontroller.io/dc/dc/issues/158)
* reload startupservice after user approves the MPE_TABLES page ([e5f8e50](https://git.datacontroller.io/dc/dc/commit/e5f8e500c125ee233c6f7af5ad0077c0ed6abfcb))
* showing catalog_cnt in libinfo ([e44a25d](https://git.datacontroller.io/dc/dc/commit/e44a25dcc39ba4b9714257c60da84c2dfa613a85)), closes [#160](https://git.datacontroller.io/dc/dc/issues/160)
### Features
* adding 4 new tables for catalogs ([e4dbab8](https://git.datacontroller.io/dc/dc/commit/e4dbab8b1654b24e610e4b0603d1cf2b02a451e2))
* capturing catalog specific information, closes [#159](https://git.datacontroller.io/dc/dc/issues/159) ([b4c586a](https://git.datacontroller.io/dc/dc/commit/b4c586a859929e0122cd46449e43d4ca597b8b2b))
* viewer added catalog_cnt ([2aa19d1](https://git.datacontroller.io/dc/dc/commit/2aa19d1dca747f41274a032cde78d8ba73d66224))
### BREAKING CHANGES
* Introduction of 4 new tables for capturing information related to catalogs and their objects. Migration script prepared and available in the DB folder (usual place)
## [6.16.2](https://git.datacontroller.io/dc/dc/compare/v6.16.1...v6.16.2) (2025-06-06)
### Bug Fixes
* streaming viya deploy `isStreaming` function stability fix ([4830c6d](https://git.datacontroller.io/dc/dc/commit/4830c6d2191cb47abcc7919bc1d49e55595e6121))
## [6.16.1](https://git.datacontroller.io/dc/dc/compare/v6.16.0...v6.16.1) (2025-06-06)
### Bug Fixes
* viya deploy updating index html based on URL ([86134f4](https://git.datacontroller.io/dc/dc/commit/86134f478ae0b9426e01bfcc9ca4ee597ca733f7))
* viya streamed app deploy page flow fix ([89ab296](https://git.datacontroller.io/dc/dc/commit/89ab2961513b245eeea48d1867c6496d3261761e))
# [6.16.0](https://git.datacontroller.io/dc/dc/compare/v6.15.2...v6.16.0) (2025-06-05)
### Bug Fixes
* adapter bump ([ca7caa2](https://git.datacontroller.io/dc/dc/commit/ca7caa25b6eea1bd4579fb8b67ec9b211a893079))
* automatic viya deploy timing issue ([037a97b](https://git.datacontroller.io/dc/dc/commit/037a97b6ffa27b40891531ae6812ebe5b5e71e34))
* bump core to ensure ff works on viya streaming deploy ([cbd69df](https://git.datacontroller.io/dc/dc/commit/cbd69df708edf3a8446115ca7315fac3557dcf97)), closes [#156](https://git.datacontroller.io/dc/dc/issues/156)
* viya deploy load data timing ([abdbb67](https://git.datacontroller.io/dc/dc/commit/abdbb674713796e5308eb4272197a5c253868a85))
### Features
* viya deploy, update the index.html contextname ([7223955](https://git.datacontroller.io/dc/dc/commit/72239558af2ee50cdfc71b7e185e6661ab568ba1))
## [6.15.2](https://git.datacontroller.io/dc/dc/compare/v6.15.1...v6.15.2) (2025-06-04)
### Bug Fixes
* pipeline updates for DC.html ([624a7a8](https://git.datacontroller.io/dc/dc/commit/624a7a8f37f0265cf576da310ac330c75aa417cf))
## [6.15.1](https://git.datacontroller.io/dc/dc/compare/v6.15.0...v6.15.1) (2025-06-04)
### Bug Fixes
* updating pipeline to default to streaming on viya ([4b55894](https://git.datacontroller.io/dc/dc/commit/4b558948d997f456ff25a12a58827fe0d2075493))
# [6.15.0](https://git.datacontroller.io/dc/dc/compare/v6.14.10...v6.15.0) (2025-06-04)
### Bug Fixes
* makedata with context name ([da4d0b2](https://git.datacontroller.io/dc/dc/commit/da4d0b28c7109afd6f96455e1e0e80a40d25a942))
### Features
* viya deploy context ([6c96ef7](https://git.datacontroller.io/dc/dc/commit/6c96ef7fb0a55754a84ff0a8bbab838b78c1acaf))
## [6.14.10](https://git.datacontroller.io/dc/dc/compare/v6.14.9...v6.14.10) (2025-06-02)
### Bug Fixes
* bump core ([0e8503e](https://git.datacontroller.io/dc/dc/commit/0e8503ed2bb22a0fc3924ac929e7f19626772e0a))
* default to home directory for SAS Drive in Viya ([9682b54](https://git.datacontroller.io/dc/dc/commit/9682b548e6106d99d97dcc023a35d93addfd5170))
## [6.14.9](https://git.datacontroller.io/dc/dc/compare/v6.14.8...v6.14.9) (2025-06-02)
### Bug Fixes
* default DC path for viya ([f3125ff](https://git.datacontroller.io/dc/dc/commit/f3125ff4641e47e33cb203228f5b1014ea3343bc))
## [6.14.8](https://git.datacontroller.io/dc/dc/compare/v6.14.7...v6.14.8) (2025-05-28)
### Bug Fixes
* CSP issues, clarity local library build, fixed some style issues ([841201a](https://git.datacontroller.io/dc/dc/commit/841201adab582149b1cca3a42e75f7cac75167f9))
* deploy page, makedata error handling, added local build of clarity, to address clr-stack-view CSP issues (inline styles) ([7b5e7ae](https://git.datacontroller.io/dc/dc/commit/7b5e7ae18414152f9b9d8f2d94fc94de43152003))
* improved deploy flow for Viya ([9604661](https://git.datacontroller.io/dc/dc/commit/9604661f3b76111387bc9474cc26348d73ab112e))
* requests modal causing VIYA CSP errors ([1dc6934](https://git.datacontroller.io/dc/dc/commit/1dc69341cadb837e1f11624d5cf35788bbb98d96))
* sas viya service init timing issue ([9de04e9](https://git.datacontroller.io/dc/dc/commit/9de04e9a0ce016e1a9fb8b19c656077079ddcf2f))
* scss of components transferred to the global styles.scss so we do not cause CSP (inline styles) issues when streaming to Viya ([6c171a6](https://git.datacontroller.io/dc/dc/commit/6c171a6394aba8104fe0f50aa8a4e6b9fa8023a2))
* viya deploy page improved flow ([4bd2154](https://git.datacontroller.io/dc/dc/commit/4bd215491f8cdc68f78bade68e7cb98e07edc81e))
## [6.14.7](https://git.datacontroller.io/dc/dc/compare/v6.14.6...v6.14.7) (2025-05-08)
### Bug Fixes
* updated hot, clarity and improved accessibility score. ([2844c70](https://git.datacontroller.io/dc/dc/commit/2844c70f9507036216b8b621900c2bb9010c1d34))
## [6.14.6](https://git.datacontroller.io/dc/dc/compare/v6.14.5...v6.14.6) (2025-04-03)
### Bug Fixes
* history table modal links styling ([c63fcdd](https://git.datacontroller.io/dc/dc/commit/c63fcdd465950ada439d7d69622a3886e8f3a783))
## [6.14.5](https://git.datacontroller.io/dc/dc/compare/v6.14.4...v6.14.5) (2025-03-24)
### Bug Fixes
* improving accessibility lighthouse score ([7f3577c](https://git.datacontroller.io/dc/dc/commit/7f3577c3ef9f44e55a58bc64fbf89a3a64006dd4))
* prevent errors when using sqlrc in a DI job in a HOOK ([d1f0879](https://git.datacontroller.io/dc/dc/commit/d1f0879f0acf7e816c80f7635fd02f4f284214ed))
* user profile style fix, new select library and table icons ([69f8830](https://git.datacontroller.io/dc/dc/commit/69f883034fabbed31aa5d832e20561c4ae3042db))
## [6.14.4](https://git.datacontroller.io/dc/dc/compare/v6.14.3...v6.14.4) (2025-03-18)
### Bug Fixes
* removing cli dependency warnings2 ([43c0f73](https://git.datacontroller.io/dc/dc/commit/43c0f73c2189ff762986a964caae6b0b108164fc))
## [6.14.3](https://git.datacontroller.io/dc/dc/compare/v6.14.2...v6.14.3) (2025-03-15)
### Bug Fixes
* NLDAT & NLDATM formats are now being staged ([3f5cb1e](https://git.datacontroller.io/dc/dc/commit/3f5cb1e2defe390220e904e4bf04a165cb31fec4))
## [6.14.2](https://git.datacontroller.io/dc/dc/compare/v6.14.1...v6.14.2) (2025-03-10)
### Bug Fixes
* improving instructions for setup ([83b3d77](https://git.datacontroller.io/dc/dc/commit/83b3d775b6e33653b087ca9f4eb3ad5b0dbbd479))
## [6.14.1](https://git.datacontroller.io/dc/dc/compare/v6.14.0...v6.14.1) (2025-03-05)
### Bug Fixes
* handle national language datetime formats ([149e318](https://git.datacontroller.io/dc/dc/commit/149e318a8787be0109f25aeec3a1270ea75a97b2))
* updating logic to use NLDAT formats ([95289aa](https://git.datacontroller.io/dc/dc/commit/95289aa9524d3cb2b1c248cfb84f6b0d0a490c32))
# [6.14.0](https://git.datacontroller.io/dc/dc/compare/v6.13.2...v6.14.0) (2025-02-26) # [6.14.0](https://git.datacontroller.io/dc/dc/compare/v6.13.2...v6.14.0) (2025-02-26)

View File

@ -23,7 +23,16 @@ _Problems with the above include:_
Data Controller for SAS® solves all these issues in a simple-to-install, user-friendly, secure, documented, battle-tested web application. Available on Viya, SAS 9 EBI, and [SASjs Server](https://server.sasjs.io). Data Controller for SAS® solves all these issues in a simple-to-install, user-friendly, secure, documented, battle-tested web application. Available on Viya, SAS 9 EBI, and [SASjs Server](https://server.sasjs.io).
For more information: An individual Viya deploy can be done in just 2 lines of #SAS code!
```sas
filename dc url "https://git.datacontroller.io/dc/dc/releases/download/latest/viya.sas";
%inc dc;
```
For a multi-user deploy, using a shared system account, please see [deploy docs](https://docs.datacontroller.io/deploy-viya/).
For further information:
* Main site: https://datacontroller.io * Main site: https://datacontroller.io
* Docs: https://docs.datacontroller.io * Docs: https://docs.datacontroller.io

Binary file not shown.

Binary file not shown.

View File

@ -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@14.6.2;handsontable@14.6.2;hyperformula@2.7.1;jackspeak@3.4.3;path-scurry@1.11.1;package-json-from-dist@1.0.1' '@cds/city@1.1.0;@handsontable/angular@15.3.0;handsontable@15.3.0;hyperformula@2.7.1;hyperformula@3.0.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) {

2988
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -44,12 +44,12 @@
"@angular/platform-browser": "^17.3.3", "@angular/platform-browser": "^17.3.3",
"@angular/platform-browser-dynamic": "^17.3.3", "@angular/platform-browser-dynamic": "^17.3.3",
"@angular/router": "^17.3.3", "@angular/router": "^17.3.3",
"@cds/core": "^6.10.0", "@cds/core": "^6.15.1",
"@clr/angular": "^17.0.1", "@clr/angular": "file:libraries/clr-angular-17.9.0.tgz",
"@clr/icons": "^13.0.2", "@clr/icons": "^13.0.2",
"@clr/ui": "^17.0.1", "@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
"@handsontable/angular": "^14.3.0", "@handsontable/angular": "^15.3.0",
"@sasjs/adapter": "^4.11.0", "@sasjs/adapter": "^4.12.1",
"@sasjs/utils": "^3.4.0", "@sasjs/utils": "^3.4.0",
"@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",
@ -60,7 +60,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"d3-graphviz": "^5.0.2", "d3-graphviz": "^5.0.2",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"handsontable": "^14.3.0", "handsontable": "^15.3.0",
"https-browserify": "1.0.0", "https-browserify": "1.0.0",
"hyperformula": "^2.5.0", "hyperformula": "^2.5.0",
"iconv-lite": "^0.5.0", "iconv-lite": "^0.5.0",

View File

@ -148,5 +148,8 @@ export const globals: {
}, },
handsontable: { handsontable: {
darkTableHeaderClass: 'darkTH' darkTableHeaderClass: 'darkTH'
},
userDropdownConfig: {
closeOnDebugClick: false
} }
} }

View File

@ -139,10 +139,15 @@
[routerLink]="['/']" [routerLink]="['/']"
class="nav-link" class="nav-link"
> >
<img class="without-text d-block d-md-none" src="images/dc-logo.svg" /> <img
class="without-text d-block d-md-none"
src="images/dc-logo.svg"
alt="datacontroller logo without text"
/>
<img <img
class="with-text d-none d-md-block" class="with-text d-none d-md-block"
src="images/datacontroller.svg" src="images/datacontroller.svg"
alt="datacontroller logo"
/> />
</a> </a>
@ -283,7 +288,11 @@
<!-- App Loading Page --> <!-- App Loading Page -->
<div *ngIf="!startupDataLoaded" class="app-loading"> <div *ngIf="!startupDataLoaded" class="app-loading">
<img class="loading-logo" src="images/datacontroller.svg" /> <img
class="loading-logo"
src="images/datacontroller.svg"
alt="datacontroller logo"
/>
<div *ngIf="appActive === null" class="slider"> <div *ngIf="appActive === null" class="slider">
<div class="line"></div> <div class="line"></div>

View File

@ -1,447 +0,0 @@
@import '../colors.scss';
// Copyright (c) 2016 VMware, Inc. All Rights Reserved.
// This software is released under MIT license.
// The full license information can be found in LICENSE in the root directory of this project.
app-requests-modal {
z-index: 10000;
}
header.app-header {
background: $headerBackground !important;
color: #fff;
}
.logo img.without-text {
width: 30px;
}
.logo img.with-text {
width: 210px;
}
.header-hamburger-trigger {
display: block;
background: transparent;
border: 0;
margin-left: 10px;
}
.demo-expired-notice {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
left: 0;
top: 0;
height: 100vh !important;
width: 100vw !important;
z-index: 105;
background: rgba(33, 33, 33, .5);
.expired-details {
flex-direction: column;
align-items: center;
padding: 30px;
z-index: 110;
background: $headerBackground;
.expired-notice {
color: #e0e0e0;
font-size: 16px;
.mailto {
color: #8dc53e;
}
}
}
}
.main-container .update-key {
display: flex;
align-items: center;
color: white;
padding: 0px 10px;
background: #00000026;
}
.alert-icon-wrapper {
margin-top: 0 !important;
}
.nav-text {
margin-right: 20px;
}
.sidebar-toggle {
display: flex;
height: 100%;
align-items: center;
padding-left: 10px;
clr-icon {
cursor: pointer;
width: 30px;
height: 30px;
}
}
header {
.header-actions {
.dropdown {
position: unset; //without it, when opening user dropdown scrollbar was displaying without reason
}
}
.nav-link:hover {
color: #fafafa;
}
.nav-link.active {
background: #61717D;
}
}
.notf {
background: #16a57a;
color: #fffcfc;
font-size: 12px;
}
.toggle-switch input[type=checkbox]:checked+label:before {
border-color: #61717D;
background-color: #61717D;
transition: .15s ease-in;
transition-property: border-color,background-color;
}
.main-container {
min-height: 100vh !important;
}
.main-container .content-container .content-area {
padding: 0rem 1rem 1rem 1rem;
}
.content-container {
z-index: 0!important;
}
.navBarResp {
display: flex;
justify-content: center;
background: #495A67;
color: #fff;
}
::ng-deep {
.htInvalid {
background: black!important;
}
@media screen and (max-width:480px) {
h2 {
font-size: .7rem!important;
}
h3 {
font-size: .7rem;
}
}
.nav-link {
padding: 0rem 1rem 0rem 1rem;
}
body[cds-theme="light"] {
.btn-primary .btn, .btn.btn-primary {
border-color: $headerBackground;
background-color: $headerBackground;
color: #fff;
}
}
body[cds-theme="dark"] {
.btn-primary .btn, .btn.btn-primary {
border-color: #5e7382;
background-color: #5e7382;
color: #fff;
clr-icon, cds-icon {
color: #fff
}
}
}
.btn-primary .btn, .btn.btn-primary {
&:disabled {
opacity: 0.65;
}
}
.btn {
cursor: pointer;
display: inline-block;
-webkit-appearance: none!important;
border-radius: .125rem;
border: 1px solid;
min-width: 3rem;
max-width: 15rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-align: center;
text-transform: uppercase;
vertical-align: middle;
line-height: 1.5rem;
letter-spacing: .12em;
font-size: .5rem;
font-weight: 500;
height: 1.5rem;
padding: 0 .5rem;
}
.btn.btn-outline:hover {
border-color: $headerBackground;
background-color: #495A67;
color: #fff;
}
body[cds-theme="dark"] {
.btn.btn-icon.btn-dimmed {
color: #7295ae;
}
}
body[cds-theme="light"] {
.btn.btn-icon.btn-dimmed {
color: $headerBackground;
}
.btn.btn-outline {
border-color: $headerBackground;
background-color: transparent;
color: $headerBackground;
}
}
.htMobileEditorContainer .inputs textarea {
font-size: 13pt;
border: 2px solid #485967;
border-radius: 4px;
-webkit-appearance: none;
box-shadow: none;
position: absolute;
left: 14px;
right: 0px;
top: 0;
bottom: 0;
padding: 7pt;
width: 290px;
}
.htMobileEditorContainer .positionControls {
width: 333px;
position: absolute;
right: 5pt;
top: 50px;
bottom: 0;
display: flex;
justify-content: center;
}
.htMobileEditorContainer.active {
display: block;
height: 120px;
width: 350px;
}
/* Left and right */
/* Column headers */
body[cds-theme="light"] {
.wtBorder {
background-color: #495A67!important;
}
.ht_master tr:nth-of-type(odd) > td {
filter: brightness(0.95);
}
}
$darkBorderColor: #697c85;
body[cds-theme="dark"] {
.ht_master tr:nth-of-type(odd) > td {
filter: brightness(1.2);
}
.ht_master:not(.emptyColumns) ~ .handsontable tbody tr th, .ht_master:not(.emptyColumns) ~ .handsontable:not(.ht_clone_top) thead tr th:first-child {
background-color: #2d4048;
border-color: $darkBorderColor;
}
.handsontable td {
// border-right: 1px solid #697c85;
// border-bottom: 1px solid #697c85;
border-color: $darkBorderColor;
}
.handsontable tr:first-child th, .handsontable tr:first-child td {
border-color: $darkBorderColor;
}
.handsontable .handsontable.ht_clone_top .wtHider {
border-color: $darkBorderColor;
}
.handsontable .changeType {
background-color: #3c5662;
border-color: $darkBorderColor;
}
.handsontableInput {
background-color: #708b98;
}
}
.handsontable .handsontable.ht_clone_top .wtHider {
padding: 0 0 0px 0!important;
margin: 0px;
border-bottom: 3px solid #d6d3d3;
}
body[cds-theme="light"] {
.content-container {
// background: red;
background: #F5F6FF;
}
}
.datagrid-compact, .datagrid-history{
.datagrid {
border-collapse: separate;
border: 1px solid transparent;
border-radius: .125rem;
margin: 0;
margin-top: 1rem;
max-width: 100%;
width: 100%;
padding: 15px 15px 50px 15px;
}
.datagrid-foot {
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
height: 1.5rem;
padding: 0 .5rem;
line-height: calc(1.5rem - 3px);
font-size: .45833rem;
background-color: #fff;
border-top: 1px solid #ccc;
border-radius: 0px;
// border-radius: 0 0 .125rem .125rem;
}
.datagrid-footer {
position: absolute;
right: 30px;
top: 1px;
}
.datagrid .datagrid-head {
background-color: #fff;
border-bottom: 1px solid #ccc;
}
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
margin-top: .083333rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
padding: .5rem 0;
border: 1px solid #ccc;
box-shadow: 0 1px 0.125rem hsla(0,0%,45%,.25);
min-width: 5rem;
max-width: 15rem;
border-radius: .125rem;
visibility: hidden;
z-index: 1000;
}
.table {
border-collapse: separate;
border: 1px solid transparent;
border-radius: 0px;
margin: 0;
margin-top: 1rem;
max-width: 100%;
width: 100%;
}
.table th {
font-size: .45833rem;
font-weight: 600;
letter-spacing: .03em;
vertical-align: bottom;
border-bottom: 1px solid #ccc;
text-transform: uppercase;
}
.modal-header {
border-bottom: 2px solid #e4e4e4;
padding: 0 0 .5rem 0;
margin-bottom: 1rem;
}
.main-container .content-container {
min-height: 0px;
position: relative;
}
}
.app-loading {
.loading-logo {
max-width: 400px;
width: 100%;
}
}
@media screen and (max-width: 768px) {
.navBarResp {
display: flex;
justify-content: flex-start;
background: #495A67;
color: #fff;
}
.main-container .sub-nav.clr-nav-level-1 .nav .nav-link, .main-container .sub-nav.clr-nav-level-2 .nav .nav-link, .main-container .subnav.clr-nav-level-1 .nav .nav-link, .main-container .subnav.clr-nav-level-2 .nav .nav-link {
padding: 0 .5rem 0 1rem;
width: 100%;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
border-radius: .125rem 0 0 .125rem;
color: #95c84b;
}
.card-block, .card-footer {
padding: 10px 0px 0px 0px;
}
.main-container[_ngcontent-c0] .content-container[_ngcontent-c0] .content-area[_ngcontent-c0] {
padding: 0rem 0rem 0rem 0rem;
}
}

View File

@ -1,4 +1,9 @@
import { ChangeDetectorRef, Component, ElementRef } from '@angular/core' import {
ChangeDetectorRef,
Component,
ElementRef,
ViewEncapsulation
} from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { VERSION } from '../environments/version' import { VERSION } from '../environments/version'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
@ -36,7 +41,8 @@ ClarityIcons.addIcons(
@Component({ @Component({
selector: 'my-app', selector: 'my-app',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class AppComponent { export class AppComponent {
private dcAdapterSettings: DcAdapterSettings | undefined private dcAdapterSettings: DcAdapterSettings | undefined

View File

@ -5,7 +5,7 @@
<div class="card-header">Terms and Conditions</div> <div class="card-header">Terms and Conditions</div>
<div class="card-block"> <div class="card-block">
<div class="card-text"> <div class="card-text">
<p> <p class="mt-0">
The Demo version of Data Controller is free for EVALUATION purposes The Demo version of Data Controller is free for EVALUATION purposes
only. Before proceeding with configuration, please confirm that you only. Before proceeding with configuration, please confirm that you
have read, understood, and agreed to the have read, understood, and agreed to the

View File

@ -1,50 +0,0 @@
.card {
margin-top: 0;
}
.btn {
margin-top: 10px;
}
.log-wrapper {
width: 100%;
background: #f0f0f0;
border: 1px solid #c9c9c9;
padding: 10px;
overflow: auto;
white-space: pre-wrap;
}
#contexts-btn {
padding: 0;
min-width: 30px;
margin-left: 10px;
height: 30px;
display: inline-flex;
justify-content: center;
align-items: center;
padding-top: 3px;
}
.validation-bar {
display: flex;
margin-top: 20px;
align-items: center;
clr-icon {
margin-right: 5px;
}
}
.autodeploy-section {
padding: 0px 15px;
.clr-checkbox-wrapper {
margin: 20px 0 20px 0;
}
.btn-autodeploy {
display: block;
margin: 15px 0 15px 0;
}
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { SasService } from '../services/sas.service' import { SasService } from '../services/sas.service'
import { SASjsConfig } from '@sasjs/adapter' import { SASjsConfig } from '@sasjs/adapter'
import { Router } from '@angular/router' import { Router } from '@angular/router'
@ -13,7 +13,8 @@ import { DcAdapterSettings } from '../models/DcAdapterSettings'
styleUrls: ['./deploy.component.scss'], styleUrls: ['./deploy.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class DeployComponent implements OnInit { export class DeployComponent implements OnInit {
public step: number = 0 public step: number = 0
@ -56,25 +57,6 @@ export class DeployComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
if (this.sasJsConfig.serverType === ServerType.SasViya) {
fetch('sasbuild/viya.json')
.then((res) => res.text())
.then((res) => {
let initJsonFile: any = null
try {
initJsonFile = JSON.parse(res)
} catch (err) {
console.error(err)
}
if (initJsonFile) {
this.jsonFile = initJsonFile
this.loggerService.log(this.jsonFile)
}
})
}
this.setDeployDefaults() this.setDeployDefaults()
} }

View File

@ -9,14 +9,17 @@
<p class="m-0 align-self-start">Done</p> <p class="m-0 align-self-start">Done</p>
<hr class="w-100" /> <hr class="w-100" />
<div class="deploy-status-row"> <div
*ngIf="autoDeployStatus.deployServicePack !== null"
class="deploy-status-row"
>
<clr-icon <clr-icon
*ngIf="autoDeployStatus.deployServicePack" *ngIf="autoDeployStatus.deployServicePack === true"
class="deploy-success" class="deploy-success"
shape="success-standard" shape="success-standard"
></clr-icon> ></clr-icon>
<clr-icon <clr-icon
*ngIf="!autoDeployStatus.deployServicePack" *ngIf="!autoDeployStatus.deployServicePack === false"
class="deploy-error" class="deploy-error"
shape="times-circle" shape="times-circle"
></clr-icon> ></clr-icon>
@ -52,7 +55,7 @@
class="deploy-error" class="deploy-error"
shape="times-circle" shape="times-circle"
></clr-icon> ></clr-icon>
LAUNCH / CONFIGURE LAUNCH
</button> </button>
<button <button
@ -94,20 +97,72 @@
</div> </div>
<label for="dcloc" class="mt-20 clr-control-label">DC Loc</label> <label for="dcloc" class="mt-20 clr-control-label">DC Loc</label>
<div class="mb-10 clr-control-container"> <div class="mb-10 clr-control-container dc-loc-input-wrapper">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper small-mt">
<p class="mt-0">{{ dcPath }}</p> <input clrInput name="dcloc" [(ngModel)]="dcPath" />
</div> </div>
</div> </div>
<label for="dcloc" class="mt-20 clr-control-label">SAS Admin group</label> <label for="dcloc" class="mt-20 clr-control-label">SAS Admin group</label>
<div class="mb-10 clr-control-container"> <div class="mb-10 clr-control-container">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper small-mt">
<p class="mt-0">{{ selectedAdminGroup }}</p> <select
*ngIf="!adminGroupsLoading"
clrSelect
name="options"
[(ngModel)]="selectedAdminGroup"
>
<option *ngFor="let adminGroup of adminGroups" [value]="adminGroup.id">
{{ adminGroup.name }}
</option>
</select>
<clr-spinner
clrInline
class="spinner-sm"
*ngIf="adminGroupsLoading"
></clr-spinner>
</div> </div>
</div> </div>
<clr-checkbox-wrapper> <label for="computeContext" class="mt-20 clr-control-label"
>Compute Context</label
>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper small-mt">
<select
*ngIf="!computeContextsLoading"
clrSelect
name="options"
(ngModelChange)="onComputeContextChange($event)"
[(ngModel)]="selectedComputeContext"
>
<option
*ngFor="let computeContext of computeContexts"
[value]="computeContext.id"
>
{{ computeContext.name }}
</option>
</select>
<clr-spinner
clrInline
class="spinner-sm"
*ngIf="computeContextsLoading"
></clr-spinner>
</div>
</div>
<ng-container *ngIf="runningAsUser">
<label for="dcloc" class="mt-20 clr-control-label">Running as user:</label>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper">
<p class="mt-0">{{ runningAsUser }}</p>
</div>
</div>
</ng-container>
<!-- Keeping this for a reference in case future VIYA changes and starts allowing separate backend and frontend) -->
<!-- <clr-checkbox-wrapper>
<input <input
clrCheckbox clrCheckbox
[(ngModel)]="recreateDatabase" [(ngModel)]="recreateDatabase"
@ -116,19 +171,28 @@
checked checked
/> />
<label>Recreate database</label> <label>Recreate database</label>
</clr-checkbox-wrapper> </clr-checkbox-wrapper> -->
<hr /> <hr />
<button <button
(click)="runAutoDeploy()"
class="btn-autodeploy btn btn-primary d-inline-block mr-10"
>
Deploy
</button>
<!-- Keeping this for a reference in case future VIYA changes and starts allowing separate backend and frontend) -->
<!-- <button
(click)="executeJson()" (click)="executeJson()"
class="btn-autodeploy btn btn-primary d-inline-block mr-10" class="btn-autodeploy btn btn-primary d-inline-block mr-10"
[disabled]="!jsonFile" [disabled]="!jsonFile"
> >
Deploy {{ !jsonFile ? '(json file is not available)' : '' }} Deploy {{ !jsonFile ? '(json file is not available)' : '' }}
</button> </button> -->
<button <!-- <button
(click)="uploadJsonAuto.click()" (click)="uploadJsonAuto.click()"
class="btn-autodeploy btn btn-primary d-inline-block mr-10" class="btn-autodeploy btn btn-primary d-inline-block mr-10"
> >
@ -140,7 +204,7 @@
hidden hidden
(click)="clearUploadInput($event)" (click)="clearUploadInput($event)"
(change)="onJsonFileChange($event)" (change)="onJsonFileChange($event)"
/> /> -->
<clr-modal [(clrModalOpen)]="recreateDatabaseModal" [clrModalClosable]="false"> <clr-modal [(clrModalOpen)]="recreateDatabaseModal" [clrModalClosable]="false">
<h3 class="modal-title">Warning</h3> <h3 class="modal-title">Warning</h3>

View File

@ -1,61 +0,0 @@
.auto-deploy {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 100;
}
.spinner-box {
width: 400px;
padding: 20px;
border-radius: 3px;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
box-shadow: 1px 1px 8px 0px #00000082;
.buttons {
display: flex;
justify-content: space-between;
width: 100%;
}
}
.deploy-status-row {
display: flex;
align-items: center;
align-self: flex-start;
p {
margin: 0 0 0 10px;
}
}
.deploy-success {
color: #6ECF44;
}
.deploy-error {
color: #E74C3C;
// width: 20px;
// height: 20px;
}
.deploy-undeterminated {
color: #cacaca;
}
hr {
border: 0;
border-bottom: 1px solid #00000045;
}

View File

@ -1,15 +1,35 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core'
import SASjs, { SASjsConfig } from '@sasjs/adapter' import SASjs, { SASjsConfig } from '@sasjs/adapter'
import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings' import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings'
import { HelperService } from 'src/app/services'
import { DeployService } from 'src/app/services/deploy.service' import { DeployService } from 'src/app/services/deploy.service'
import { EventService } from 'src/app/services/event.service' import { EventService } from 'src/app/services/event.service'
import { LoggerService } from 'src/app/services/logger.service' import { LoggerService } from 'src/app/services/logger.service'
import { SasViyaService } from 'src/app/services/sas-viya.service'
import { SasService } from 'src/app/services/sas.service' import { SasService } from 'src/app/services/sas.service'
import { ViyaApiCurrentUser } from 'src/app/viya-api-explorer/models/viya-api-current-user.model'
import {
Item,
ViyaApiIdentities
} from 'src/app/viya-api-explorer/models/viya-api-identities.model'
import { ComputeContextDetails } from 'src/app/viya-api-explorer/models/viya-compute-context-details.model'
import {
ViyaComputeContexts,
Item as ComputeContextItem
} from 'src/app/viya-api-explorer/models/viya-compute-contexts.model'
@Component({ @Component({
selector: 'app-automatic-deploy', selector: 'app-automatic-deploy',
templateUrl: './automatic.component.html', templateUrl: './automatic.component.html',
styleUrls: ['./automatic.component.scss'] styleUrls: ['./automatic.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class AutomaticComponent implements OnInit { export class AutomaticComponent implements OnInit {
@Input() sasJs!: SASjs @Input() sasJs!: SASjs
@ -21,6 +41,7 @@ export class AutomaticComponent implements OnInit {
@Output() onNavigateToHome: EventEmitter<any> = new EventEmitter<any>() @Output() onNavigateToHome: EventEmitter<any> = new EventEmitter<any>()
public selectedComputeContext: string = ''
public makeDataResponse: string = '' public makeDataResponse: string = ''
public jsonFile: any = null public jsonFile: any = null
public autodeploying: boolean = false public autodeploying: boolean = false
@ -28,8 +49,19 @@ export class AutomaticComponent implements OnInit {
public recreateDatabaseModal: boolean = false public recreateDatabaseModal: boolean = false
public isSubmittingJson: boolean = false public isSubmittingJson: boolean = false
public isJsonSubmitted: boolean = false public isJsonSubmitted: boolean = false
public recreateDatabase: boolean = false /**
* Default was `false` when deploy was done with frontend and backend separately.
* Now we are using only streaming app, so we always want to recreate database (makedata)
*/
public recreateDatabase: boolean = true
public createDatabaseLoading: boolean = false public createDatabaseLoading: boolean = false
public adminGroupsLoading: boolean = false
public currentUserInfoLoading: boolean = false
public computeContextsLoading: boolean = false
public adminGroups: { id: string; name: string }[] = []
public runningAsUser: string | undefined
public currentUserInfo: ViyaApiCurrentUser | null = null
public computeContexts: ComputeContextItem[] = []
/** autoDeployStatus /** autoDeployStatus
* This object presents the status for two steps that we have for deploy. * This object presents the status for two steps that we have for deploy.
@ -50,10 +82,124 @@ export class AutomaticComponent implements OnInit {
private eventService: EventService, private eventService: EventService,
private deployService: DeployService, private deployService: DeployService,
private sasService: SasService, private sasService: SasService,
private loggerService: LoggerService private sasViyaService: SasViyaService,
private loggerService: LoggerService,
private helperService: HelperService
) {} ) {}
ngOnInit(): void {} ngOnInit(): void {
this.loadData()
}
public async loadData() {
await this.getAdminGroups()
await this.getComputeContexts()
await this.getCurrentUser()
setTimeout(() => {
if (this.selectedComputeContext) {
this.onComputeContextChange(this.selectedComputeContext)
}
}, 500)
}
public async getComputeContexts() {
return new Promise<void>((resolve, reject) => {
this.computeContextsLoading = true
this.sasViyaService.getComputeContexts().subscribe(
(res: ViyaComputeContexts) => {
this.computeContextsLoading = false
const defaultContext = res.items.find(
(item: ComputeContextItem) =>
item.name === 'SAS Job Execution compute context'
)
if (defaultContext) {
this.selectedComputeContext = defaultContext.id
}
this.computeContexts = res.items
resolve()
},
(err) => {
reject(err)
}
)
})
}
public async getCurrentUser() {
return new Promise<void>((resolve, reject) => {
this.currentUserInfoLoading = true
this.sasViyaService.getCurrentUser().subscribe(
(res: ViyaApiCurrentUser) => {
this.currentUserInfoLoading = false
this.currentUserInfo = res
this.dcPath = `/export/viya/homes/${res.id}`
resolve()
},
(err) => {
console.error('Error while getting current user', err)
reject(err)
}
)
})
}
public async getAdminGroups() {
return new Promise<void>((resolve, reject) => {
this.adminGroupsLoading = true
this.sasViyaService
.getAdminGroups()
.subscribe((res: ViyaApiIdentities) => {
this.adminGroupsLoading = false
// Map admin groups with only needed fields
this.adminGroups = res.items.map((item: Item) => {
return {
id: item.id,
name: item.name
}
})
resolve()
}),
(err: any) => {
this.adminGroupsLoading = false
this.loggerService.error('Error while getting admin groups', err)
this.eventService.showAbortModal('admin groups', err)
reject(err)
}
})
}
public async onComputeContextChange(computeContextId: string) {
this.sasViyaService
.getComputeContextById(computeContextId)
.subscribe((res: ComputeContextDetails) => {
if (res.attributes && res.attributes.runServerAs) {
this.runningAsUser = res.attributes.runServerAs
} else {
this.runningAsUser = this.currentUserInfo?.id || 'unknown'
}
})
}
public getComputeContextName(id: string): string | undefined {
return (
this.computeContexts.find(
(context: ComputeContextItem) => context.id === id
)?.name || undefined
)
}
/** /**
* Executes sas.json file to deploy the backend * Executes sas.json file to deploy the backend
@ -63,7 +209,6 @@ export class AutomaticComponent implements OnInit {
* to create database if checkbox is toggled on * to create database if checkbox is toggled on
*/ */
public async executeJson() { public async executeJson() {
this.autodeploying = true
this.isSubmittingJson = true this.isSubmittingJson = true
try { try {
@ -98,6 +243,14 @@ export class AutomaticComponent implements OnInit {
} }
this.isSubmittingJson = false this.isSubmittingJson = false
}
public async runAutoDeploy(executeJson: boolean = false) {
this.autodeploying = true
if (executeJson) {
this.executeJson()
}
if (this.recreateDatabase) { if (this.recreateDatabase) {
this.createDatabase() this.createDatabase()
@ -119,14 +272,27 @@ export class AutomaticComponent implements OnInit {
] ]
} }
// Get and run service using the selected context name
let selectedComputeContextName = this.sasJsConfig.contextName
if (this.selectedComputeContext.length && this.computeContexts.length) {
const computeContextName = this.getComputeContextName(
this.selectedComputeContext
)
if (computeContextName) {
selectedComputeContextName = computeContextName
}
}
/** /**
* We are overriding default `sasjsConfig` object fields with this object fields. * We are overriding default `sasjsConfig` object fields with this object fields.
* Here we want to run this request using original WEB method. * Here we want to run this request using original WEB method.
* contextName: null is the MUST field for it. * contextName: null is the MUST field for it.
*/ */
let overrideConfig = { let overrideConfig = {
useComputeApi: false, useComputeApi: null,
contextName: this.sasJsConfig.contextName, contextName: selectedComputeContextName,
debug: true debug: true
} }
@ -148,8 +314,24 @@ export class AutomaticComponent implements OnInit {
} else { } else {
this.autoDeployStatus.runMakeData = false this.autoDeployStatus.runMakeData = false
} }
if (typeof res.sasjsAbort !== 'undefined') {
const abortRes = res
const abortMsg = abortRes.sasjsAbort[0].MSG
const macMsg = abortRes.sasjsAbort[0].MAC
this.eventService.showAbortModal('makedata', abortMsg, {
SYSWARNINGTEXT: abortRes.SYSWARNINGTEXT,
SYSERRORTEXT: abortRes.SYSERRORTEXT,
MAC: macMsg
})
}
if (this.helperService.isStreamingViya())
this.updateIndexHtmlComputeContext()
}) })
.catch((err: any) => { .catch((err: any) => {
this.eventService.showAbortModal('makedata', JSON.stringify(err))
this.autoDeployStatus.runMakeData = false this.autoDeployStatus.runMakeData = false
this.autodeployDone = true this.autodeployDone = true
@ -161,6 +343,57 @@ export class AutomaticComponent implements OnInit {
}) })
} }
/**
* Only when on Viya streamed app, this method will update the `contextname` in the `index.html` on the SAS drive
* This is needed to ensure that the DC will use the same compute context `makedata` service used to run against.
*/
public async updateIndexHtmlComputeContext() {
const filenamePath = location.search.split('/').pop()
const filename = filenamePath?.includes('.') ? filenamePath : undefined
if (!filename) {
this.eventService.showAbortModal(
null,
'We could not figure out the file name of `index.html` based on the url.'
)
return
}
const indexHtmlContent = await this.sasService.getFileContent(
`${this.appLoc}/services`,
filename
)
if (!indexHtmlContent) {
this.loggerService.error(
`Failed to get ${filename} at ${this.appLoc}/services`
)
return
}
const computeContextName = this.getComputeContextName(
this.selectedComputeContext
)
if (!computeContextName) {
this.loggerService.error(
`Compute context name not found for ID: ${this.selectedComputeContext} | List: ${JSON.stringify(this.computeContexts)}`
)
return
}
const updatedContent = indexHtmlContent.replace(
/contextname="[^"]*"/g,
`contextname="${computeContextName}"`
)
await this.sasService
.updateFileContent(`${this.appLoc}/services`, filename, updatedContent)
.catch((err: any) => {
this.loggerService.error(`Failed to update DataController.html: ${err}`)
})
}
public downloadFile( public downloadFile(
content: any, content: any,
filename: string, filename: string,

View File

@ -1,4 +0,0 @@
.clear-memory-button {
right: 10px;
top: 2px;
}

View File

@ -1,4 +1,11 @@
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core' import {
Component,
Input,
OnInit,
Output,
EventEmitter,
ViewEncapsulation
} from '@angular/core'
import SASjs, { SASjsConfig } from '@sasjs/adapter' import SASjs, { SASjsConfig } from '@sasjs/adapter'
import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings' import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings'
import { RequestWrapperResponse } from 'src/app/models/request-wrapper/RequestWrapperResponse' import { RequestWrapperResponse } from 'src/app/models/request-wrapper/RequestWrapperResponse'
@ -10,7 +17,8 @@ import { SasService } from 'src/app/services/sas.service'
@Component({ @Component({
selector: 'app-manual-deploy', selector: 'app-manual-deploy',
templateUrl: './manual.component.html', templateUrl: './manual.component.html',
styleUrls: ['./manual.component.scss'] styleUrls: ['./manual.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class ManualComponent implements OnInit { export class ManualComponent implements OnInit {
@Input() sasJs!: SASjs @Input() sasJs!: SASjs
@ -266,7 +274,7 @@ export class ManualComponent implements OnInit {
* contextName: null is the MUST field for it. * contextName: null is the MUST field for it.
*/ */
let overrideConfig = { let overrideConfig = {
useComputeApi: false, useComputeApi: null,
contextName: this.sasJsConfig.contextName, contextName: this.sasJsConfig.contextName,
debug: true debug: true
} }

View File

@ -10,11 +10,13 @@
</p> </p>
<p class="m-0 mt-10"> <p class="m-0 mt-10">
Please specify a physical directory below, to which user Please specify a physical directory (on the
<strong>{{ SYSUSERID }}</strong> can write, on behalf of Data Controller: <strong> {{ SYSHOSTNAME }}</strong>
compute server) below, to which user
<strong>{{ SYSUSERID }}</strong> can write, on behalf of Data Controller.
</p> </p>
<label class="mt-20 clr-control-label">DC Directory</label> <label class="mt-20 clr-control-label">DC Staging Directory</label>
<div class="mb-10 clr-control-container"> <div class="mb-10 clr-control-container">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input <input

View File

@ -1,23 +0,0 @@
.clr-control-container {
width: 50vw;
}
.clr-input-wrapper {
width: 100%;
input {
width: 100%;
}
}
.thinProgress {
left: 0px;
right: 0;
width: unset;
height: 1px;
margin-top: 0 !important;
&::after {
top: 0;
}
}

View File

@ -1,5 +1,12 @@
import { Location } from '@angular/common' import { Location } from '@angular/common'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core'
import SASjs, { SASjsConfig } from '@sasjs/adapter' import SASjs, { SASjsConfig } from '@sasjs/adapter'
import { ServerType } from '@sasjs/utils/types/serverType' import { ServerType } from '@sasjs/utils/types/serverType'
import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings' import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings'
@ -12,7 +19,8 @@ import { SasjsService } from 'src/app/services/sasjs.service'
@Component({ @Component({
selector: 'app-sasjs-configurator', selector: 'app-sasjs-configurator',
templateUrl: './sasjs-configurator.component.html', templateUrl: './sasjs-configurator.component.html',
styleUrls: ['./sasjs-configurator.component.scss'] styleUrls: ['./sasjs-configurator.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class SasjsConfiguratorComponent implements OnInit { export class SasjsConfiguratorComponent implements OnInit {
@Input() sasJs!: SASjs @Input() sasJs!: SASjs

View File

@ -1,238 +0,0 @@
.record-edit-modal {
.column-entry {
display: flex;
justify-content: space-between;
.name-input-row {
width: 100%;
max-width: 260px;
.cell-desc {
margin-right: 30px;
margin-top: 10px;
}
}
.inputs-wrapper {
flex: 1;
display: flex;
align-items: center;
::ng-deep >*:not(.date-field):not(clr-select-container) {
flex: 1;
}
}
p {
margin-top: 0px;
}
::ng-deep {
.clr-textarea-wrapper {
margin-top: 0 !important;
}
.clr-form-control {
margin-top: 0px !important;
}
app-soft-select {
display: block;
width: 224px;
border: 1px solid #999;
color: #000;
padding: calc(.25rem + 2px) .5rem;
border-radius: .125rem;
font-size: .541667rem;
margin-right: 6px;
input {
width: 100%;
border: 0;
&:focus {
background: none;
border: 0 !important;
}
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
}
}
&:first-child p:first-child {
margin-top: 0;
}
}
.date-field {
position: relative;
display: inline-block;
textarea {
width: 230px;
}
.date-picker {
position: absolute;
right: 0;
top: 4px;
::ng-deep {
// clr-datepicker-view-manager {
// transform: unset !important;
// left: unset !important;
// right: 70px !important;
// }
.clr-input-group {
border: 0 !important;
}
}
}
}
.modal-body {
padding-bottom: 10px;
}
::ng-deep {
clr-select-container {
border: 1px solid #999;
color: #000;
border-radius: .125rem;
margin-right: 5px;
.clr-select-wrapper {
max-height: unset;
&::after {
top: 15px;
}
}
select {
height: auto;
padding: 10px;
padding-right: 20px;
border: 0 !important;
&:focus {
background: 0 0 !important;
}
&:hover {
background: transparent;
}
}
}
clr-input-container {
width: 224px;
border: 1px solid #999;
color: #000;
padding: calc(.25rem + 2px) .5rem;
border-radius: .125rem;
font-size: .541667rem;
margin-right: 6px;
input {
width: 100%;
border: 0;
&:focus {
background: none;
border: 0 !important;
}
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
&.invalid-data {
border-color: red;
}
}
.modal-dialog {
width: 80vw;
}
.clr-control-container {
width: 100%;
textarea {
width: 100%;
resize: none;
border-color: #999;
&.invalid-data {
border-color: red;
outline: 0;
}
&.not-char {
font-family: "Lucida Console", Monaco, monospace;
}
}
}
.generate-record-url {
right: 40px;
top: 40px;
font-size: 12px;
}
.generate-record-url-button {
right: 25px;
top: 5px;
}
.modal-header {
padding: 0 0 1rem 0;
}
.modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
// height: 65px;
.alert {
margin: 0;
}
}
}
}
.prev-next {
display: flex;
align-items: center;
p {
margin: 0;
}
button {
margin: 0px 10px;
}
}
.focusable {
&:focus {
box-shadow: 0 0 3px 0px #5aa220;
}
}
.entry-input-left-offset {
left: -30px;
}
.validation-info-alert {
width: 310px
}

View File

@ -1,5 +1,12 @@
import { KeyValue } from '@angular/common' import { KeyValue } from '@angular/common'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core'
import moment from 'moment' import moment from 'moment'
import { ValidateFilterSASResponse } from 'src/app/models/sas/validate-filter.model' import { ValidateFilterSASResponse } from 'src/app/models/sas/validate-filter.model'
import { QueryClause } from 'src/app/models/TableData' import { QueryClause } from 'src/app/models/TableData'
@ -16,7 +23,8 @@ import { EditRecordModal } from '../../models/EditRecordModal'
@Component({ @Component({
selector: 'app-edit-record', selector: 'app-edit-record',
templateUrl: './edit-record.component.html', templateUrl: './edit-record.component.html',
styleUrls: ['./edit-record.component.scss'] styleUrls: ['./edit-record.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class EditRecordComponent implements OnInit { export class EditRecordComponent implements OnInit {
@Input() currentRecord!: EditRecordModal @Input() currentRecord!: EditRecordModal

View File

@ -1,8 +0,0 @@
:host {
display: block;
}
p {
margin: 0;
text-align: center;
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
/** /**
* Goal of this component is to recieve array of strings where every element is one state * Goal of this component is to recieve array of strings where every element is one state
@ -10,7 +10,8 @@ import { Component, OnInit } from '@angular/core'
@Component({ @Component({
selector: 'app-upload-stater', selector: 'app-upload-stater',
templateUrl: './upload-stater.component.html', templateUrl: './upload-stater.component.html',
styleUrls: ['./upload-stater.component.scss'] styleUrls: ['./upload-stater.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class UploadStaterComponent implements OnInit { export class UploadStaterComponent implements OnInit {
public statesList: string[] = [] //States appended to be displayed public statesList: string[] = [] //States appended to be displayed

View File

@ -36,7 +36,7 @@
<div class="clr-row card-block mt-15 d-flex justify-content-between"> <div class="clr-row card-block mt-15 d-flex justify-content-between">
<div class="clr-col-md-auto"> <div class="clr-col-md-auto">
<div class="encoding-block"> <div class="encoding-block">
<clr-radio-container class="mt-0-i" clrInline> <clr-radio-container class="mt-0" clrInline>
<clr-radio-wrapper> <clr-radio-wrapper>
<input <input
type="radio" type="radio"
@ -193,13 +193,14 @@
libName: (libds?.split('.'))![0], libName: (libds?.split('.'))![0],
tableName: (libds?.split('.'))![1] tableName: (libds?.split('.'))![1]
} as libdsParsed" } as libdsParsed"
class="editor-title text-center mt-0-i" class="editor-title text-center mt-0"
> >
<clr-tooltip> <clr-tooltip>
<clr-icon <clr-icon
clrTooltipTrigger clrTooltipTrigger
(click)="datasetInfo = true" (click)="datasetInfo = true"
shape="info-circle" shape="info-circle"
aria-label="View dataset meta info"
class="is-highlight cursor-pointer" class="is-highlight cursor-pointer"
size="24" size="24"
></clr-icon> ></clr-icon>

View File

@ -1,246 +0,0 @@
.card {
margin-top: 0;
border: 0;
}
.buttonBar {
padding: 2px 10px 2px 10px;
align-items: center;
}
.testRed {
color: white;
background: rgba(255,0,0, 0.8) !important;
}
hot-table {
::ng-deep {
.firstColumnHeaderStyle button.changeType {
display: none;
}
.handsontable tbody th.ht__highlight, .handsontable thead th.ht__highlight {
&.primaryKeyHeaderStyle {
background-color: #306b00b0 !important;
}
}
.primaryKeyHeaderStyle {
background-color: #306b006e !important;
}
th.readonlyCell {
div {
opacity: 0.4;
}
}
td.readonlyCell {
opacity: 0.5
}
}
}
.submit-reason {
min-height: 120px;
max-height: 120px;
height: 120px;
}
.infoBar {
margin-top:14px;
background: #495967;
color: white;
text-align:center;
padding: 3px;
font-size: 16px;
height: 30px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
span {
width: 80%;
}
&:hover {
height: unset;
white-space: normal;
span {
width: unset;
}
}
}
.pkHeader {
background: #687682;
color: #fff;
margin: -1px -1px -1px -1px;
}
.headerBar {
// padding: 13px 0px 14px 0px;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background: var(--clr-vertical-nav-bg-color);
}
.error-icon {
width: 30px;
height: 30px;
color: red;
}
.btnCtrl {
display:flex;
justify-content:flex-end;
}
.card-header {
border-bottom: 1px solid transparent;
}
.hidden {
visibility: hidden;
}
.my-drop-zone {
border: solid 1px lightgray;
border-radius: 10px;
background: whitesmoke;
box-shadow: inset 0px 0px 4px 2px #a7a5a52b;
height: 50vh;
}
.nv-file-over {
border: solid 2px green;
} /* Default class applied to drop zones on over */
.file-drop-text{
text-align: center;
}
.nv-file-over {
border: solid 2px green;
} /* Default class applied to drop zones on over */
.file-drop-text{
text-align: center;
}
@media screen and (max-width: 768px) {
.progresStatic {
margin-top:9px!important;
}
.progress, .progress-static {
width: calc(100% - 14px);
}
}
.hotEditor {
position: relative;
}
.excel-parsing {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.details {
margin: 0;
position: absolute;
top: -45px;
}
}
.edit-record-spinner {
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.6);
position: absolute;
top: 0px;
bottom: 0px;
width: 100%;
z-index: 500;
}
@media screen and (max-width: 480px) {
.progresStatic {
margin-top:32px!important;
}
.card-block, .card-footer {
padding: 10px 0px 0px 0px;
}
}
.content-area {
padding: 0 0.8rem 0.8rem 0.8rem !important;
padding-top: 0;
// .card {
// min-height: calc(100vh - 160px);
// }
}
.drop-area {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
justify-content: center;
align-items: flex-start;
margin: 1px;
border: 2px dashed #fff;
z-index: -1;
span {
font-size: 20px;
margin-top: 20px;
padding: 10px;
background: #dbdbdb;
border-radius: 5px;
color: black;
}
}
#submitBtn, #cancelSubmitBtn {
width: 150px;
}
.view-table {
font-size: inherit !important;
}
// When width is smaller remove the text from the buttons
// keep only the icons
@media (max-width: 992px) {
.icon-collapse {
.text {
display: none;
}
}
}
// FIXME
// Let's leave it here for a reference if there
// is an issue with viewboxes/filter modal overlaying
// we will remove it if no issues found
// .filter-modal {
// z-index: 1210;
// }

View File

@ -69,7 +69,7 @@ import { ParseResult } from '../models/ParseResult.interface'
host: { host: {
class: 'content-container' class: 'content-container'
}, },
encapsulation: ViewEncapsulation.Emulated encapsulation: ViewEncapsulation.None
}) })
export class EditorComponent implements OnInit, AfterViewInit { export class EditorComponent implements OnInit, AfterViewInit {
@ViewChildren('uploadStater') @ViewChildren('uploadStater')

View File

@ -1,85 +0,0 @@
@import '../../colors.scss';
::ng-deep body[cds-theme="dark"] {
.group-info {
background-color: $headerBackground;
border-color: $headerBackground;
}
.group-data {
background-color: $headerBackground;
border-color: $headerBackground;
}
.member-table tbody{
tr:hover{
background-color: #29404b;
}
}
}
::ng-deep body[cds-theme="light"] {
.group-info{
background-color: #f9f9f9;
border-color: #a7a7a7;
box-shadow: 0px 2px 5px #dad7d7;
}
.group-data {
background-color: #f9f9f9;
border-color: #a7a7a7;
box-shadow: 0px 2px 5px #dad7d7;
}
.member-table tbody{
tr:hover{
background-color: #e6e6e6;
}
}
}
.sidebar-height{
height: 100%;
}
.group-info-text{
display: inline;
font-size: 20px;
}
.group-info{
border: 1px solid;
border-radius: 3px;
}
.group-info td{
text-align: center;
}
.group-data{
border: 1px solid;
border-radius: 3px;
}
.group-data{
min-height: auto;
h3, h5{
text-align: center;
}
.member-table{
width: 100%;
}
.member-table tbody{
tr:hover{
cursor: pointer;
}
}
}
.table-container{
overflow: auto;
}
@media screen and (max-width: 768px){
.group-data{
min-height: unset !important;
}
}

View File

@ -1,5 +1,5 @@
import { Location } from '@angular/common' import { Location } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { SASjsConfig } from '@sasjs/adapter' import { SASjsConfig } from '@sasjs/adapter'
import { ServerType } from '@sasjs/utils/types/serverType' import { ServerType } from '@sasjs/utils/types/serverType'
@ -14,7 +14,8 @@ import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapper
styleUrls: ['./group.component.scss'], styleUrls: ['./group.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class GroupComponent implements OnInit { export class GroupComponent implements OnInit {
public groups: Array<any> | undefined public groups: Array<any> | undefined

View File

@ -123,11 +123,11 @@
</div> </div>
<div *ngIf="!loading" class="no-table-selected"> <div *ngIf="!loading" class="no-table-selected">
<clr-icon <img
shape="warning-standard" src="images/select-table.png"
size="60" class="select-table-icon"
class="is-info icon-dc-fill" alt="select table icon"
></clr-icon> />
<p <p
*ngIf="treeNodeLibraries?.length! > 0" *ngIf="treeNodeLibraries?.length! > 0"
class="text-center color-gray mt-10" class="text-center color-gray mt-10"

View File

@ -1,32 +0,0 @@
clr-tree-node button {
white-space: nowrap;
}
.card-block {
height: 100%;
padding: 0;
}
.no-table-selected {
position: relative;
height: 100%;
}
::ng-deep {
// .badge.badge-info {
// background: #6a9235!important;
// color: #fff;
// }
clr-icon.is-blue, clr-icon.is-info {
fill: #6a9235;
}
}
.spinner-wrapper-fullpage {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}

View File

@ -3,7 +3,7 @@
* This software is released under MIT license. * This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project. * The full license information can be found in LICENSE in the root directory of this project.
*/ */
import { Component, AfterContentInit } from '@angular/core' import { Component, AfterContentInit, ViewEncapsulation } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { globals } from '../_globals' import { globals } from '../_globals'
@ -18,7 +18,8 @@ import { LicenceService } from '../services/licence.service'
templateUrl: './home.component.html', templateUrl: './home.component.html',
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class HomeComponent implements AfterContentInit { export class HomeComponent implements AfterContentInit {
public treeNodeLibraries: Array<any> | null = null public treeNodeLibraries: Array<any> | null = null

View File

@ -1,51 +0,0 @@
:host {
height: calc(100% - 96px);
padding: 20px 20px;
}
.card {
margin-top: 0;
}
.key-error {
font-size: 16px;
}
.misskey {
color: #E74C3C;
}
.license-key-form, .activation-key-form {
padding: 0;
.clr-control-container {
width: 100%;
textarea {
width: 100%;
height: 170px;
max-height: 170px;
min-height: 170px;
resize: none;
}
}
}
.apply-keys {
height: 40px;
}
.drop-area {
display: flex;
justify-content: center;
align-items: center;
padding: 15px;
border: 2px dashed #b2b2b2;
border-radius: 4px;
cursor: pointer;
margin: 10px 0;
}
clr-tabs button {
box-shadow: none !important
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AppService, LicenceService, SasService } from '../services' import { AppService, LicenceService, SasService } from '../services'
import { LicenseKeyData } from '../models/LicenseKeyData' import { LicenseKeyData } from '../models/LicenseKeyData'
@ -14,7 +14,8 @@ enum LicenseActions {
@Component({ @Component({
selector: 'app-licensing', selector: 'app-licensing',
templateUrl: './licensing.component.html', templateUrl: './licensing.component.html',
styleUrls: ['./licensing.component.scss'] styleUrls: ['./licensing.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class LicensingComponent implements OnInit { export class LicensingComponent implements OnInit {
public action: LicenseActions | null = null public action: LicenseActions | null = null

View File

@ -1,85 +0,0 @@
@import '../../colors.scss';
.toggle-switch input[type=checkbox]:checked+label:before {
border-color: $headerBackground;
background-color: $headerBackground !important;
transition: .15s ease-in;
transition-property: border-color,background-color;
}
#graph{
height: calc(100vh - 195px);
overflow: hidden;
text-align: center;
display: block;
width: 100%;
border: 1px solid #e4e4e4;
margin-top: 10px;
}
.selection-wrapper {
width: 100%;
max-width: 670px;
}
.column-active {
background: #d8e3e9;
color: black;
}
.content-area {
padding: 0.5rem !important;
.card {
min-height: calc(100vh - 120px);
.card-block {
padding: 0.5rem 0.35rem !important;
}
}
}
clr-tree-node button {
white-space: nowrap;
}
.btn-group.direction {
margin-left: var(--cds-global-space-6);
}
.graph-render-spinner {
position: absolute;
top: 0;
width: 100%;
display: flex;
justify-content: center;
margin-top: 10px;
}
.biglineage-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-footer {
p {
margin: 0;
}
}
.lineage-title-wrapper {
left: 12px;
}
.max-depth-input {
width: 100%;
}
@media (max-width: 768px) {
.toggle-switch-container {
margin-bottom: 20px;
}
}

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, ViewEncapsulation } from '@angular/core'
import { Location } from '@angular/common' import { Location } from '@angular/common'
import { globals } from '../_globals' import { globals } from '../_globals'
import * as d3Viz from 'd3-graphviz' import * as d3Viz from 'd3-graphviz'
@ -18,7 +18,8 @@ const moment = require('moment')
templateUrl: './lineage.component.html', templateUrl: './lineage.component.html',
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class LineageComponent { export class LineageComponent {
public switchFlag: boolean = false public switchFlag: boolean = false

View File

@ -1,82 +0,0 @@
::ng-deep body[cds-theme="dark"] {
.object-header:hover {
background-color: #405560;
}
}
::ng-deep body[cds-theme="light"] {
.objects-col {
background: white;
}
.object-header:hover {
background-color: #d8e3e9;
}
}
.objects-col{
height: 75vh;
overflow: scroll;
border: 1px solid #cccccc;
border-radius: 4px;
}
.cols-head {
border: 1px solid #cccccc;
padding: 10px;
display: flex;
}
.object-text {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-left: 10px;
flex: 1;
}
.repo-dropdown{
margin-right: 15px;
margin-left: 15px;
margin-bottom: 10px;
}
.clr-accordion-title{
width: 100%;
}
.float-right{
margin: 0px;
float: right;
}
.full-width{
width: 100%;
}
.object-uri{
margin: 0px;
margin-top: 5px;
}
.object-header{
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 3px;
padding-right: 3px;
}
.object-header:hover{
border-radius: 3px;
}
.datagrid-host{
display: unset !important;
}
.card {
margin-top: 0;
flex: 1;
display: flex;
flex-direction: column;
}
.content-area {
padding: 0.5rem !important;
display: flex;
flex-direction: column;
}

View File

@ -1,5 +1,5 @@
import { Location } from '@angular/common' import { Location } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { ClrDatagridStringFilterInterface } from '@clr/angular' import { ClrDatagridStringFilterInterface } from '@clr/angular'
import { Observable, of } from 'rxjs' import { Observable, of } from 'rxjs'
@ -50,7 +50,8 @@ class ValueFilter implements ClrDatagridStringFilterInterface<MetaData> {
styleUrls: ['./metadata.component.scss'], styleUrls: ['./metadata.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class MetadataComponent implements OnInit { export class MetadataComponent implements OnInit {
metaDataList: Array<any> | undefined metaDataList: Array<any> | undefined

View File

@ -8,4 +8,5 @@ export interface Libinfo {
LIBID: string LIBID: string
LIBSIZE: number LIBSIZE: number
TABLE_CNT: number TABLE_CNT: number
CATALOG_CNT: number
} }

View File

@ -1,30 +1,14 @@
import { BaseSASResponse } from './common/BaseSASResponse' import { BaseSASResponse } from './common/BaseSASResponse'
export interface EditorsStageDataSASResponse extends BaseSASResponse { export interface EditorsStageDataSASResponse extends BaseSASResponse {
SYSDATE: string
SYSTIME: string
sasparams: Sasparam[] sasparams: Sasparam[]
_DEBUG: string
_PROGRAM: string
AUTOEXEC: string AUTOEXEC: string
MF_GETUSER: string
SYSCC: string
SYSENCODING: string SYSENCODING: string
SYSERRORTEXT: string
SYSHOSTINFOLONG: string SYSHOSTINFOLONG: string
SYSHOSTNAME: string
SYSPROCESSID: string SYSPROCESSID: string
SYSPROCESSMODE: string SYSPROCESSMODE: string
SYSPROCESSNAME: string SYSPROCESSNAME: string
SYSJOBID: string
SYSSCPL: string
SYSSITE: string
SYSTCPIPHOSTNAME: string SYSTCPIPHOSTNAME: string
SYSUSERID: string
SYSVLONG: string
SYSWARNINGTEXT: string
END_DTTM: string
MEMSIZE: string
} }
export interface Sasparam { export interface Sasparam {

View File

@ -0,0 +1,28 @@
import { BaseSASResponse } from './common/BaseSASResponse'
export interface PublicGetChangeinfo extends BaseSASResponse {
jsparams: Jsparam[]
}
export interface Jsparam {
TABLE_ID: string
SUBMIT_STATUS_CD: string
BASE_LIB: string
BASE_DS: string
SUBMITTED_BY_NM: string
SUBMITTED_ON: number
SUBMITTED_REASON_TXT: string
INPUT_OBS: number
INPUT_VARS: number
NUM_OF_APPROVALS_REQUIRED: number
NUM_OF_APPROVALS_REMAINING: number
REVIEWED_BY_NM: string
REVIEWED_ON?: any
TABLE_NM: string
BASE_TABLE: string
REVIEWED_ON_DTTM: string
SUBMITTED_ON_DTTM: string
LIB_ENGINE: string
ALLOW_RESTORE: string
REASON: string
}

View File

@ -127,7 +127,7 @@
class="no-table-selected pointer-events-none" class="no-table-selected pointer-events-none"
> >
<clr-icon <clr-icon
shape="warning-standard" shape="upload-cloud"
size="40" size="40"
class="is-info icon-dc-fill" class="is-info icon-dc-fill"
></clr-icon> ></clr-icon>

View File

@ -1,54 +0,0 @@
.no-table-selected {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
position: absolute;
background: var(--clr-vertical-nav-bg-color);
z-index: 10;
width: 100%;
height: 100%;
top: 0;
}
.header-row {
padding: 15px 0;
border-bottom: 1px solid #d3d3d3;
}
.dataset-input-wrapper {
max-width: 500px;
width: 100%;
textarea {
min-height: 200px;
height: 200px;
}
}
.submit-reason {
min-height: 70px;
max-height: 70px;
height: 70px;
}
.log-wrapper {
margin: 0 10px;
height: auto;
}
::ng-deep td.not-matched {
background-color: #ff000054;
}
.dataset-selection-actions {
border-top: 1px solid #d3d3d3;
}
.licence-limit-notice {
color: var(--cds-alias-status-warning-dark);
}
.submission-results {
border-bottom: 1px solid #d3d3d3;
}

View File

@ -4,7 +4,8 @@ import {
ElementRef, ElementRef,
HostBinding, HostBinding,
OnInit, OnInit,
ViewChild ViewChild,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { import {
EventService, EventService,
@ -45,7 +46,8 @@ enum FileLoadingState {
@Component({ @Component({
selector: 'app-multi-dataset', selector: 'app-multi-dataset',
templateUrl: './multi-dataset.component.html', templateUrl: './multi-dataset.component.html',
styleUrls: ['./multi-dataset.component.scss'] styleUrls: ['./multi-dataset.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class MultiDatasetComponent implements OnInit { export class MultiDatasetComponent implements OnInit {
@HostBinding('class.content-container') contentContainerClass = true @HostBinding('class.content-container') contentContainerClass = true

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-not-found', selector: 'app-not-found',
@ -6,7 +6,8 @@ import { Component, OnInit } from '@angular/core'
styleUrls: ['./not-found.component.scss'], styleUrls: ['./not-found.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class NotFoundComponent implements OnInit { export class NotFoundComponent implements OnInit {
constructor() {} constructor() {}

View File

@ -1,307 +0,0 @@
::ng-deep {
body[cds-theme="dark"] {
.clause-logic {
background: #192a30;
}
.clause-query {
background: #263e48;
}
}
body[cds-theme="light"] {
.clause-logic {
background: #e9e9e9;
}
.clause-query {
background: #fbf8f8;
}
}
}
.content {
display: flex;
.clauses-container {
display: flex;
flex-direction: column;
.clause-logic {
display: flex;
justify-content: center;
flex-direction: column;
padding: 15px;
}
.clause-query {
padding: 30px 0px 20px 20px;
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
& > .clr-row {
justify-content: space-between;
&:not(:last-child) {
padding-bottom: 15px;
margin-bottom: 15px;
border-bottom: 1px solid rgba(0, 0, 0, 0.16)
}
}
.remove-group-clause-button {
position: absolute;
top: 0px;
right: 10px;
color: gray;
}
.variable-col {
display: flex;
align-items: flex-start;
padding-bottom: 1px;
.datalist-wrapper {
width: 100%;
input {
width: 100%;
}
}
}
.operator-col {
display: flex;
align-items: flex-start;
clr-select-container {
height: 45px;
margin-top: 0;
width: 100%;
}
}
.value-col {
display: flex;
align-items: flex-start;
padding-bottom: 1px;
.checkbox-vals {
width: 100%;
padding: 0px 5px;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
clr-checkbox-container {
margin-top: 0;
}
section {
max-height: 120px;
overflow-y: scroll;
}
}
.single-field-vals {
width: 100%;
::ng-deep {
.clr-control-container {
width: 100%;
.clr-input-wrapper {
max-width: none;
.clr-input-group {
width: 100%;
}
}
}
}
& > input {
width: 100%;
}
input[type=time] {
width: 100%;
padding-right: 17px;
}
}
.range-vals {
width: 100%;
::ng-deep {
.clr-control-container {
width: 100%;
.clr-input-wrapper {
max-width: none;
.clr-input-group {
width: 100%;
}
}
}
}
.from {
margin-bottom: 10px;
& > input {
width: 100%;
}
input[type=time] {
width: 100%;
padding-right: 17px;
}
}
.from, .to {
min-width: 100px;
& > input {
width: 100%;
}
input[type=time] {
width: 100%;
padding-right: 17px;
}
}
}
.contains-vals {
width: 100%;
::ng-deep {
.clr-control-container {
width: 100%;
.clr-input-wrapper {
max-width: none;
.clr-input-group {
width: 100%;
}
}
}
}
& > input {
width: 100%;
}
input[type=time] {
width: 100%;
padding-right: 17px;
}
}
}
.clause-buttons {
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: row;
align-items: center;
button {
min-width: auto;
}
}
}
}
}
.invalid-clause {
border-left: 2px solid #d94b31;
}
.clause-row {
clr-icon {
margin: 0;
}
}
.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;
}
::ng-deep body[cds-theme="dark"] {
.line-numbers {
border-color: #989797 !important;
}
}
pre[class*="language-"] {
padding: 8px;
margin: 0;
border-radius: 1px;
display: flex;
justify-content: center;
align-items: center;
min-height: 66px;
position: relative;
span.spinner {
position: absolute;
left: 10px;
top: 10px;
}
code {
white-space: pre-wrap;
word-break: break-word;
}
}
.input-val {
border: 0px;
background: #fbf8f8;
border-bottom: 1px solid #999999;
}
clr-date-container {
margin-top: 2px !important;
}
input[type="time"] {
border: 0;
background: transparent;
border-bottom: 1px solid #b3b3b3;
&:focus {
outline: none;
}
}
.in-values-modal {
.modal-footer {
border-top: 1px solid #d8d8d8;
margin-top: 10px;
}
}
.progress, .progress-static {
background-color: transparent;
width: 100%;
height: 4px;
top: 3px;
}

View File

@ -6,7 +6,8 @@ import {
OnDestroy, OnDestroy,
ChangeDetectorRef, ChangeDetectorRef,
LOCALE_ID, LOCALE_ID,
Input Input,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { SasStoreService } from '../services/sas-store.service' import { SasStoreService } from '../services/sas-store.service'
import { globals } from '../_globals' import { globals } from '../_globals'
@ -27,7 +28,8 @@ registerLocaleData(localeEnGB)
selector: 'app-query', selector: 'app-query',
templateUrl: './query.component.html', templateUrl: './query.component.html',
styleUrls: ['./query.component.scss'], styleUrls: ['./query.component.scss'],
providers: [{ provide: LOCALE_ID, useValue: 'en-GB' }] providers: [{ provide: LOCALE_ID, useValue: 'en-GB' }],
encapsulation: ViewEncapsulation.None
}) })
export class QueryComponent export class QueryComponent
implements AfterViewInit, AfterContentInit, OnDestroy implements AfterViewInit, AfterContentInit, OnDestroy

View File

@ -1,210 +0,0 @@
@import '../../../colors.scss';
.loader {
display:flex;
justify-content: center;
height:75vh;
align-items:center;
flex-direction:column
}
.modalLarge {
width: 50rem!important;
}
.addedRow {
border: 1px solid rgba(9, 77, 117, 0.2);
border-radius: 5px;
}
.deletedRow {
border: 1px solid rgba(70, 71, 70, 0.2);
border-radius: 5px;
}
::ng-deep body[cds-theme="dark"] {
table {
.updatedRow {
background: #93971e;
}
.addedRow {
background: rgb(86 153 95);
}
.deletedRow {
background: rgb(138 90 90);
}
}
}
::ng-deep body[cds-theme="light"] {
table {
.updatedRow {
background: #fafda8;
}
.addedRow {
background: rgb(146, 208, 154);
}
.deletedRow {
background: rgb(230, 179, 179);
}
}
}
.updatedRow {
border: 1px solid rgba(9, 117, 9, 0.2);
border-radius: 5px;
}
.table {
border: 0px solid;
}
.ch {
background: rgba(0,0,0,.1);
border: 1px solid rgba(104, 100, 0, 0.4);
border-radius: 5px;
}
.ch:hover {
background: rgba(252, 135, 120, 0.4);
}
.tooltip .tooltip-content.tooltip-top-right, .tooltip.tooltip-top-right>.tooltip-content, .tooltip>.tooltip-content {
font-size: .54167rem;
font-weight: 400;
letter-spacing: normal;
background: $headerBackground;
border-radius: .125rem;
color: #f0f1ec;;
line-height: .75rem;
margin: 0;
padding: .375rem .5rem;
width: 235px;
position: absolute;
top: auto;
bottom: 100%;
left: 12px;
right: auto;
border-bottom-left-radius: 0;
margin-bottom: .66667rem;
}
.tooltip .tooltip-content.tooltip-top-right:before, .tooltip.tooltip-top-right>.tooltip-content:before, .tooltip>.tooltip-content:before {
position: absolute;
bottom: -.375rem;
left: 0;
top: auto;
right: auto;
content: "";
border-left: .25rem solid $headerBackground;
border-top: .20833rem solid $headerBackground;
border-right: .25rem solid transparent;
border-bottom: .20833rem solid transparent;
}
.table {
border: 0px solid;
}
.toggle-switch input[type=checkbox]:checked+label:before {
border-color: $headerBackground;
background-color: $headerBackground !important;
transition: .15s ease-in;
transition-property: border-color,background-color;
}
.tableCont {
overflow:auto;
margin: 15px 10px 10px 10px;
td {
word-break: break-word;
}
}
.approvalInfo {
display: flex;
justify-content: flex-end
}
.approvalBack {
display: flex;
justify-content: flex-start;
}
@media screen and (max-width:768px) {
.approvalInfo {
display: flex;
justify-content: center;
margin-top: 15px;
}
.approvalBack {
display: flex;
justify-content: center;
margin-bottom: 15px;
}
.card {
margin-top:0rem!important;
min-height: calc(100vh - 0px)!important;
}
.table td.left, .table th.left {
text-align: left;
width: 150px!important;
flex: 0
}
}
.table td.left, .table th.left {
text-align: left;
flex: 1;
width: 300px!important;
}
.tooll {
position: absolute;
background: #e6b3b3;
color: $headerBackground;
top: 0px;
height: 36px;
width: 100%;
left: 0px;
justify-content: center;
align-items: center;
display: flex;
}
#acceptBtn, #rejectBtn {
width: 175px
}
.formatted-values-toggle {
min-width: 75px
}
clr-modal {
::ng-deep {
.modal-body-wrapper {
overflow: auto;
}
}
}
.rows-notice {
display: flex;
align-items: center;
margin-right: 10px;
color: #6a6a6a;
font-size: 15px;
clr-icon {
margin: 0;
}
}

View File

@ -1,6 +1,11 @@
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { SasStoreService } from '../../services/sas-store.service' import { SasStoreService } from '../../services/sas-store.service'
import { Component, AfterViewInit, OnDestroy } from '@angular/core' import {
Component,
AfterViewInit,
OnDestroy,
ViewEncapsulation
} from '@angular/core'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { EventService } from '../../services/event.service' import { EventService } from '../../services/event.service'
@ -8,6 +13,8 @@ import {
AuditorsPostdataSASResponse, AuditorsPostdataSASResponse,
Param Param
} from '../../models/sas/auditors-postdata.model' } from '../../models/sas/auditors-postdata.model'
import { PublicGetChangeinfo } from 'src/app/models/sas/public-getchangeinfo.model'
import { SasService } from 'src/app/services'
interface ChangesObj { interface ChangesObj {
ind: any ind: any
@ -22,7 +29,8 @@ interface ChangesObj {
styleUrls: ['./approve-details.component.scss'], styleUrls: ['./approve-details.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
private _detailsSub: Subscription | undefined private _detailsSub: Subscription | undefined
@ -70,9 +78,11 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
public diffsLimit: boolean = false public diffsLimit: boolean = false
public recordsLimit: number = 100 public recordsLimit: number = 100
public refreshStartupserviceAfterApprove: boolean = false
constructor( constructor(
private sasStoreService: SasStoreService, private sasStoreService: SasStoreService,
private sasService: SasService,
private eventService: EventService, private eventService: EventService,
private router: ActivatedRoute, private router: ActivatedRoute,
private route: Router private route: Router
@ -156,6 +166,9 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
await this.sasStoreService await this.sasStoreService
.approveTable(approveParams, 'SASControlTable', 'auditors/postdata') .approveTable(approveParams, 'SASControlTable', 'auditors/postdata')
.then((res: any) => { .then((res: any) => {
// If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables
if (this.refreshStartupserviceAfterApprove)
this.sasService.reloadStartupData()
this.route.navigateByUrl('/review/history') this.route.navigateByUrl('/review/history')
}) })
.catch((err: any) => { .catch((err: any) => {
@ -170,7 +183,7 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
public async callChangesInfo(tableId: any) { public async callChangesInfo(tableId: any) {
await this.sasStoreService await this.sasStoreService
.getChangeInfo(tableId) .getChangeInfo(tableId)
.then((res: any) => { .then((res: PublicGetChangeinfo) => {
this.tableDetails = res.jsparams[0] this.tableDetails = res.jsparams[0]
this.jsParams = res.jsparams[0] this.jsParams = res.jsparams[0]
@ -183,6 +196,11 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
} }
this.keysArray = keysArray this.keysArray = keysArray
// If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables
// After user approved if armed, reload will be triggered
if (res.jsparams[0].BASE_DS === 'MPE_TABLES')
this.refreshStartupserviceAfterApprove = true
}) })
.catch((err: any) => { .catch((err: any) => {
this.acceptLoading = false this.acceptLoading = false
@ -349,13 +367,12 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
this.params = param this.params = param
this.response = res this.response = res
this.calcDiff() this.calcDiff()
this.callChangesInfo(this.tableId)
}) })
.catch((err: any) => err) .catch((err: any) => err)
.finally(() => { .finally(() => {
this.loadingTable = true this.loadingTable = true
}) })
this.callChangesInfo(this.tableId)
} }
) )
if (typeof this.router.snapshot.params['tableId'] === 'undefined') { if (typeof this.router.snapshot.params['tableId'] === 'undefined') {
@ -378,6 +395,7 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
this.params = param this.params = param
this.response = res this.response = res
this.calcDiff() this.calcDiff()
this.callChangesInfo(this.tableId)
}) })
.catch((err: any) => { .catch((err: any) => {
this.acceptLoading = false this.acceptLoading = false
@ -386,8 +404,6 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
this.loadingTable = true this.loadingTable = true
this.setFocus() this.setFocus()
}) })
this.callChangesInfo(this.tableId)
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -89,6 +89,7 @@
<clr-dg-cell class="p-0 d-flex justify-content-center"> <clr-dg-cell class="p-0 d-flex justify-content-center">
<button <button
class="btn btn-success" class="btn btn-success"
aria-label="Download audit file"
[id]="approveItem.tableId" [id]="approveItem.tableId"
(click)=" (click)="
download(approveItem.tableId); $event.stopPropagation() download(approveItem.tableId); $event.stopPropagation()

View File

@ -1,43 +0,0 @@
@import '../../../colors.scss';
.column-center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.datagrid .datagrid-column .datagrid-column-title{
outline: none!important;
}
.links {
font-weight: 700;cursor: pointer;
}
.tooltip.tooltip-bottom-left>.tooltip-content, .tooltip .tooltip-content.tooltip-bottom-left {
background: $headerBackground !important;
}
.tooltip.tooltip-bottom-left>.tooltip-content:before, .tooltip .tooltip-content.tooltip-bottom-left:before {
border-right: .25rem solid $headerBackground;
border-bottom: .20833rem solid $headerBackground;
}
.noBorder {
border-bottom: 1px solid transparent!important;
}
.approvals-list-wrapper {
height: 70vh;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.noapprovals-info-wrapper {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
height: calc(100vh - 200px);
}

View File

@ -1,4 +1,9 @@
import { Component, OnInit, ChangeDetectorRef } from '@angular/core' import {
Component,
OnInit,
ChangeDetectorRef,
ViewEncapsulation
} from '@angular/core'
import { SasStoreService } from '../../services/sas-store.service' import { SasStoreService } from '../../services/sas-store.service'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { SasService } from '../../services/sas.service' import { SasService } from '../../services/sas.service'
@ -20,7 +25,8 @@ interface ApproveData {
styleUrls: ['./approve.component.scss'], styleUrls: ['./approve.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class ApproveComponent implements OnInit { export class ApproveComponent implements OnInit {
public approveList: Array<ApproveData> | undefined public approveList: Array<ApproveData> | undefined

View File

@ -24,19 +24,19 @@
<a <a
*ngIf="ind < 1" *ngIf="ind < 1"
(click)="getTable(approveData[col])" (click)="getTable(approveData[col])"
class="cursor-pointer" class="cursor-pointer table-link"
>{{ approveData[col] }}</a >{{ approveData[col] }}</a
> >
<div *ngIf="ind < 2 && ind >= 1"> <div *ngIf="ind < 2 && ind >= 1">
<a <a
(click)="getBaseTable(approveData[col])" (click)="getBaseTable(approveData[col])"
class="cursor-pointer" class="cursor-pointer table-link"
>VIEW</a >VIEW</a
> >
<span> / </span> <span> / </span>
<a <a
(click)="getEditTable(approveData[col])" (click)="getEditTable(approveData[col])"
class="cursor-pointer" class="cursor-pointer table-link"
>EDIT</a >EDIT</a
> >
</div> </div>
@ -47,7 +47,12 @@
</table> </table>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="openModal = false"> <button
type="button"
aria-label="Close modal"
class="btn btn-outline"
(click)="openModal = false"
>
OK OK
</button> </button>
</div> </div>
@ -119,6 +124,7 @@
<clr-dg-cell class="verCenter">{{ historyItem.reviewed }}</clr-dg-cell> <clr-dg-cell class="verCenter">{{ historyItem.reviewed }}</clr-dg-cell>
<clr-dg-cell class="verCenter p-0 d-flex justify-content-center"> <clr-dg-cell class="verCenter p-0 d-flex justify-content-center">
<button <button
aria-label="Download audit file"
class="btn btn-success" class="btn btn-success"
(click)="download(historyItem.tableId); $event.stopPropagation()" (click)="download(historyItem.tableId); $event.stopPropagation()"
> >

View File

@ -1,37 +0,0 @@
.rejected {
color: #f83126;
font-weight: bold
}
.accepted {
color: #3fc424;
font-weight: bold
}
.hsCell {
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
padding: 7px;
}
.btCell {
display: flex !important;
justify-content: center !important;
}
.verCenter {
display: flex;
align-items: center;
word-break: break-all;
}
.load-more {
input {
width: 90px;
}
}
#noDataContainer {
height: calc(100vh - 200px);
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { SASjsConfig } from '@sasjs/adapter' import { SASjsConfig } from '@sasjs/adapter'
@ -15,7 +15,8 @@ import {
styleUrls: ['./history.component.scss'], styleUrls: ['./history.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class HistoryComponent implements OnInit { export class HistoryComponent implements OnInit {
public history: Array<any> = [] public history: Array<any> = []

View File

@ -64,7 +64,11 @@
<!-- <clr-dg-cell>{{sub.approver}}</clr-dg-cell> --> <!-- <clr-dg-cell>{{sub.approver}}</clr-dg-cell> -->
<clr-dg-cell>{{ sub.submitReason }}</clr-dg-cell> <clr-dg-cell>{{ sub.submitReason }}</clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>
<div class="row justify-content-around" role="tooltip"> <div
class="row justify-content-around"
role="tooltip"
aria-label="Go to staged data screen"
>
<a <a
class="column-center links tooltip tooltip-md tooltip-bottom-left color-blue" class="column-center links tooltip tooltip-md tooltip-bottom-left color-blue"
(click)="goToStage(sub.tableId)" (click)="goToStage(sub.tableId)"
@ -79,6 +83,7 @@
<clr-dg-cell class="p-0 d-flex justify-content-center"> <clr-dg-cell class="p-0 d-flex justify-content-center">
<button <button
class="btn btn-success" class="btn btn-success"
aria-label="Download audit file for table record"
(click)="download(sub.tableId); $event.stopPropagation()" (click)="download(sub.tableId); $event.stopPropagation()"
> >
<clr-icon shape="download"></clr-icon> <clr-icon shape="download"></clr-icon>

View File

@ -1,17 +0,0 @@
@import '../../../colors.scss';
.noBorder {
border-bottom: 1px solid transparent!important;
}
.tooltip.tooltip-bottom-left>.tooltip-content, .tooltip .tooltip-content.tooltip-bottom-left {
background: $headerBackground !important;
}
.tooltip.tooltip-bottom-left>.tooltip-content:before, .tooltip .tooltip-content.tooltip-bottom-left:before {
border-right: .25rem solid $headerBackground;
border-bottom: .20833rem solid $headerBackground;
}
.no-submitted-tables {
height: calc(100vh - 200px);
}

View File

@ -1,4 +1,9 @@
import { Component, AfterViewInit, OnInit } from '@angular/core' import {
Component,
AfterViewInit,
OnInit,
ViewEncapsulation
} from '@angular/core'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { SasStoreService, EventService, SasService } from '../../services' import { SasStoreService, EventService, SasService } from '../../services'
@ -17,7 +22,8 @@ interface SubmitterData {
styleUrls: ['./submitter.component.scss'], styleUrls: ['./submitter.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class SubmitterComponent implements OnInit, AfterViewInit { export class SubmitterComponent implements OnInit, AfterViewInit {
public remained: number = 0 public remained: number = 0

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { globals } from '../_globals' import { globals } from '../_globals'
import { HelperService } from '../services/helper.service' import { HelperService } from '../services/helper.service'
import { Location } from '@angular/common' import { Location } from '@angular/common'
@ -12,7 +12,8 @@ import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapper
styleUrls: ['./role.component.scss'], styleUrls: ['./role.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class RoleComponent implements OnInit { export class RoleComponent implements OnInit {
public roles: Array<any> | undefined public roles: Array<any> | undefined

View File

@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core' import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-home-route', selector: 'app-home-route',
@ -6,7 +6,8 @@ import { Component, OnInit, OnDestroy } from '@angular/core'
styleUrls: ['./home-route.component.scss'], styleUrls: ['./home-route.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class HomeRouteComponent implements OnInit, OnDestroy { export class HomeRouteComponent implements OnInit, OnDestroy {
constructor() {} constructor() {}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-review-route', selector: 'app-review-route',
@ -6,7 +6,8 @@ import { Component, OnInit } from '@angular/core'
styleUrls: ['./review-route.component.scss'], styleUrls: ['./review-route.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class ReviewRouteComponent implements OnInit { export class ReviewRouteComponent implements OnInit {
constructor() {} constructor() {}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-usernav-route', selector: 'app-usernav-route',
@ -6,7 +6,8 @@ import { Component, OnInit } from '@angular/core'
styleUrls: ['./usernav-route.component.scss'], styleUrls: ['./usernav-route.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class UsernavRouteComponent implements OnInit { export class UsernavRouteComponent implements OnInit {
constructor() {} constructor() {}

View File

@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core' import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-view-route', selector: 'app-view-route',
@ -6,7 +6,8 @@ import { Component, OnInit, OnDestroy } from '@angular/core'
styleUrls: ['./view-route.component.scss'], styleUrls: ['./view-route.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class ViewRouteComponent implements OnInit, OnDestroy { export class ViewRouteComponent implements OnInit, OnDestroy {
constructor() {} constructor() {}

View File

@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core' import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'app-xlmap-route', selector: 'app-xlmap-route',
@ -6,7 +6,8 @@ import { Component, OnInit, OnDestroy } from '@angular/core'
styleUrls: ['./xlmap-route.component.scss'], styleUrls: ['./xlmap-route.component.scss'],
host: { host: {
class: 'content-container' class: 'content-container'
} },
encapsulation: ViewEncapsulation.None
}) })
export class XLMapRouteComponent implements OnInit, OnDestroy { export class XLMapRouteComponent implements OnInit, OnDestroy {
constructor() {} constructor() {}

View File

@ -1,6 +1,7 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import cloneDeep from 'lodash-es/cloneDeep' import cloneDeep from 'lodash-es/cloneDeep'
import * as CryptoMD5 from 'crypto-js/md5' import * as CryptoMD5 from 'crypto-js/md5'
import { SasService } from './sas.service'
const librariesToShow = 50 const librariesToShow = 50
@ -12,7 +13,7 @@ export class HelperService {
public loadMoreCount: number = librariesToShow public loadMoreCount: number = librariesToShow
public isMicrosoft: boolean = false public isMicrosoft: boolean = false
constructor() { constructor(private sasService: SasService) {
this.isMicrosoft = this.isIEorEDGE() this.isMicrosoft = this.isIEorEDGE()
console.log('Is IE or Edge?', this.isMicrosoft) console.log('Is IE or Edge?', this.isMicrosoft)
} }
@ -314,6 +315,20 @@ export class HelperService {
} }
} }
public isStreamingViya(): boolean {
const serverType = this.sasService.getServerType()
if (serverType !== 'SASVIYA') return false
if (
location.search.toLowerCase().includes('?_file=') &&
location.pathname.toLowerCase().includes('/sasjobexecution')
)
return true
return false
}
// Required type is NodeJS.Timeout // Required type is NodeJS.Timeout
// But NodeJS is not available in browser so we have to go with any // But NodeJS is not available in browser so we have to go with any
private debounceTimeout: any private debounceTimeout: any

View File

@ -223,7 +223,7 @@ export class SasStoreService {
tables[tableName] = [tableData] tables[tableName] = [tableData]
return ( return (
await this.sasService.request(program, tables, { await this.sasService.request(program, tables, {
useComputeApi: false useComputeApi: null // Using WEB APPROACH as a temporary workaround until VIYA JES API is fixed. For other server types then VIYA this is not applicable
}) })
).adapterResponse ).adapterResponse
} }
@ -232,7 +232,7 @@ export class SasStoreService {
tables[tableName] = [tableData] tables[tableName] = [tableData]
return ( return (
await this.sasService.request(program, tables, { await this.sasService.request(program, tables, {
useComputeApi: false useComputeApi: null // Using WEB APPROACH as a temporary workaround until VIYA JES API is fixed. For other server types then VIYA this is not applicable
}) })
).adapterResponse ).adapterResponse
} }

View File

@ -1,9 +1,21 @@
import { HttpClient } from '@angular/common/http' import {
HttpClient,
HttpContext,
HttpErrorResponse,
HttpHeaders,
HttpParams
} from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Observable } from 'rxjs' import { catchError, Observable, throwError } from 'rxjs'
import { Collection } from '../viya-api-explorer/models/collection.model' import { Collection } from '../viya-api-explorer/models/collection.model'
import { AppStoreService } from './app-store.service' import { AppStoreService } from './app-store.service'
import { ViyaApis } from '../viya-api-explorer/models/viya-apis.models' import { ViyaApis } from '../viya-api-explorer/models/viya-apis.models'
import { ViyaApiFolderMembers } from '../viya-api-explorer/models/viya-api-folder-content.model'
import { ViyaApiFolder } from '../viya-api-explorer/models/viya-api-folder.model'
import { ViyaApiIdentities } from '../viya-api-explorer/models/viya-api-identities.model'
import { ViyaApiCurrentUser } from '../viya-api-explorer/models/viya-api-current-user.model'
import { ViyaComputeContexts } from '../viya-api-explorer/models/viya-compute-contexts.model'
import { ComputeContextDetails } from '../viya-api-explorer/models/viya-compute-context-details.model'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -22,7 +34,8 @@ export class SasViyaService {
}, },
Compute: { Compute: {
jobs: '/jobDefinitions', jobs: '/jobDefinitions',
jobExecution: '/jobExecution' jobExecution: '/jobExecution',
contexts: '/compute/contexts'
}, },
Decision_Management: { Decision_Management: {
modelManagement: '/modelManagement', modelManagement: '/modelManagement',
@ -57,15 +70,23 @@ export class SasViyaService {
constructor( constructor(
private http: HttpClient, private http: HttpClient,
private appStoreService: AppStoreService private appStoreService: AppStoreService
) { ) {}
/**
* This function is replacing the constructor.
* The reason for this is timing issues, other services eg. sas.service, app-store.service
* must be initialized before this bit of code is executed.
* This function is being called by `sas.service`
*/
setup() {
const adapterConfig = this.appStoreService.getDcAdapterSettings() const adapterConfig = this.appStoreService.getDcAdapterSettings()
this.serverUrl = adapterConfig?.serverUrl || '' this.serverUrl = adapterConfig?.serverUrl || ''
//example // example collection request
this.getByCollection('jobs').subscribe((res) => { // this.getByCollection('jobs').subscribe((res) => {
console.log('res', res) // console.log('res', res)
}) // })
} }
/** /**
@ -82,7 +103,7 @@ export class SasViyaService {
* @returns * @returns
*/ */
getByUrl(url: string): Observable<Collection> { getByUrl(url: string): Observable<Collection> {
return this.http.get<Collection>(`${this.serverUrl}${url}`, { return this.get<Collection>(`${this.serverUrl}${url}`, {
withCredentials: true withCredentials: true
}) })
} }
@ -93,8 +114,106 @@ export class SasViyaService {
* @returns * @returns
*/ */
getByCollection(apiCollection: string): Observable<Collection> { getByCollection(apiCollection: string): Observable<Collection> {
return this.http.get<Collection>(`${this.serverUrl}${apiCollection}`, { return this.get<Collection>(`${this.serverUrl}${apiCollection}`, {
withCredentials: true withCredentials: true
}) })
} }
getComputeContexts(): Observable<ViyaComputeContexts> {
return this.get<ViyaComputeContexts>(`${this.serverUrl}/compute/contexts`, {
withCredentials: true
})
}
getComputeContextById(id: string): Observable<ComputeContextDetails> {
return this.get<ComputeContextDetails>(
`${this.serverUrl}/compute/contexts/${id}`,
{
withCredentials: true
}
)
}
/**
* @param path Path to the folder
* @returns The folder info object
*/
getFolderByPath(path: string): Observable<ViyaApiFolder> {
return this.get<ViyaApiFolder>(
`${this.serverUrl}/folders/folders/@item?path=${path}`,
{
withCredentials: true
}
)
}
getFolderMembers(folderId: string): Observable<ViyaApiFolderMembers> {
return this.get<ViyaApiFolderMembers>(
`${this.serverUrl}/folders/folders/${folderId}/members`,
{
withCredentials: true
}
)
}
getAdminGroups(limit: number = 5000): Observable<ViyaApiIdentities> {
return this.get<ViyaApiIdentities>(
`${this.serverUrl}/identities/groups?sortBy=name&limit=${limit}`,
{
withCredentials: true
}
)
}
getCurrentUser(): Observable<ViyaApiCurrentUser> {
return this.get<ViyaApiCurrentUser>(
`${this.serverUrl}/identities/users/@currentUser`,
{
withCredentials: true
}
)
}
get<T>(
url: string,
options?: {
headers?:
| HttpHeaders
| {
[header: string]: string | string[]
}
context?: HttpContext
observe?: 'body'
params?:
| HttpParams
| {
[param: string]:
| string
| number
| boolean
| ReadonlyArray<string | number | boolean>
}
reportProgress?: boolean
responseType?: 'json'
withCredentials?: boolean
transferCache?:
| {
includeHeaders?: string[]
}
| boolean
}
): Observable<T> {
return this.http.get<T>(url, options).pipe(
catchError((err: HttpErrorResponse) => {
console.log('url', url)
console.log('err.status', err.status)
if (err.status === 449 || err.status === 401) {
// Retry once if we got a 449
return this.http.get<T>(url, options)
}
// Otherwise propagate the error
return throwError(() => err)
})
)
}
} }

View File

@ -16,6 +16,9 @@ import { RequestWrapperOptions } from '../models/request-wrapper/RequestWrapperO
import { ErrorBody } from '../models/ErrorBody' import { ErrorBody } from '../models/ErrorBody'
import { UploadFileResponse } from '../models/UploadFile' import { UploadFileResponse } from '../models/UploadFile'
import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse'
import { SasViyaService } from './sas-viya.service'
import { ViyaApiFolder } from '../viya-api-explorer/models/viya-api-folder.model'
import { ViyaApiFolderMembers } from '../viya-api-explorer/models/viya-api-folder-content.model'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -38,6 +41,7 @@ export class SasService {
private userService: UserService, private userService: UserService,
private eventService: EventService, private eventService: EventService,
private sasjsService: SasjsService, private sasjsService: SasjsService,
private sasViyaService: SasViyaService,
private loggerService: LoggerService, private loggerService: LoggerService,
private router: Router private router: Router
) {} ) {}
@ -51,6 +55,7 @@ export class SasService {
this.dcAdapterSettings = this.appStoreService.getDcAdapterSettings() this.dcAdapterSettings = this.appStoreService.getDcAdapterSettings()
this.sasjsService.setup() this.sasjsService.setup()
this.sasViyaService.setup()
if (!this.dcAdapterSettings) { if (!this.dcAdapterSettings) {
this.eventService.showInfoModal( this.eventService.showInfoModal(
@ -328,6 +333,10 @@ export class SasService {
}) })
} }
public reloadStartupData() {
this.loadStartupServiceEmitter.emit()
}
public getLicenseSiteId(): string[] { public getLicenseSiteId(): string[] {
return this.license_site_id.value || [] return this.license_site_id.value || []
} }
@ -423,21 +432,93 @@ export class SasService {
typeof this.sasjsAdapter.getFolder !== 'undefined' typeof this.sasjsAdapter.getFolder !== 'undefined'
let appLocExists: boolean = false let appLocExists: boolean = false
let errorMessage: string | undefined = undefined
if (getFolderExistsInAdapter) { if (getFolderExistsInAdapter) {
appLocExists = await this.appLocCheck(path) const results = await this.appLocCheck(path)
appLocExists = results.found
errorMessage = results.errorMessage
} else { } else {
appLocExists = await this.appLocCheckPreAxiosdAdapter(path) appLocExists = await this.appLocCheckPreAxiosdAdapter(path)
} }
if (appLocExists) { if (appLocExists) {
this.loadStartupServiceEmitter.emit() // Check if there is appLoc/services/admin/makedata.sas present
// if yes, it needs to be run, so we redirect to /deploy
// if not, we load the startup service
this.viyaMakedataSuccessfull().then(
(success: boolean) => {
if (success) {
this.loadStartupServiceEmitter.emit()
} else {
this.eventService.startupDataLoaded()
this.router.navigateByUrl('/deploy')
}
},
(error: any) => {
console.error('Error while looking for the file: makedata.sas', error)
}
)
} else {
const errorMessageToShow =
(errorMessage ||
'Viya services are not present on the current appLoc, or API not reachable. Check the ADAPTER configuration.') +
`\nAppLoc: ${path}`
this.eventService.showInfoModal('Error', errorMessageToShow)
} }
} }
public appLocCheck(path: string): Promise<boolean> { private async viyaMakedataSuccessfull(): Promise<boolean> {
return new Promise((resolve, reject) => {
const sasjsConfig = this.getSasjsConfig()
const configuratorFolder = `${sasjsConfig.appLoc}/services/admin`
this.sasViyaService.getFolderByPath(configuratorFolder).subscribe(
(folderInfo: ViyaApiFolder) => {
const folderId = folderInfo.id
if (!folderId) {
console.error(
`Folder ID is not present. ${configuratorFolder}`,
sasjsConfig
)
resolve(false)
}
this.sasViyaService.getFolderMembers(folderId).subscribe(
(members: ViyaApiFolderMembers) => {
if (
!members.items.some((item: any) => item.name === 'makedata')
) {
// Makedata.sas is not present, which means it was run
resolve(true)
} else {
// Makedata.sas is present, which means it was not run
resolve(false)
}
},
(err: any) => {
console.error('Error getting folder contents', err)
reject()
}
)
},
(err: any) => {
console.warn('Error getting folder info', err)
reject(err)
}
)
})
}
public appLocCheck(
path: string
): Promise<{ found: boolean; errorMessage?: string }> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let statusNotFound: boolean = false let fetchError: string = ''
let res: any let res: any
@ -448,20 +529,21 @@ export class SasService {
this.appLocCheckPending = true this.appLocCheckPending = true
this.shouldLogin.next(true) this.shouldLogin.next(true)
resolve(false) resolve({ found: false })
} else if (err.name === 'NotFoundeError') {
fetchError = err.message
} else { } else {
statusNotFound = true fetchError =
'Viya services are not present on the current appLoc, or API not reachable. Check the ADAPTER configuration.'
} }
} }
if (statusNotFound) { if (fetchError.length) {
console.warn('Viya services are not present on the current appLoc.') console.warn(fetchError)
this.eventService.startupDataLoaded() return resolve({ found: false, errorMessage: fetchError })
this.router.navigateByUrl('/deploy')
return resolve(false)
} }
resolve(true) resolve({ found: true })
}) })
} }
@ -579,4 +661,17 @@ export class SasService {
} }
} }
} }
// Viya specific functions
public getFileContent(folderPath: string, fileName: string) {
return this.sasjsAdapter.getFileContent(folderPath, fileName)
}
public updateFileContent(
folderPath: string,
fileName: string,
content: string
) {
return this.sasjsAdapter.updateFileContent(folderPath, fileName, content)
}
} }

View File

@ -7,7 +7,10 @@
> >
<h3 class="modal-title"> <h3 class="modal-title">
{{ data.modalTitle }} {{ data.modalTitle }}
<p *ngIf="data.sasService && data.sasService.length > 0" class="sasService"> <p
*ngIf="data.sasService && data.sasService.length > 0"
class="sasService mt-0"
>
SAS Service: <strong>{{ data.sasService }}</strong> SAS Service: <strong>{{ data.sasService }}</strong>
</p> </p>
</h3> </h3>

View File

@ -1,43 +0,0 @@
.clr-abort-modal {
::ng-deep {
.modal {
z-index: 2050;
}
.modal-title-wrapper {
width: 100%;
}
.modal {
z-index: 2050;
}
}
}
.modal-title {
position: relative;
}
.sasService {
position: absolute;
top: 0px;
right: 10px;
margin: 0;
}
.modal-footer {
position: relative;
border-top: 1px solid #dcdcdc;
}
.systext {
overflow: auto;
margin-top: 20px;
padding: 10px 0;
border-top: 1px solid #dcdcdc;
p {
margin-top: 0;
word-wrap: break-word;
}
}

View File

@ -1,4 +1,11 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { ServerType } from '@sasjs/utils/types/serverType' import { ServerType } from '@sasjs/utils/types/serverType'
import { EventService } from 'src/app/services/event.service' import { EventService } from 'src/app/services/event.service'
@ -9,7 +16,8 @@ import { AbortDetails, InfoModal } from '../../models/InfoModal'
@Component({ @Component({
selector: 'app-info-modal', selector: 'app-info-modal',
templateUrl: './info-modal.component.html', templateUrl: './info-modal.component.html',
styleUrls: ['./info-modal.component.scss'] styleUrls: ['./info-modal.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class InfoModalComponent implements OnInit { export class InfoModalComponent implements OnInit {
@Output() onConfirmModalClick: EventEmitter<any> = new EventEmitter() @Output() onConfirmModalClick: EventEmitter<any> = new EventEmitter()

View File

@ -1,3 +0,0 @@
clr-alerts {
display: block;
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { Alert } from './alert' import { Alert } from './alert'
import { AlertsService } from './alerts.service' import { AlertsService } from './alerts.service'
@ -6,7 +6,8 @@ import { AlertsService } from './alerts.service'
@Component({ @Component({
selector: 'app-alerts', selector: 'app-alerts',
templateUrl: './alerts.component.html', templateUrl: './alerts.component.html',
styleUrls: ['./alerts.component.scss'] styleUrls: ['./alerts.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class AlertsComponent implements OnInit { export class AlertsComponent implements OnInit {
public alerts: Array<Alert> = [] public alerts: Array<Alert> = []

View File

@ -1,75 +0,0 @@
.input-val {
border: 0px;
background: transparent;
border-bottom: 1px solid #999999;
}
input {
width: 100%;
outline: none;
&::-webkit-calendar-picker-indicator {
margin-top: -5px;
}
}
::ng-deep {
body[cds-theme="dark"] {
.datalist {
background: #21333b;
border: 1px solid #575757;
}
input {
color: #fff;
}
.datalist option {
color: #fff
}
}
body[cds-theme="light"] {
.datalist {
background: #fff;
}
}
}
.autocomplete-wrapper {
.overlay {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1500;
}
.datalist {
position: fixed;
box-shadow: 0px 3px 10px -1px #0000002b;
overflow: auto;
z-index: 2000;
::ng-deep {
option {
padding: 5px 10px;
cursor: pointer;
&:hover {
background: #0000000f;
}
&.focused {
background: #0000000f;
}
}
}
}
.load-more {
text-align: center;
border-top: 1px solid #e6e6e6;
}
}

View File

@ -7,7 +7,8 @@ import {
Input, Input,
OnInit, OnInit,
Output, Output,
ViewChild ViewChild,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
export type OnLoadingMoreEvent = { export type OnLoadingMoreEvent = {
@ -17,7 +18,8 @@ export type OnLoadingMoreEvent = {
@Component({ @Component({
selector: 'app-autocomplete', selector: 'app-autocomplete',
templateUrl: './autocomplete.component.html', templateUrl: './autocomplete.component.html',
styleUrls: ['./autocomplete.component.scss'] styleUrls: ['./autocomplete.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class AutocompleteComponent implements OnInit, AfterViewInit { export class AutocompleteComponent implements OnInit, AfterViewInit {
@ViewChild('input') inputElement: any @ViewChild('input') inputElement: any

View File

@ -1,3 +0,0 @@
.unset {
color: unset;
}

View File

@ -1,9 +1,10 @@
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'
@Component({ @Component({
selector: 'contact-link', selector: 'contact-link',
templateUrl: './contact-link.component.html', templateUrl: './contact-link.component.html',
styleUrls: ['./contact-link.component.scss'] styleUrls: ['./contact-link.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class ContactLinkComponent implements OnInit { export class ContactLinkComponent implements OnInit {
@Input() classes: string = '' @Input() classes: string = ''

View File

@ -1,35 +0,0 @@
.modal-body {
clr-tabs {
max-height: 70vh;
}
::ng-deep {
.tab-content {
width: 100%;
overflow: auto;
.datagrid-outer-wrapper {
width: 100%;
}
}
}
}
clr-modal {
::ng-deep {
.modal-dialog {
height: 100%;
}
}
}
.clickable-row {
cursor: pointer;
}
::ng-deep {
.datagrid-table .datagrid-cell:focus {
outline: none;
outline-offset: 0;
}
}

View File

@ -5,7 +5,8 @@ import {
OnChanges, OnChanges,
OnInit, OnInit,
Output, Output,
SimpleChanges SimpleChanges,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { DSMeta, Version } from 'src/app/models/sas/editors-getdata.model' import { DSMeta, Version } from 'src/app/models/sas/editors-getdata.model'
import { Tab } from './models/dsmeta-groupped.model' import { Tab } from './models/dsmeta-groupped.model'
@ -13,7 +14,8 @@ import { Tab } from './models/dsmeta-groupped.model'
@Component({ @Component({
selector: 'app-dataset-info', selector: 'app-dataset-info',
templateUrl: './dataset-info.component.html', templateUrl: './dataset-info.component.html',
styleUrls: ['./dataset-info.component.scss'] styleUrls: ['./dataset-info.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class DatasetInfoComponent implements OnInit, OnChanges { export class DatasetInfoComponent implements OnInit, OnChanges {
@Input() open: boolean = false @Input() open: boolean = false

View File

@ -1,17 +0,0 @@
clr-tree-node button {
white-space: nowrap;
}
clr-tree {
::ng-deep {
.clr-tree-node-content-container {
&:focus {
.clr-treenode-link {
background: #e8e8e8;
background: var(--clr-tree-link-hover-color, #e8e8e8);
text-decoration: none;
}
}
}
}
}

View File

@ -9,7 +9,8 @@ import {
Output, Output,
QueryList, QueryList,
SimpleChanges, SimpleChanges,
ViewChildren ViewChildren,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { HelperService } from 'src/app/services/helper.service' import { HelperService } from 'src/app/services/helper.service'
import { LicenceService } from 'src/app/services/licence.service' import { LicenceService } from 'src/app/services/licence.service'
@ -20,7 +21,8 @@ import { TableClickEmitter } from './models/TableClickEmitter'
@Component({ @Component({
selector: 'dc-tree', selector: 'dc-tree',
templateUrl: './dc-tree.component.html', templateUrl: './dc-tree.component.html',
styleUrls: ['./dc-tree.component.scss'] styleUrls: ['./dc-tree.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class DcTreeComponent implements OnInit, AfterViewInit, OnChanges { export class DcTreeComponent implements OnInit, AfterViewInit, OnChanges {
// REFACTOR NOTICE // REFACTOR NOTICE

View File

@ -1,18 +0,0 @@
.excel-password-root {
::ng-deep {
.modal {
z-index: 1060;
}
}
}
.modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
.buttons {
display: flex;
gap: 5px;
}
}

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, ViewEncapsulation } from '@angular/core'
import { Observable } from 'rxjs' import { Observable } from 'rxjs'
import { ExcelPasswordModalService } from './excel-password-modal.service' import { ExcelPasswordModalService } from './excel-password-modal.service'
import { Options } from './models/options.interface' import { Options } from './models/options.interface'
@ -6,7 +6,8 @@ import { Options } from './models/options.interface'
@Component({ @Component({
selector: 'app-excel-password-modal', selector: 'app-excel-password-modal',
styleUrls: ['./excel-password-modal.component.scss'], styleUrls: ['./excel-password-modal.component.scss'],
templateUrl: './excel-password-modal.component.html' templateUrl: './excel-password-modal.component.html',
encapsulation: ViewEncapsulation.None
}) })
export class ExcelPasswordModalComponent { export class ExcelPasswordModalComponent {
options$: Observable<Options> = this.excelPasswordModalService.optionsSubject$ options$: Observable<Options> = this.excelPasswordModalService.optionsSubject$

View File

@ -1,53 +0,0 @@
// there are no clear instructions how to use Clarity ui variables
$clr-header-height: 2.5rem;
$clr-dark-gray: #565656;
$clr-red: #c92100;
$clr-yellow: rgb(233, 191, 4);
$clr-green: #60b515;
.loading-indicator {
line-height: $clr-header-height;
height: $clr-header-height;
display: flex;
align-items: center;
height: 100%;
margin-right: 10px;
.spinner {
vertical-align: middle;
}
clr-signpost-content {
line-height: 24px;
color: $clr-dark-gray;
cursor: auto;
p {
margin-top: 10px;
display: flex;
justify-content: space-between;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
span {
margin-left: 10px;
&.running {
color: $clr-yellow;
}
&.success {
color: $clr-green;
}
&.fail {
color: $clr-red;
}
}
}
}
}

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { Service } from '../service.interface' import { Service } from '../service.interface'
@ -6,7 +6,8 @@ import { Service } from '../service.interface'
@Component({ @Component({
selector: 'app-loading-indicator', selector: 'app-loading-indicator',
templateUrl: './loading-indicator.component.html', templateUrl: './loading-indicator.component.html',
styleUrls: ['./loading-indicator.component.scss'] styleUrls: ['./loading-indicator.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class LoadingIndicatorComponent implements OnInit, OnDestroy { export class LoadingIndicatorComponent implements OnInit, OnDestroy {
public loading: boolean = false public loading: boolean = false

View File

@ -1,13 +1,17 @@
<div class="login-sidebar-wrapper" [class.active]="isActive"> <div class="login-sidebar-wrapper" [class.active]="isActive">
<div class="login-sidebar sideBarProps"> <div class="login-sidebar sideBarProps">
<!--img src="images/data_controller.png" alt=""--> <!--img src="images/data_controller.png" alt=""-->
<img class="login-logo" src="images/datacontroller.svg" alt="" /> <img
class="login-logo"
src="images/datacontroller.svg"
alt="datacontroller logo"
/>
<form class="login" (ngSubmit)="submit()"> <form class="login" (ngSubmit)="submit()">
<label class="title"> <label class="title">
<h3 class="welcome">Welcome to</h3> <h3 class="welcome">Welcome to</h3>
Data Controller Data Controller
<h5 class="hint">Capture, Review, and Approve</h5> <h4 class="hint">Capture, Review, and Approve</h4>
</label> </label>
<div class="login-group"> <div class="login-group">
<input <input

View File

@ -1,129 +0,0 @@
@import '../../../colors.scss';
.sideBarProps {
background: $headerBackground !important;
color: #e0e0e0;
}
.sideBarProps h2, .sideBarProps h3, .sideBarProps h4, .sideBarProps h5, .sideBarProps input {
color: #e0e0e0;
}
.sideBarProps button {
border-color: wheat!important;
}
.sideBarProps a {
color: #e0e0e0;
}
.login-sidebar-wrapper {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
pointer-events: none;
z-index: 10000;
>* {
pointer-events: auto;
}
.login-sidebar {
width: 400px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
background: #fff;
border-right: 1px solid #ddd;
padding: 40px;
form.login {
z-index: 101;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
.title {
font-size: 32px;
letter-spacing: normal;
line-height: 36px;
.welcome {
margin-top: 36px;
}
}
.login-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
padding: 48px 0 0 0;
>* {
margin: 6px 0 18px 0;
}
}
}
-webkit-transform: translateX(-400px);
transform: translateX(-400px);
transition: -webkit-transform .3s ease;
transition: transform .3s ease;
transition: transform .3s ease, -webkit-transform .3s ease;
}
&.active {
.login-sidebar {
-webkit-transform: translateX(0);
transform: translateX(0);
z-index: 101;
}
.overlay {
display: block;
}
}
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba(33, 33, 33, .5);
z-index: 100;
}
}
::ng-deep .login-sidebar-wrapper .login-group {
.clr-control-container, .username, .password {
width: 100%;
}
.clr-input-wrapper {
max-width: none;
}
button {
max-width: none;
}
}
.login-logo {
max-width: 200px
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core' import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'
import { LoggerService } from '../../services/logger.service' import { LoggerService } from '../../services/logger.service'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
@ -12,7 +12,8 @@ interface User {
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
templateUrl: './login.component.html', templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'] styleUrls: ['./login.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class LoginComponent implements OnInit, OnDestroy { export class LoginComponent implements OnInit, OnDestroy {
private _subscription: Subscription = new Subscription() private _subscription: Subscription = new Subscription()

View File

@ -86,9 +86,17 @@
</clr-tree> </clr-tree>
<div <div
*ngIf="serverType !== 'SASVIYA'"
class="log-wrapper saslog" class="log-wrapper saslog"
[innerHTML]="programLog.logFile" [innerHTML]="programLog.logFile"
></div> ></div>
<div
*ngIf="serverType === 'SASVIYA'"
class="log-wrapper saslog viya"
[textContent]="programLog.logFile"
></div>
<button <button
*ngIf="programLog.logFile?.length! > 0" *ngIf="programLog.logFile?.length! > 0"
(click)="downloadLog(programLog.logFile)" (click)="downloadLog(programLog.logFile)"

View File

@ -1,68 +0,0 @@
::ng-deep {
.requests-modal .modal-header .close clr-icon {
display: block !important;
}
.requests-modal .modal-content {
padding: 20px 10px 5px 10px;
}
.work-tables-dropdown button {
color: var(--clr-nav-link-color, #8c8c8c) !important;
}
.stack-view {
height: auto !important;
//Following lines will fix clarity (requests modal white) issue.
//Clarity version that has issue is: v12
mask-image: none !important;
-webkit-mask-image: none !important;
}
.content {
clr-icon {
margin-bottom: 5px;
}
pre {
word-break: break-all;
white-space: pre-wrap;
max-height: initial;
overflow: visible;
border: 0;
}
.stack-block-label {
// Clarity before V3 -----
// display: none;
// Clarity V3 -----
width: 100%;
padding-left: .6rem !important;
.stack-view-key {
display: none !important;
}
}
}
.err-links {
.clr-treenode-children {
max-height: 55px;
overflow: auto;
}
}
}
.dropdown-item {
&.selected {
background: #d8e3e9;
}
}
.no-reqs {
border-top: 1px solid #0000001a;
padding-top: 5px;
text-align: center;
}

View File

@ -1,10 +1,17 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core'
import { SASjsRequest } from '@sasjs/adapter' import { SASjsRequest } from '@sasjs/adapter'
import * as moment from 'moment' import * as moment from 'moment'
import { HelperService } from 'src/app/services/helper.service' import { HelperService } from 'src/app/services/helper.service'
import { LoggerService } from '../../services/logger.service' import { LoggerService } from '../../services/logger.service'
import { SasService } from '../../services/sas.service' import { SasService } from '../../services/sas.service'
import { ServerType } from '@sasjs/utils/types/serverType'
interface SASjsRequestExtended extends SASjsRequest { interface SASjsRequestExtended extends SASjsRequest {
parsedTimestamp?: string parsedTimestamp?: string
logErrors?: string[] logErrors?: string[]
@ -15,7 +22,8 @@ interface SASjsRequestExtended extends SASjsRequest {
@Component({ @Component({
selector: 'app-requests-modal', selector: 'app-requests-modal',
templateUrl: './requests-modal.component.html', templateUrl: './requests-modal.component.html',
styleUrls: ['./requests-modal.component.scss'] styleUrls: ['./requests-modal.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class RequestsModalComponent implements OnInit { export class RequestsModalComponent implements OnInit {
private _opened: boolean = false private _opened: boolean = false
@ -38,6 +46,7 @@ export class RequestsModalComponent implements OnInit {
public tablesActive: boolean = false public tablesActive: boolean = false
public sasjsConfig = this.sasService.getSasjsConfig() public sasjsConfig = this.sasService.getSasjsConfig()
public serverType: string
public sasjsRequests: SASjsRequestExtended[] = [] public sasjsRequests: SASjsRequestExtended[] = []
public workTables: any public workTables: any
@ -45,7 +54,10 @@ export class RequestsModalComponent implements OnInit {
private sasService: SasService, private sasService: SasService,
private loggerService: LoggerService, private loggerService: LoggerService,
private helperService: HelperService private helperService: HelperService
) {} ) {
this.sasjsConfig = this.sasService.getSasjsConfig()
this.serverType = this.sasService.getServerType()
}
ngOnInit(): void {} ngOnInit(): void {}
@ -90,21 +102,81 @@ export class RequestsModalComponent implements OnInit {
requestStackId: string, requestStackId: string,
type: string type: string
) { ) {
let allLines: any = document.querySelectorAll( const logWrapper: HTMLElement | null = document.querySelector(
`#${requestStackId} .log-wrapper.saslog font`
)
let logWrapper: any = document.querySelector(
`#${requestStackId} .log-wrapper.saslog` `#${requestStackId} .log-wrapper.saslog`
) )
for (let line of allLines) { if (!logWrapper) return
if (line.textContent.includes(linkingLine)) {
logWrapper.scrollTop = line.offsetTop - logWrapper.offsetTop
line.style.backgroundColor = '#61a2202b'
setTimeout(() => { if (this.serverType === 'SASVIYA') {
line.style = '' // For VIYA (textContent approach)
}, 3000) const logContent = logWrapper.textContent || ''
const logLines = logContent.split('\n')
let lineIndex = -1
// Find the matching line index
for (let i = 0; i < logLines.length; i++) {
if (logLines[i].includes(linkingLine)) {
lineIndex = i
break
}
}
if (lineIndex === -1) return
// Create a temporary div to calculate line height
const tempDiv = document.createElement('div')
tempDiv.className = 'temp-line-height-calc'
tempDiv.textContent = 'X'
logWrapper.appendChild(tempDiv)
const lineHeight = tempDiv.clientHeight
logWrapper.removeChild(tempDiv)
// Scroll to the appropriate position
logWrapper.scrollTop = lineHeight * lineIndex
// Create highlighting overlay at that position
const overlay = document.createElement('div')
overlay.className = `line-highlight-overlay ${type === 'error' ? 'error-highlight' : 'warning-highlight'}`
// We are setting the height using a CSS variable to the HTML element
// this does not trigger CSP errors because it's driven by JS
overlay.classList.add('temp-height-setter')
document.documentElement.style.setProperty(
'--line-height',
`${lineHeight}px`
)
overlay.classList.add('line-position-setter')
document.documentElement.style.setProperty(
'--line-top',
`${lineHeight * lineIndex}px`
)
logWrapper.appendChild(overlay)
setTimeout(() => {
if (logWrapper.contains(overlay)) {
logWrapper.removeChild(overlay)
}
}, 3000)
} else {
// For non-VIYA (innerHTML approach)
const allLines: NodeListOf<Element> = document.querySelectorAll(
`#${requestStackId} .log-wrapper.saslog font`
)
for (let line of Array.from(allLines)) {
if (line.textContent?.includes(linkingLine)) {
logWrapper.scrollTop =
(line as HTMLElement).offsetTop - logWrapper.offsetTop
// Use class instead of inline style
line.classList.add('highlighted-line')
setTimeout(() => {
line.classList.remove('highlighted-line')
}, 3000)
break
}
} }
} }
} }
@ -117,7 +189,9 @@ export class RequestsModalComponent implements OnInit {
let errorLines = [] let errorLines = []
let warningLines = [] let warningLines = []
// Create a safe version of the log content
let logLines = req.logFile.split('\n') let logLines = req.logFile.split('\n')
let originalLogLines = [...logLines]
for (let i = 0; i < logLines.length; i++) { for (let i = 0; i < logLines.length; i++) {
if (/<.*>ERROR/gm.test(logLines[i])) { if (/<.*>ERROR/gm.test(logLines[i])) {
@ -129,7 +203,9 @@ export class RequestsModalComponent implements OnInit {
} else if (/^ERROR/gm.test(logLines[i])) { } else if (/^ERROR/gm.test(logLines[i])) {
errorLines.push(logLines[i]) errorLines.push(logLines[i])
logLines[i] = '<font>' + logLines[i] + '</font>' if (this.serverType !== 'SASVIYA') {
logLines[i] = '<font class="error-line">' + logLines[i] + '</font>'
}
} }
if (/<.*>WARNING/gm.test(logLines[i])) { if (/<.*>WARNING/gm.test(logLines[i])) {
@ -141,12 +217,41 @@ export class RequestsModalComponent implements OnInit {
} else if (/^WARNING/gm.test(logLines[i])) { } else if (/^WARNING/gm.test(logLines[i])) {
warningLines.push(logLines[i]) warningLines.push(logLines[i])
logLines[i] = '<font>' + logLines[i] + '</font>' if (this.serverType !== 'SASVIYA') {
logLines[i] = '<font class="warning-line">' + logLines[i] + '</font>'
}
} }
} }
this.loggerService.log(warningLines) this.loggerService.log(warningLines)
// For VIYA, store both versions of the log
if (this.serverType === 'SASVIYA') {
req.originalLogFile = originalLogLines.join('\n')
req.logFileLineMap = {}
// Create a mapping of error/warning lines to their indices
errorLines.forEach((errorLine) => {
for (let i = 0; i < originalLogLines.length; i++) {
if (originalLogLines[i].includes(errorLine)) {
if (!req.logFileLineMap.errors) req.logFileLineMap.errors = {}
req.logFileLineMap.errors[errorLine] = i
break
}
}
})
warningLines.forEach((warningLine) => {
for (let i = 0; i < originalLogLines.length; i++) {
if (originalLogLines[i].includes(warningLine)) {
if (!req.logFileLineMap.warnings) req.logFileLineMap.warnings = {}
req.logFileLineMap.warnings[warningLine] = i
break
}
}
})
}
req.logFile = logLines.join('\n') req.logFile = logLines.join('\n')
req.logErrors = errorLines req.logErrors = errorLines
req.logWarnings = warningLines req.logWarnings = warningLines

View File

@ -11,7 +11,7 @@
class="d-flex justify-content-center sub-dropdown" class="d-flex justify-content-center sub-dropdown"
> >
<clr-dropdown> <clr-dropdown>
<button class="dropdown-toggle btn btn-link" clrDropdownTrigger> <button class="dropdown-toggle btn btn-primary" clrDropdownTrigger>
{{ getSubPage() }} {{ getSubPage() }}
<clr-icon shape="caret down"></clr-icon> <clr-icon shape="caret down"></clr-icon>
</button> </button>
@ -113,7 +113,7 @@
class="d-flex justify-content-center sub-dropdown" class="d-flex justify-content-center sub-dropdown"
> >
<clr-dropdown> <clr-dropdown>
<button class="dropdown-toggle btn btn-link" clrDropdownTrigger> <button class="dropdown-toggle btn btn-primary" clrDropdownTrigger>
{{ getSubPage() }} {{ getSubPage() }}
<clr-icon shape="caret down"></clr-icon> <clr-icon shape="caret down"></clr-icon>
</button> </button>

View File

@ -1,82 +0,0 @@
$sidebarWidth: 272px;
.clr-vertical-nav .nav-link.active {
background-color: transparent;
}
clr-vertical-nav {
width: $sidebarWidth;
min-width: $sidebarWidth;
height: 100%;
max-width: 375px;
position: relative;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.12);
.sun-dropdown {
min-height: 36px
}
.nav-tree {
height: 100%;
overflow-y: auto;
}
&.closed {
margin-left: -$sidebarWidth;
}
.resize-handle {
position: absolute;
top: 0;
bottom: 0;
right: -3px;
border-right: 4px solid #80b441;
cursor: col-resize;
opacity: 0;
transition: all 0.1s ease-in-out;
&:hover {
opacity: .5;
}
&.resizing {
opacity: 1;
}
}
&.resizing {
transition: none !important;
}
}
.nav-divider {
border: 0;
border-top: 1px solid #d3d3d3;
margin-bottom: 0;
}
.page-title {
margin: 0;
font-size: 18px;
text-align: center;
}
.zero-margin{
margin: 0px;
}
.user-nav-btn{
padding: 0px;
padding-left: 2px;
padding-right: 2px;
}
#sidebarNav {
z-index: 200;
}
@media (max-width: 767px) { //768
#sidebarNav {
position: absolute;
bottom: 0;
top: 0;
}
}

View File

@ -5,7 +5,8 @@ import {
ViewChild, ViewChild,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
Output Output,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { EventService } from '../../services/event.service' import { EventService } from '../../services/event.service'
@ -16,7 +17,8 @@ import { globals } from '../../_globals'
@Component({ @Component({
selector: 'app-sidebar', selector: 'app-sidebar',
templateUrl: './sidebar.component.html', templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.scss'] styleUrls: ['./sidebar.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class SidebarComponent implements OnInit { export class SidebarComponent implements OnInit {
@ViewChild('sidebarNav') sidebarNav!: ElementRef @ViewChild('sidebarNav') sidebarNav!: ElementRef

View File

@ -1,39 +0,0 @@
.input-val {
border: 0px;
background: transparent;
border-bottom: 1px solid #999999;
}
input {
width: 100%;
outline: none;
&::-webkit-calendar-picker-indicator {
margin-top: -5px;
}
}
clr-date-container {
position: relative;
margin-top: 2px !important;
::ng-deep {
.clr-input-group-icon-action {
position: absolute;
right: -5px;
}
input::-webkit-calendar-picker-indicator {
margin-right: 20px;
margin-top: -5px;
}
}
}
label.secondLabelActive span {
&:not(.value-type-selected) {
text-decoration: line-through;
cursor: pointer;
opacity: 0.6;
}
}

View File

@ -6,14 +6,16 @@ import {
OnInit, OnInit,
Output, Output,
SimpleChanges, SimpleChanges,
ViewChild ViewChild,
ViewEncapsulation
} from '@angular/core' } from '@angular/core'
import { OnLoadingMoreEvent } from '../autocomplete/autocomplete.component' import { OnLoadingMoreEvent } from '../autocomplete/autocomplete.component'
@Component({ @Component({
selector: 'app-soft-select', selector: 'app-soft-select',
templateUrl: './soft-select.component.html', templateUrl: './soft-select.component.html',
styleUrls: ['./soft-select.component.scss'] styleUrls: ['./soft-select.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class SoftSelectComponent implements OnInit, OnChanges { export class SoftSelectComponent implements OnInit, OnChanges {
@Input() inputId: string = '' @Input() inputId: string = ''

Some files were not shown because too many files have changed in this diff Show More