Compare commits

..

367 Commits

Author SHA1 Message Date
Tim Donohue
b731301b39 Merge pull request #749 from atmire/Edit-collection-item-template
Edit collection item template
2020-07-02 12:17:05 -05:00
Tim Donohue
0eb7eb6962 Merge pull request #703 from atmire/CC-License-Submission-Step
Cc license submission step
2020-07-02 11:22:33 -05:00
Tim Donohue
3fb4be27df Merge pull request #700 from atmire/Fix-context-sensitive-menus
Fix context sensitive menus
2020-07-02 11:14:43 -05:00
Art Lowel
4fa8d02fb2 remove unused imports 2020-07-02 17:32:34 +02:00
Art Lowel
a68dfc1c01 Merge branch 'master' into Fix-context-sensitive-menus 2020-07-02 17:18:20 +02:00
Tim Donohue
a414f04e96 Merge pull request #752 from paulo-graca/patch-3
DSPACE_HOST example fix
2020-07-02 09:53:41 -05:00
Tim Donohue
c2298f6fee Merge pull request #636 from atmire/scripts-processes
Scripts & processes admin UI
2020-07-02 09:46:50 -05:00
Paulo Graça
cece770e8f DSPACE_HOST example fix 2020-07-02 14:54:25 +01:00
Art Lowel
5e191ff4d1 Merge pull request #722 from DSpace/dependabot/npm_and_yarn/websocket-extensions-0.1.4
Bump websocket-extensions from 0.1.3 to 0.1.4
2020-07-02 13:51:20 +02:00
Samuel
531ef1fb1b Merge branch 'master' into CC-License-Submission-Step 2020-07-02 13:48:38 +02:00
Samuel
f655f5d149 CC License Submission Step - fix error when saving submission 2020-07-02 12:54:27 +02:00
Kristof De Langhe
92e47dee07 65272: AoT Build fix + LGTM fixes 2020-07-02 12:32:21 +02:00
Kristof De Langhe
b77fd69ac7 Merge branch 'master' into w2p-65272_Edit-collection-item-template
Conflicts:
	src/app/core/auth/auth-request.service.ts
	src/app/core/core.module.ts
2020-07-02 11:39:30 +02:00
Kristof De Langhe
e234c3a44d 65272: Fixed lint error 2020-07-02 11:12:16 +02:00
Kristof De Langhe
6d802f5078 65272: Edit item template - breadcrumb + title 2020-07-02 11:07:41 +02:00
Kristof De Langhe
e9993c8e16 65272: Fixed readonly error + test cases 2020-07-02 10:21:02 +02:00
Tim Donohue
2fe9965411 Merge pull request #716 from atmire/Authorization-for-downloads-of-restricted-bitstreams
Authorization for downloads of restricted bitstreams
2020-07-01 15:43:20 -05:00
Art Lowel
7cfa0f17a5 add support for authorized downloads 2020-07-01 19:00:21 +02:00
Art Lowel
df5d55c246 Merge branch 'Authorization-for-downloads-of-restricted-bitstreams' into scripts-processes 2020-07-01 18:51:23 +02:00
Art Lowel
68ecc7ac31 rename token param to authentication-token 2020-07-01 18:42:24 +02:00
Samuel
9bbdf95bee CC License Submission Step - fix error when changing accepted license 2020-07-01 18:28:48 +02:00
Tim Donohue
0e1874d269 Merge pull request #707 from atmire/Forgot-Password
Forgot password
2020-07-01 09:49:14 -05:00
Tim Donohue
71ff276079 Merge pull request #687 from atmire/w2p-70504_New-user-registration
New User Registration
2020-07-01 09:48:23 -05:00
Art Lowel
09f1b7e01f disable fetching and querying all fields 2020-07-01 16:40:16 +02:00
Art Lowel
1d0f0b8304 move schema on metadatafields to an observable remotedata 2020-07-01 16:12:15 +02:00
Kristof De Langhe
e0990aeb4b 65272: Test fixes 2020-07-01 14:07:15 +02:00
Kristof De Langhe
71da279d2f 70597: Build fix 2020-07-01 13:09:55 +02:00
Kristof De Langhe
5884308037 Merge branch 'master' into w2p-65272_Edit-collection-item-template
Conflicts:
	src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.spec.ts
	src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts
	src/app/+item-page/edit-item-page/edit-item-page.module.ts
	src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
	src/app/core/core.module.ts
	src/app/core/data/data.service.ts
2020-07-01 11:47:19 +02:00
Kristof De Langhe
9a4f962a21 71504: Remove unused imports 2020-07-01 11:08:22 +02:00
Kristof De Langhe
9f91fd2ad7 Merge branch 'master' into w2p-71504_Authorization-for-downloads-of-restricted-bitstreams
Conflicts:
	src/app/shared/shared.module.ts
2020-07-01 11:05:05 +02:00
Philip Vissenaekens
150d2cbb71 Merge remote-tracking branch 'origin/w2p-70504_New-user-registration' into Forgot-Password 2020-07-01 10:25:03 +02:00
Philip Vissenaekens
d35f2a419e 70504: removed unused import and variables 2020-07-01 10:15:49 +02:00
lotte
5b46ec1570 fixed test issue 2020-06-30 19:06:46 +02:00
Tim Donohue
199d4bf38f Merge pull request #710 from atmire/w2p-70599_Comcol-tree
Community and Collection Tree fixes
2020-06-30 11:09:18 -05:00
Samuel
ea28998bc1 CC License Submission Step - fix tests bis 2020-06-30 17:31:32 +02:00
lotte
a8b7035aff fixed issue with validation 2020-06-30 16:02:32 +02:00
lotte
0348d23aac fixed remove parameter bug 2020-06-30 14:28:58 +02:00
lotte
09665dfbe2 solved lint issues, added typedoc, fixed lgtm warnings 2020-06-30 13:44:38 +02:00
lotte
c7994f9d90 Merge branch 'master' into scripts-processes 2020-06-30 13:25:59 +02:00
Marie Verdonck
f992fe1afd Feedback: - set initial loading moved outside of of NgZone 2020-06-30 10:55:54 +02:00
Marie Verdonck
6433e211a8 Feedback processed: - change so state change behaviourSubjects back in NgZone.run 2020-06-30 10:55:54 +02:00
Marie Verdonck
94e3f2d5e0 Feedback processed: - pagesize comcol changed to 50 &
- loadCommunities inside ngZone.runOutsideAngular
- Chevron size small unexpanded and large expanded when logged in fixed
2020-06-30 10:55:54 +02:00
Ben Bosman
53779cf69e remove console logs 2020-06-30 10:55:54 +02:00
Marie Verdonck
1dfe7ec170 70599: Test fixes comcol tree after changes 2020-06-30 10:55:54 +02:00
Samuel
3f39752550 CC License Submission Step - fix tests 2020-06-30 10:53:56 +02:00
Marie Verdonck
b1e44a7fa5 70599: Improvements comcol tree 2020-06-30 10:49:30 +02:00
Samuel
6ef60351a5 Merge branch 'master' into CC-License-Submission-Step 2020-06-30 10:29:43 +02:00
dependabot[bot]
31eadf9c94 Bump websocket-extensions from 0.1.3 to 0.1.4
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-30 08:20:00 +00:00
Yana De Pauw
fc1ffd0e18 Merge remote-tracking branch 'upstream/master' into w2p-70504_New-user-registration 2020-06-30 10:10:29 +02:00
Yana De Pauw
ea16289013 Merge remote-tracking branch 'upstream/master' into Forgot-Password 2020-06-30 09:49:51 +02:00
lotte
1cb0bb72e4 added create-from functionality 2020-06-29 22:17:41 +02:00
Tim Donohue
bb4aedc472 Merge pull request #723 from atmire/async-code-in-beforeeach
Wait for async code in beforeEach
2020-06-29 11:33:52 -05:00
Art Lowel
066e6cd142 fixed a number of instances in community-list-service.spec.ts where async code was presumed synchronous 2020-06-29 17:42:16 +02:00
Art Lowel
e119967325 fix issue where beforeEach wouldn't wait for dropBitstream to end 2020-06-29 17:24:00 +02:00
Yana De Pauw
1a0e5f4098 Merge remote-tracking branch 'upstream/master' into Forgot-Password 2020-06-29 11:45:33 +02:00
Yana De Pauw
2863837bf8 Merge remote-tracking branch 'upstream/master' into w2p-70504_New-user-registration 2020-06-29 10:42:16 +02:00
Tim Donohue
5b82a8a07b Merge pull request #709 from atmire/Simplify-bitstream-drag-and-drop
Simplify bitstream drag and drop
2020-06-26 17:13:04 -05:00
Tim Donohue
ca564b2ad1 Merge pull request #708 from 4Science/CST-3090-collection-dropdown
Collection dropdown on MyDSpace & support enable/disable in Submission UI
2020-06-26 10:58:48 -05:00
Samuel
0888d81310 CC License Submission Step - fix lint issues 2020-06-26 17:30:06 +02:00
Samuel
fd59e02786 Merge branch 'master' into CC-License-Submission-Step 2020-06-26 16:59:48 +02:00
Samuel
02ddf7c8c5 CC License Submission Step - implement contract change 2020-06-26 16:58:45 +02:00
lotte
32c8d9de03 scripts & processes improvements 2020-06-26 15:27:48 +02:00
lotte
9677e053f5 solved merge issues 2020-06-26 14:27:28 +02:00
Kristof De Langhe
0c56e0182a Merge branch 'master' into w2p-71380_Simplify-bitstream-drag-and-drop 2020-06-26 14:24:22 +02:00
lotte
6ad7cee7d1 Merge branch 'master' into scripts-processes 2020-06-26 14:14:21 +02:00
Kristof De Langhe
9c27be085e Merge branch 'master' into w2p-71504_Authorization-for-downloads-of-restricted-bitstreams
Conflicts:
	src/app/core/core.module.ts
2020-06-26 10:03:07 +02:00
Danilo Di Nuzzo
5642a2798a [CST-3090] fix unused import alerts 2020-06-26 09:55:01 +02:00
Danilo Di Nuzzo
f37de548c0 [CST-3090] fix position of word 'here' 2020-06-26 09:37:43 +02:00
Kristof De Langhe
f24bd9fe36 71380: Reset page size 2020-06-25 17:52:02 +02:00
Kristof De Langhe
bfdd943d45 71380: Remove redundant code and add subscribable removeByHrefSubstring 2020-06-25 17:51:11 +02:00
Tim Donohue
bb705919f3 Merge pull request #697 from atmire/Refactor-registry-service-and-associated-models
Refactor registry service and associated models
2020-06-25 10:37:16 -05:00
Kristof De Langhe
73c25998e3 71380: Fix loading/cache issue with dropping objects on page 2020-06-25 11:09:37 +02:00
Kristof De Langhe
24858fceab 71504: Shortlived tokens + file-download-link test cases 2020-06-22 13:44:16 +02:00
Kristof De Langhe
b578aa408b 71504: FileDownloadLinkComponent 2020-06-22 11:40:39 +02:00
Kristof De Langhe
bbaaaed4b5 71504: short-lived token for downloading files through FileService 2020-06-19 17:26:11 +02:00
Kristof De Langhe
4c1b589158 70834: Use data-service's responseMsToLive for searchBy 2020-06-19 11:09:02 +02:00
Tim Donohue
5cef15eb20 Merge pull request #701 from atmire/Misc-edit-community-and-collection-bugs
Misc edit community and collection fixes
2020-06-18 15:13:40 -05:00
Danilo Di Nuzzo
f841e45019 [CST-3090] fix tests 2020-06-18 15:38:03 +02:00
Samuel
e963aa9af0 CC License Submission Step - feedback 2020-06-18 15:20:55 +02:00
Samuel
0721b844f5 Misc edit community and collection bugs - repair create top level community 2020-06-18 12:25:50 +02:00
Kristof De Langhe
28891211e4 71380: Reset page size 2020-06-18 12:13:32 +02:00
Kristof De Langhe
82a3014af4 71380: drag-and-drop-list customOrder to avoid elements hopping back after drop + freeze fix 2020-06-18 12:11:20 +02:00
Danilo Di Nuzzo
709726e041 [CST-3105] tests 2020-06-18 12:00:30 +02:00
Danilo Di Nuzzo
136e36afab [CST-3105] done 2020-06-18 11:30:45 +02:00
Samuel
baec130cf3 Merge branch 'master' into Misc-edit-community-and-collection-bugs 2020-06-18 11:15:59 +02:00
Danilo Di Nuzzo
f33f391eb3 [CTS-3090] - fix pagination 2020-06-18 10:23:56 +02:00
Danilo Di Nuzzo
be2d496335 [CTS-3090] update imports 2020-06-17 17:02:27 +02:00
Danilo Di Nuzzo
3b581b93c5 [CST-3090] fix 2020-06-17 16:31:11 +02:00
Kristof De Langhe
752cf97787 71380: Fix tests 2020-06-17 13:12:49 +02:00
Danilo Di Nuzzo
294f5e5f31 [CST-3090] fix services name and dropdown 2020-06-17 10:47:46 +02:00
Giuseppe Digilio
efc476ab31 remove unused disabled$ variable 2020-06-16 17:46:24 +02:00
Yana De Pauw
f5959e9857 Merge remote-tracking branch 'upstream/master' into Forgot-Password 2020-06-16 15:58:59 +02:00
Yana De Pauw
e277a72ebf 71304: Fix spec descriptions 2020-06-16 15:58:19 +02:00
Danilo Di Nuzzo
5f0f665501 [CTS-3090] - fix 2020-06-16 15:51:56 +02:00
Danilo Di Nuzzo
be16134329 Merge branch 'master' into CST-3090-collection-dropdown 2020-06-16 15:18:50 +02:00
Danilo Di Nuzzo
9e05072290 [CST-3090] done 2020-06-16 14:26:59 +02:00
Kristof De Langhe
c6ee46fdea 71380: Reset page size back to normal 2020-06-15 17:57:25 +02:00
Kristof De Langhe
16d3d0e063 71380: Remove object updates for drag-and-drop and send out immediate patch requests for bitstream drag-and-drop 2020-06-15 17:48:03 +02:00
Yana De Pauw
6f9f4ec968 71304: Implement Forgot password components 2020-06-15 11:59:25 +02:00
Samuel
b8ab83ce99 Misc edit community and collection bugs - repair test 2020-06-12 13:58:22 +02:00
Samuel
7421eef223 Misc edit community and collection bugs 2020-06-12 09:54:13 +02:00
Samuel
470c21d8d8 Merge branch 'master' into CC-License-Submission-Step 2020-06-12 09:04:29 +02:00
Samuel
3db47f5791 CC License Submission Step 2 - Storing the results - add SubmissionCcLicenceUrl model 2020-06-12 09:04:00 +02:00
Tim Donohue
8b8d7ba91a Merge pull request #702 from 4Science/CSR-auth-guard-issue
Fixed authentication issue with protected page on CSR
2020-06-11 11:12:37 -05:00
Kristof De Langhe
ee9f5ec7f1 70834: MetadataField search responseMsToLive fix 2020-06-11 15:48:26 +02:00
Giuseppe Digilio
c835d9b9c7 fixed test description 2020-06-11 14:44:42 +02:00
Giuseppe Digilio
6bd04c94ec store token on AUTHENTICATED_SUCCESS action 2020-06-11 14:15:19 +02:00
Samuel
6c1e636f5c fix tests 2020-06-11 13:49:48 +02:00
Art Lowel
405815ac5a fix test 2020-06-11 13:49:48 +02:00
Art Lowel
d27034d634 fix issue where the current collection or community would no longer be selected in the new and edit menus 2020-06-11 13:49:48 +02:00
Kristof De Langhe
9a4fc65331 68067: Fix instance field declaration 2020-06-11 10:50:39 +02:00
Tim Donohue
ea26597b6a Merge pull request #689 from atmire/polyfill-error-fix
fix issue with polyfill order in safari and firefox
2020-06-10 14:20:57 -05:00
Tim Donohue
31b6bfc332 Merge pull request #698 from atmire/FileSizePipe-refactor
FileSizePipe refactor
2020-06-10 13:20:06 -05:00
Yana De Pauw
035a4b6e16 Merge remote-tracking branch 'upstream/master' into Forgot-Password 2020-06-10 17:05:37 +02:00
Kristof De Langhe
9f64fedc7b Merge branch 'master' into w2p-68067_Fix-context-sensitive-menus 2020-06-10 13:10:21 +02:00
Kristof De Langhe
ce04825c4a 71174: FileSizePipe 'jedec' standard 2020-06-10 10:32:58 +02:00
Yana De Pauw
ca7a76b80f Implement community feedback
Remove other registration references
Enabled enter submit in registration form
Fixed create-profile password validation to be on debounce
Fixed register page title
2020-06-10 10:15:06 +02:00
Kristof De Langhe
a51a683215 71174: Breadcrumb test fix 2020-06-04 16:30:16 +02:00
Kristof De Langhe
44386823a3 Merge branch 'master' into w2p-70834_Refactor-registry-service-and-associated-models
Conflicts:
	src/app/core/data/data.service.ts
2020-06-04 16:28:56 +02:00
Kristof De Langhe
b79a3d37f3 Merge remote-tracking branch 'dspace/master' into w2p-71174_FileSizePipe-refactor 2020-06-03 10:56:09 +02:00
Kristof De Langhe
f8f0e5f149 71174: FileSizePipe using filesize.js 2020-06-03 10:54:29 +02:00
Art Lowel
bcb77c8dcc remove comment about zone polyfill 2020-06-02 09:21:49 +02:00
Art Lowel
697be3c610 fix issue with polyfill order in safari and firefox 2020-06-02 09:21:49 +02:00
Tim Donohue
9b7a33cc69 Merge pull request #692 from atmire/fix-minimist-vulnerability
Fix minimist vulnerability
2020-06-01 15:25:17 -05:00
Tim Donohue
3ece498b81 Merge pull request #693 from tdonohue/fix_references_to_environment_js
Fix all outdated references to environment.*.js.
2020-06-01 12:59:48 -05:00
Tim Donohue
b1d39feeda Fix compilation bug in environment.dev.ts used by Docker. Add comments 2020-06-01 11:38:29 -05:00
Bram Luyten
ba9996a3b0 Merge pull request #683 from reetagithub/finnish-msg-keys
Add Finnish translations (first set after master rebase)
2020-05-31 14:48:21 +02:00
Bram Luyten
fcb610412d Activating Finnish in environment.common.ts 2020-05-30 18:15:00 +02:00
Tim Donohue
23e8c8b449 Fix all outdated references to environment.*.js. Fix bug in Docker compose too 2020-05-29 16:52:54 -05:00
Tim Donohue
c423b474ab Merge pull request #691 from atmire/w2p-71201_Angular-UI-does-not-properly-logout-when-clicking-logout
Angular UI does not properly log out when clicking logout
2020-05-29 14:42:18 -05:00
Art Lowel
7b4a481f43 update mkdirp and add resolution for minimist 2020-05-29 17:59:13 +02:00
Art Lowel
ce6b259a3a update karma 2020-05-29 17:35:06 +02:00
Art Lowel
db5ade547d update protractor 2020-05-29 17:28:50 +02:00
Art Lowel
2fbf3afd4a replace deprecated postcss-smart-import with postcss-import 2020-05-29 17:22:34 +02:00
Tim Donohue
45247ff07c Merge pull request #645 from 4Science/#601-resource-policies
#601 resource policies
2020-05-29 10:03:10 -05:00
Art Lowel
d869c6282a Merge pull request #660 from DSpace/dependabot/npm_and_yarn/acorn-6.4.1
Bump acorn from 6.4.0 to 6.4.1
2020-05-29 16:56:12 +02:00
dependabot[bot]
d9749c80c4 Bump acorn from 6.4.0 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.4.0 to 6.4.1.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.4.0...6.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-05-29 13:46:12 +00:00
Tim Donohue
acd6e6079e Merge pull request #677 from atmire/w2p-70901_ui-environment-vars
Fixed issue with environment UI variables being ignored
2020-05-28 10:57:40 -05:00
Tim Donohue
4ae2977ef2 Merge pull request #682 from 4Science/authentication_issue_CSR
Authentication issue csr
2020-05-28 10:54:22 -05:00
Tim Donohue
56ee4bbaa0 Merge pull request #675 from atmire/w2p-70905_Breadcrumb-update-issue
Fix delay in breadcrumb rendering
2020-05-28 10:49:05 -05:00
Yana De Pauw
1295e127fd 71201: Add test 2020-05-28 15:25:48 +02:00
Yana De Pauw
d24c51e1cd 71201: #678 Angular UI does not properly logout when clicking logout 2020-05-28 14:30:56 +02:00
Giuseppe Digilio
7227d5eefd Remove cached search request after result was retrieved 2020-05-28 11:47:26 +02:00
Giuseppe Digilio
f0bf87b7f9 Show edit group button only when resource policy has permissions on group 2020-05-28 11:39:42 +02:00
Yana De Pauw
36acb7578f Fix to breadcrumb related injector issues on edit pages 2020-05-28 10:50:49 +02:00
Yana De Pauw
d483d46370 70905: Breadcrumb update issue 2020-05-28 10:50:49 +02:00
Yana De Pauw
8fc2309d48 Fix rebase issues 2020-05-28 10:34:03 +02:00
Yana De Pauw
bca1e8bdd4 70504: Implement feedback 2020-05-28 09:43:47 +02:00
Yana De Pauw
96d76073ef 70504: fix compile issue 2020-05-28 09:41:16 +02:00
Yana De Pauw
f136ea7d4f 70504: New user registration 2020-05-28 09:41:16 +02:00
Giuseppe Digilio
5421d97bc5 Merge remote-tracking branch 'remotes/origin/master' into authentication_issue_CSR 2020-05-28 09:23:22 +02:00
Giuseppe Digilio
a57d5d7c4f Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies 2020-05-28 09:22:11 +02:00
lotte
a9cb6aeaa6 added doc to scripts 2020-05-28 09:15:02 +02:00
lotte
f881c2f428 fixed SSR issues 2020-05-28 09:15:01 +02:00
lotte
e7043f8734 changes to server.ts 2020-05-28 09:15:01 +02:00
lotte
e4a83f0704 fixed ui environment vars issue 2020-05-28 09:15:01 +02:00
Tim Donohue
780b8b7db9 Merge pull request #690 from tdonohue/fix_travis_e2e
Quick fix to Travis e2e testing issues (running against a Docker backend)
2020-05-27 17:00:16 -05:00
Tim Donohue
92b1a4477d Fix Docker local.cfg by correcting UI port to 4000 2020-05-27 15:54:33 -05:00
Kristof De Langhe
7b64d6bc31 68067: JSDocs + menu-effects tests 2020-05-26 14:08:54 +02:00
Kristof De Langhe
0b67bd54fb 68067: Refactoring menu-component resolving route menu data to menu effects 2020-05-26 11:54:33 +02:00
Reeta Kuuskoski
5f6fdf00ec Add Finnish translations (first set after master rebase) 2020-05-25 12:56:34 +03:00
Giuseppe Digilio
460e20284e fixed test 2020-05-22 16:50:48 +02:00
Giuseppe Digilio
b61490341e Added missing class in the authentication form to apply style properly 2020-05-22 16:50:06 +02:00
Giuseppe Digilio
4a65051641 Fixed issue with authentication when SSR is disabled 2020-05-22 16:48:51 +02:00
Giuseppe Digilio
1dde3087ff Fixed failed test 2020-05-22 11:36:02 +02:00
Giuseppe Digilio
c5bf8f6267 Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies
# Conflicts:
#	src/app/shared/shared.module.ts
2020-05-21 19:35:35 +02:00
Tim Donohue
5c7cd4a27d Merge pull request #653 from atmire/Login-as-EPerson
Login as EPerson
2020-05-21 10:10:04 -05:00
Giuseppe Digilio
b41acfdb33 Moved resource policy's group edit link 2020-05-21 12:21:08 +02:00
Giuseppe Digilio
8ef77df651 Fixed issue with resource policies list that was not updated after a delete 2020-05-21 12:19:24 +02:00
Giuseppe Digilio
51620df76c Fixed issue with item edit page 2020-05-21 12:18:17 +02:00
Giuseppe Digilio
09ee329f17 Fixed failed test 2020-05-21 12:17:37 +02:00
Giuseppe Digilio
e1716751d4 Fixed build error 2020-05-20 18:10:17 +02:00
Giuseppe Digilio
b70f8e12f6 Fixed merge with master 2020-05-20 17:05:54 +02:00
Giuseppe Digilio
b5d92590ee Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies
# Conflicts:
#	src/app/core/eperson/eperson-data.service.spec.ts
#	src/app/core/eperson/group-data.service.spec.ts
#	src/app/shared/shared.module.ts
#	src/app/submission/sections/upload/section-upload.component.spec.ts
2020-05-20 15:37:33 +02:00
Kristof De Langhe
49bb61b2ae 70834: Registry breadcrumbs 2020-05-20 13:59:00 +02:00
Samuel
18007048a3 CC License Submission Step 2 - Storing the results - feedback 2020-05-20 13:55:42 +02:00
Kristof De Langhe
59205b174f 70834: refactor createOrUpdate methods to use existing data-service methods 2020-05-20 12:30:17 +02:00
Kristof De Langhe
79eecc7c76 68067: Route menu data - menu ID 2020-05-19 17:34:56 +02:00
Kristof De Langhe
8761d0ac27 68067: Add unsubscribes on open subscriptions in menu component 2020-05-19 16:46:58 +02:00
Kristof De Langhe
6d88381ead 68067: Route data menu sections - tests 2020-05-19 16:35:36 +02:00
Samuel
1071506133 CC License Submission Step 2 - Storing the results 2020-05-19 16:02:05 +02:00
Samuel
e802185657 CC License Submission Step - fix tests 2020-05-19 16:02:05 +02:00
Samuel
245cb45503 CC License Submission Step 2020-05-19 16:02:05 +02:00
Kristof De Langhe
ff0750d053 68067: Add menu sections through route data 2020-05-19 14:37:17 +02:00
Kristof De Langhe
172d0d986b 68067: JSON.stringify to compare menu section changes 2020-05-19 12:08:59 +02:00
Kristof De Langhe
8b78ed3a97 68067: Fix adding/removing menu sections 2020-05-19 11:11:07 +02:00
Kristof De Langhe
ad26ececbf Merge branch 'master' into Login-as-EPerson
Conflicts:
	src/app/shared/shared.module.ts
2020-05-19 10:01:10 +02:00
Tim Donohue
b28f59f087 Merge pull request #676 from bram-atmire/sync-i18n-fix
Ensuring environment.ts is present before sync-i18n-files invocation
2020-05-18 10:21:51 -05:00
Bram Luyten
03f910b45d Ensuring environment.ts is present before sync-i18n-files invocation 2020-05-18 15:52:16 +02:00
Tim Donohue
64478870c0 Merge pull request #650 from atmire/w2p-70136_workflow-search-ui
Administer Workflow
2020-05-14 10:22:59 -05:00
Kristof De Langhe
ad8f31d44a 70834: Test fixes + data service tests 2020-05-14 11:29:35 +02:00
Kristof De Langhe
e42785a7a4 70834: MetadataSchemaComponent test fix 2020-05-13 17:42:38 +02:00
Kristof De Langhe
0e9d624519 70834: RegistryService test fixes 2020-05-13 17:32:12 +02:00
Kristof De Langhe
c97e3e0515 70834: Metadata schema component refactoring and caching issue fix #2 2020-05-13 16:49:39 +02:00
Kristof De Langhe
cd46f33909 70834: Metadata schema component refactoring and caching issue fix 2020-05-13 13:56:42 +02:00
Kristof De Langhe
3894b3615d 70373: Test import fix 2020-05-12 17:20:02 +02:00
lotte
03668e347e added missing typedoc 2020-05-12 17:03:48 +02:00
Kristof De Langhe
f548d5bf20 Merge branch 'master' into Login-as-EPerson
Conflicts:
	src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts
	src/app/core/auth/auth.service.spec.ts
	src/app/profile-page/profile-page.component.spec.ts
2020-05-12 16:54:40 +02:00
Kristof De Langhe
7677a673aa 70834: Intermediate commit 2020-05-12 16:36:03 +02:00
lotte
7ced70b7d3 fixed issues with tests 2020-05-12 16:33:42 +02:00
Kristof De Langhe
101f1a76dd 70834: Refactoring registry-service pt1 - removing response-parsing services and using data-services 2020-05-12 14:54:10 +02:00
Tim Donohue
33be8a4a91 Merge pull request #663 from atmire/resolve-tsconfig-errors-in-spec-files
[Quickfix] Fix IDE issues with spec files
2020-05-11 09:23:07 -05:00
lotte
a58d6da8e0 added jasmine to root tsconfig.json 2020-05-11 15:05:02 +02:00
lotte
6220c51aa6 fixed tests 2020-05-11 13:28:02 +02:00
Kristof De Langhe
67b73ff921 70597: Test fixes 2020-05-11 13:21:01 +02:00
lotte
e8f418b077 Merge branch 'master' into w2p-70136_workflow-search-ui 2020-05-11 11:58:31 +02:00
lotte
a561f37b00 fixed missing comma 2020-05-11 11:29:29 +02:00
lotte
4f7afc578f Merge branch 'master' into scripts-processes 2020-05-11 11:28:52 +02:00
Art Lowel
bb0f28c9c4 Merge pull request #661 from atmire/fix-prod-server-port
Hotfix: use the server port from the environment file
2020-05-08 13:15:19 +02:00
Art Lowel
4580f1b18a use the server port from the environment file 2020-05-08 12:40:31 +02:00
Art Lowel
4fe2c75810 Merge pull request #625 from atmire/angular-cli
Switch to Angular CLI
2020-05-08 09:16:38 +02:00
lotte
b249a91aaa Merge branch 'master' into angular-cli 2020-05-07 16:11:38 +02:00
Kristof De Langhe
f5f4570116 65272: Allow relationship fields to be edited 2020-05-04 17:57:08 +02:00
Kristof De Langhe
b5e1394fce 65272: Post-merge fixes 2020-05-04 17:38:31 +02:00
Kristof De Langhe
07c8c593ec Merge branch 'master' into w2p-65272_Edit-collection-item-template
Conflicts:
	src/app/+collection-page/collection-page-routing.module.ts
	src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts
	src/app/+item-page/edit-item-page/edit-item-page.module.ts
	src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
	src/app/core/cache/server-sync-buffer.effects.ts
	src/app/core/core.module.ts
	src/app/core/data/data.service.ts
	src/app/core/data/dso-change-analyzer.service.ts
	src/app/core/data/object-updates/object-updates.service.ts
2020-05-04 16:36:46 +02:00
Bram Luyten
519046e769 i18n correction English catalog 2020-05-04 15:09:46 +02:00
Bram Luyten
3b30af3e4d i18n correcting two errors in English main catalog 2020-05-04 13:33:55 +02:00
Giuseppe Digilio
bacb778fa7 Fixed resource policy page buttons 2020-04-30 17:25:00 +02:00
Giuseppe Digilio
b338332d13 Added possibility to search for eperson or group while adding a new resource policy 2020-04-30 15:43:52 +02:00
lotte
84d9e4b063 removed debugger; line 2020-04-30 12:35:25 +02:00
lotte
4c48088920 fixed test issues and watch mode for unit tests 2020-04-30 12:13:41 +02:00
lotte
ef91468310 fixed set-env.ts, reverted unnecessary e2e changes, updated travis.yml 2020-04-29 16:28:26 +02:00
Art Lowel
df2cc22172 remove clearStateMetaReducer 2020-04-24 14:06:37 +02:00
Art Lowel
c2789dfbf7 fix issue where a hard refresh wouldn't work to clear the state due to the browser caching the html 2020-04-24 13:16:52 +02:00
Giuseppe Digilio
8635209959 Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies 2020-04-23 17:05:38 +02:00
lotte
7ec7d3a455 reinstated other tests 2020-04-23 14:30:46 +02:00
lotte
0f43ff4fea switched back to port 4000 2020-04-23 14:17:05 +02:00
lotte
f1d1761fd7 sync i18n script 2020-04-23 14:14:29 +02:00
lotte
ce9fed7507 fixing e2e:ci 2020-04-22 16:28:17 +02:00
lotte
51dd1b1b2b changing timeout 2020-04-22 16:07:22 +02:00
lotte
2caf88bebe reset env variables 2020-04-22 15:30:45 +02:00
lotte
2e367cb87c testing e2e on travis 2020-04-22 15:29:52 +02:00
lotte
2a353efa5f updated environment file 2020-04-22 07:44:29 +02:00
lotte
6196a99a98 fixed tests 2020-04-21 18:41:38 +02:00
lotte
ad4b7fa254 test travis with external rest 2020-04-21 16:39:51 +02:00
lotte
42740809c0 changed tasks into wfi's 2020-04-21 16:27:26 +02:00
lotte
172d3891f0 switched port to test with Travis 2020-04-21 15:16:42 +02:00
lotte
cad9dcaf98 Merge branch 'master' into angular-cli 2020-04-21 13:45:55 +02:00
lotte
267db6ddce updated dockers files 2020-04-21 13:41:30 +02:00
lotte
c4d02ff67d fixed import 2020-04-17 16:43:01 +02:00
lotte
37e4e63f81 fixed compilation issue with abstract component 2020-04-17 16:26:26 +02:00
lotte
bbac79bdfc fixes after merge 2020-04-17 16:09:26 +02:00
lotte
92dca8d4e8 Merge branch 'master' into angular-cli 2020-04-17 16:09:12 +02:00
Giuseppe Digilio
c03146e415 Fixed resource policy's group edit link 2020-04-16 17:12:20 +02:00
Kristof De Langhe
a6d7b6444c 70373: Remove unnecessary route navigate 2020-04-16 15:12:41 +02:00
Kristof De Langhe
5e94cf379c 70373: AuthService impersonate tests 2020-04-15 16:47:18 +02:00
Giuseppe Digilio
98ade2eb63 Fixed issue with merge 2020-04-15 16:35:29 +02:00
Kristof De Langhe
7df5025aa5 70373: EPerson impersonate tests 2020-04-15 16:23:41 +02:00
Giuseppe Digilio
4deaf145b6 Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies
# Conflicts:
#	src/app/core/eperson/eperson-data.service.spec.ts
#	src/app/core/eperson/group-data.service.ts
#	src/app/shared/testing/group-mock.ts
2020-04-15 16:18:27 +02:00
Giuseppe Digilio
b81d8ed900 Added test for ResourcePolicyEditComponent 2020-04-15 16:13:38 +02:00
Giuseppe Digilio
4ac3eb5f9b Added test for ResourcePolicyCreateComponent 2020-04-15 16:13:22 +02:00
Giuseppe Digilio
83a1f9d31d Added test for EpersonGroupListComponent 2020-04-15 16:13:06 +02:00
Giuseppe Digilio
ceaa14e9b2 Added test for ResourcePolicyFormComponent 2020-04-15 16:12:35 +02:00
Giuseppe Digilio
ee38de488c Added test for ResourcePoliciesComponent 2020-04-15 16:12:05 +02:00
Giuseppe Digilio
e7d0c96a26 Added test for ItemAuthorizationsComponent 2020-04-15 16:11:24 +02:00
Kristof De Langhe
4cd11bcbca 70373: Fix existing texts 2020-04-15 15:35:41 +02:00
Kristof De Langhe
c48bb2cbb0 70373: Stop impersonating button in navbar + clear cookie on logout 2020-04-15 13:08:04 +02:00
Kristof De Langhe
e43aa15a70 70373: Store authenticated EPerson ID in store instead of object 2020-04-15 11:14:41 +02:00
Giuseppe Digilio
00f2aa5e1c Renamed ResourcePolicyFormComponent's file 2020-04-14 21:13:43 +02:00
Giuseppe Digilio
46498992a7 Renamed ResourcePolicyFormComponent's file 2020-04-14 20:58:58 +02:00
Kristof De Langhe
638793ca5e 70373: Login as EPerson intermediate commit 2020-04-10 17:41:39 +02:00
lotte
3d482aed26 removed unnecessary import 2020-04-09 16:17:27 +02:00
lotte
76790be925 Merge branch 'master' into w2p-70136_workflow-search-ui 2020-04-09 11:42:09 +02:00
lotte
3ac575c360 fixed messages for Admin Workflow 2020-04-09 11:29:39 +02:00
lotte
9cfed06784 fixed caching issue 2020-04-09 10:20:42 +02:00
lotte
e43f04e564 finished tests 2020-04-08 15:41:55 +02:00
Giuseppe Digilio
37fe6d2193 Fixed failed test 2020-04-07 09:29:21 +02:00
Giuseppe Digilio
99c1234a7d Disable policyType and action fields in resource policy edit form 2020-04-07 09:26:24 +02:00
Giuseppe Digilio
0b65bdac46 fixed lint error 2020-04-06 20:47:52 +02:00
Giuseppe Digilio
e078071dfb Intermediate commit 2020-04-06 20:36:56 +02:00
Giuseppe Digilio
b210a36e53 Added new date utils 2020-04-06 20:11:37 +02:00
Giuseppe Digilio
4c391bbae4 Fixed issue with delete operation 2020-04-06 20:11:20 +02:00
lotte
d003400c16 started fixing tests 2020-04-06 17:45:27 +02:00
Giuseppe Digilio
5cb0570bc0 Added new date utils 2020-04-06 16:27:58 +02:00
Giuseppe Digilio
9339ae2d7c Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies
# Conflicts:
#	resources/i18n/en.json5
#	src/app/+item-page/edit-item-page/edit-item-page.module.ts
#	src/app/shared/shared.module.ts
2020-04-04 15:59:44 +02:00
Giuseppe Digilio
6314e17f27 Intermediate commit 2020-04-03 20:25:58 +02:00
lotte
de1b57d8d9 workflow delete/sendback 2020-04-03 18:13:22 +02:00
lotte
2eb3d11cd2 debugging issue commit 2020-04-03 16:00:52 +02:00
Giuseppe Digilio
1ac52edbf7 Added create and delete method to resource policy service 2020-04-02 20:50:02 +02:00
Giuseppe Digilio
b9de6a7a7d Changed DataService's create method in the way to accept array of request params 2020-04-02 19:54:30 +02:00
Giuseppe Digilio
41d6255998 Renamed SearchParam class with a generic name RequestParam 2020-04-02 19:19:38 +02:00
Giuseppe Digilio
5a37891184 Merge remote-tracking branch 'remotes/origin/master' into #601-resource-policies
# Conflicts:
#	src/app/shared/shared.module.ts
2020-04-02 19:12:19 +02:00
Giuseppe Digilio
4f14e546a5 Added fallback strategy for DSONameService to get name for dspace object without a dc.tile metadata 2020-04-02 19:10:22 +02:00
Giuseppe Digilio
fab11e9055 Added component to edit and create a resource policy 2020-04-02 18:58:51 +02:00
Giuseppe Digilio
7f6c88164b Added create and edit resource policy link 2020-04-02 18:57:48 +02:00
Giuseppe Digilio
8913a45a6b Added a form field for selected resource policy target eperson/group 2020-04-02 18:54:34 +02:00
Giuseppe Digilio
b603c7fc05 Added a component that show a paginated list of eperson or group 2020-04-02 18:52:53 +02:00
lotte
258b1228f3 replaced wfi components by task components that render wfi's 2020-04-02 17:05:46 +02:00
lotte
f664cf4c90 made timeout longer for e2e 2020-04-02 17:02:14 +02:00
lotte
97953912c5 added waiting until loading is done to e2e tests 2020-04-02 11:22:48 +02:00
lotte
b3ba67e31d Merge branch 'master' into angular-cli 2020-04-02 10:36:37 +02:00
lotte
5bb4065580 print html in e2e to debug 2020-04-02 10:27:08 +02:00
lotte
45beb3f93f Added more thens to e2e tests 2020-04-02 09:44:05 +02:00
lotte
6e49ef6859 start of admin workflow ui 2020-04-01 17:04:54 +02:00
lotte
5bcc700cc9 fixed e2e issue 2020-04-01 10:43:07 +02:00
lotte
4a52513a38 fixed test 2020-03-31 16:11:13 +02:00
lotte
27fcdab8ad fixed non-existing color in setenv script 2020-03-31 15:04:38 +02:00
lotte
894bee2583 added rimraf to dev deps 2020-03-31 13:52:39 +02:00
lotte
69ba0865a8 fixed test files + added clean for environment.ts + fixed set-env script bug 2020-03-31 13:50:12 +02:00
lotte
6b6068ffb8 Merge branch 'master' into angular-cli 2020-03-31 13:49:40 +02:00
lotte
3a73de90ba fixed alignment issue on new process page 2020-03-31 10:00:02 +02:00
lotte
c225c9015e Added messages and menu links + tests 2020-03-30 15:19:22 +02:00
lotte
b666e3f208 70090: Added trail for processes pages 2020-03-30 15:19:22 +02:00
Kristof De Langhe
d4609b87ea 69940: Fix tests 2020-03-30 15:19:22 +02:00
Kristof De Langhe
6b53c448c8 69940: Processes - date format, back button and hiding empty fields 2020-03-30 15:19:22 +02:00
Kristof De Langhe
5e890aca2c 69940: Process detail - Output Files 2020-03-30 15:19:22 +02:00
Kristof De Langhe
3bac6cc1b3 69940: Process files request 2020-03-30 15:19:22 +02:00
Kristof De Langhe
cf492a92c8 69940: Process detail and overview test cases 2020-03-30 15:19:22 +02:00
Kristof De Langhe
b4bb3acb63 69940: Process details intermediate commit #2 2020-03-30 15:19:22 +02:00
Kristof De Langhe
07a5dceed1 69940: Process detail page intermediate commit 2020-03-30 15:19:22 +02:00
Kristof De Langhe
eacc13a95c 69940: Process overview page 2020-03-30 15:19:22 +02:00
Art Lowel
428abc8282 fix file padding and help text color 2020-03-30 15:19:22 +02:00
lotte
e7a5daad18 fixed tests and feedback 2020-03-30 15:19:22 +02:00
lotte
ef3a235178 added tests and typedoc 2020-03-30 15:19:22 +02:00
lotte
e38aec831f fixed file upload, styling, boolean/date/output inputs 2020-03-30 15:19:22 +02:00
lotte
3e4704af0d working on upload functionality 2020-03-30 15:18:07 +02:00
lotte
ee649debfb moved process data services 2020-03-30 15:18:07 +02:00
lotte
68e2a08af2 added switch for parameter types 2020-03-30 15:17:01 +02:00
lotte
7c9c45b7cb added script parameters & route updates 2020-03-30 15:17:01 +02:00
lotte
1cb39cef41 created new process page 2020-03-30 15:17:01 +02:00
Giuseppe Digilio
1f26a7b634 Show the policies for each bundle and bitstream within the item 2020-03-30 12:57:33 +02:00
Giuseppe Digilio
18d38ca737 Implemented resource policies component 2020-03-30 12:36:36 +02:00
Giuseppe Digilio
be8923d572 Added primaryBitstream and bitstreams properties to Bundle model 2020-03-30 11:43:38 +02:00
Giuseppe Digilio
2e94b349f9 Added eperson and group property to ResourcePolicy model 2020-03-30 11:43:02 +02:00
Giuseppe Digilio
1af5958fa9 Added ngFor track by DSO's id directive 2020-03-30 11:40:58 +02:00
Art Lowel
f61f92e1ad add template file, update readme, remove logs 2020-03-27 15:51:54 +01:00
Giuseppe Digilio
e48b8ad147 Fixed issue with accessCondition in SubmissionSectionUploadAccessConditionsComponent 2020-03-27 12:21:53 +01:00
Giuseppe Digilio
e87c173e96 Fixed issue with getSearchEndpoint which make wrong request to endpointMap 2020-03-27 12:19:20 +01:00
Giuseppe Digilio
ac323f48cc Added item authorizations component 2020-03-27 12:17:59 +01:00
lotte
1caec64115 added npm-run-all 2020-03-27 11:02:07 +01:00
lotte
a3b97f7bd9 fixed notification type 2020-03-27 10:10:44 +01:00
lotte
0850c264b6 added nodemon to watch dev environment changes 2020-03-27 10:06:17 +01:00
lotte
1b7fdfc59c removed custom environment files and fixed config build 2020-03-27 09:10:32 +01:00
lotte
e53727248d environment.ts script 2020-03-26 15:30:41 +01:00
Giuseppe Digilio
e396fe054e Refactored Resource Policy service 2020-03-26 14:40:06 +01:00
lotte
1a318b6f7a Fixed path to coverage report 2020-03-19 12:36:36 +01:00
lotte
9043e1375c fixed e2e script that uses docker 2020-03-19 11:46:18 +01:00
lotte
02c67f4ec0 changed travis/docker setup 2020-03-19 10:48:53 +01:00
lotte
c870b3d02c Merge branch 'master' into angular-cli 2020-03-19 10:27:13 +01:00
Art Lowel
56318ad86b fix followLink tests 2020-03-18 18:32:12 +01:00
lotte
dd0396465e fixed tests except for iterator issue in data services 2020-03-18 17:03:19 +01:00
lotte
8bf241c182 angular cli 2020-03-18 16:03:40 +01:00
Kristof De Langhe
46ab613481 65272: Filter autocomplete metadata fields + fix test 2020-02-11 15:48:56 +01:00
Kristof De Langhe
e3facbd8c8 65272: filter relationship metadata when displaying on item-metadata, keep them stored in the object-updates store 2020-02-11 14:55:08 +01:00
Kristof De Langhe
1885845fef 65272: Clear template-item cache on removal 2020-02-07 17:18:51 +01:00
Kristof De Langhe
53355d1fc4 65272: Test fixes 2020-01-23 17:49:41 +01:00
Kristof De Langhe
d98ce7c97e 65272: Logo spacing layout fix 2020-01-23 17:33:25 +01:00
Kristof De Langhe
98937bd240 65272: Missing JSDocs + id and uuid serializing fix for NormalizedTemplateItem 2020-01-23 17:24:46 +01:00
Kristof De Langhe
a714958c04 65272: Object update PUT to PATCH requests + option to add ignored metadata fields to update 2020-01-23 16:49:31 +01:00
Kristof De Langhe
4ae5ee21b1 65272: Edit template item - Empty metadata alert + alignment fixes 2020-01-23 15:59:47 +01:00
Kristof De Langhe
24fc3e6c76 65272: TemplateItem object and normalized version 2020-01-23 15:14:25 +01:00
Kristof De Langhe
4f048f59f7 Merge branch 'master' into w2p-65272_Edit-collection-item-template
Conflicts:
	resources/i18n/en.json5
	src/app/+collection-page/collection-page.module.ts
	src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.html
	src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.spec.ts
	src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.ts
	src/app/core/core.module.ts
	src/app/core/data/data.service.ts
	src/app/shared/shared.module.ts
2020-01-23 14:30:44 +01:00
Kristof De Langhe
b3371c5c14 Merge branch 'master' into w2p-65272_Edit-collection-item-template
Conflicts:
	resources/i18n/en.json5
	src/app/+collection-page/collection-page-routing.module.ts
	src/app/+collection-page/collection-page.module.ts
	src/app/core/core.module.ts
	src/app/core/data/data.service.ts
	src/app/shared/shared.module.ts
2019-11-29 11:04:06 +01:00
Kristof De Langhe
b3b8ea1dee 65272: item template REST contract endpoint changes 2019-10-14 16:47:35 +02:00
Kristof De Langhe
7fd4b41460 65272: Added test cases 2019-10-04 17:50:53 +02:00
Kristof De Langhe
088304fce7 Merge branch 'w2p-63669_Edit-Col/Com-Tabs' into w2p-65272_Edit-collection-item-template 2019-10-04 15:48:18 +02:00
Kristof De Langhe
cfdc227563 65272: CollectionMetadataComponent test import fixes 2019-10-04 14:46:59 +02:00
Kristof De Langhe
2eae641703 Merge branch 'master' into w2p-65272_Edit-collection-item-template 2019-10-04 13:35:19 +02:00
Kristof De Langhe
90beee9a85 65272: Existing test fixes 2019-10-04 13:34:56 +02:00
Kristof De Langhe
644ab2cfab 65272: JSDocs 2019-10-04 13:05:15 +02:00
Kristof De Langhe
cf8bba7112 65272: Revert testing changes 2019-10-04 12:38:47 +02:00
Kristof De Langhe
ba436a6467 65272: Functional EditItemTemplatePageComponent 2019-10-04 11:46:14 +02:00
Kristof De Langhe
4cc1f55272 65272: EditItemTemplatePageComponent 2019-10-03 17:50:48 +02:00
Kristof De Langhe
cddaf539aa 65272: add, delete and edit button for collection item template 2019-10-03 16:36:07 +02:00
Kristof De Langhe
143604fa4d 65272: Intermediate commit 2019-10-03 15:07:05 +02:00
Kristof De Langhe
ef9976cf09 Merge branch 'w2p-63669_Edit-Col/Com-Tabs' into w2p-65272_Edit-collection-item-template 2019-10-03 14:41:15 +02:00
Kristof De Langhe
12be9101e5 65272: ItemTemplateDataService 2019-10-03 13:16:46 +02:00
897 changed files with 23957 additions and 14785 deletions

View File

@@ -1,5 +1,4 @@
# http://editorconfig.org
# Editor configuration, see https://editorconfig.org
root = true
[*]

7
.gitignore vendored
View File

@@ -7,8 +7,9 @@ npm-debug.log
/build/
/config/environment.dev.js
/config/environment.prod.js
/src/environments/environment.ts
/src/environments/environment.dev.ts
/src/environments/environment.prod.ts
/coverage
@@ -36,3 +37,5 @@ yarn-error.log
package-lock.json
.java-version
.env

View File

@@ -1,10 +1,25 @@
sudo: required
dist: bionic
language: node_js
# Enable caching for yarn & node_modules
cache:
yarn: true
node_js:
- "10"
- "12"
# Install latest chrome (for e2e headless testing). Run an update if needed.
addons:
apt:
sources:
- google-chrome
packages:
- google-chrome-stable
update: true
env:
# Install the latest docker-compose version for ci testing.
# The default installation in travis is not compatible with the latest docker-compose file version.
COMPOSE_VERSION: 1.24.1
# The ci step will test the dspace-angular code against DSpace REST.
# Direct that step to utilize a DSpace REST service that has been started in docker.
DSPACE_REST_HOST: localhost
@@ -12,47 +27,31 @@ env:
DSPACE_REST_NAMESPACE: '/server/api'
DSPACE_REST_SSL: false
services:
- xvfb
before_install:
# Docker Compose Install
- curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
# Check our versions of everything
- echo "Check versions"
- yarn -v
- docker-compose -v
- google-chrome-stable --version
install:
# update chrome
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
- sudo apt-get update
- sudo apt-get install google-chrome-stable
# Start up DSpace 7 using the entities database dump
- docker-compose -f ./docker/docker-compose-travis.yml up -d
# Use the dspace-cli image to populate the assetstore. Trigger a discovery and oai update
# Use the dspace-cli image to populate the assetstore. Triggers a discovery and oai update
- docker-compose -f ./docker/cli.yml -f ./docker/cli.assetstore.yml run --rm dspace-cli
- travis_retry yarn install
before_script:
- echo "Check Docker containers"
- docker container ls
# The following line could be enabled to verify that the rest server is responding.
# Currently, "yarn run build" takes enough time to run to allow the service to be available
#- curl http://localhost:8080/
after_script:
- docker-compose -f ./docker/docker-compose-travis.yml down
language: node_js
node_js:
- "10"
- "12"
cache:
yarn: true
bundler_args: --retry 5
#- echo "Check REST API available (via Docker)"
#- curl http://localhost:8080/server/
script:
- yarn run build
- yarn run ci
- cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
- cat coverage/dspace-angular-cli/lcov.info | ./node_modules/coveralls/bin/coveralls.js
after_script:
# Shutdown docker after everything runs
- docker-compose -f ./docker/docker-compose-travis.yml down

View File

@@ -4,9 +4,9 @@
FROM node:12-alpine
WORKDIR /app
ADD . /app/
EXPOSE 3000
EXPOSE 4000
# We run yarn install with an increased network timeout (5min) to avoid "ESOCKETTIMEDOUT" errors from hub.docker.com
# See, for example https://github.com/yarnpkg/yarn/issues/5540
RUN yarn install --network-timeout 300000
CMD yarn run watch
CMD yarn run start:dev

View File

@@ -29,7 +29,7 @@ yarn install
yarn start
```
Then go to [http://localhost:3000](http://localhost:3000) in your browser
Then go to [http://localhost:4000](http://localhost:4000) in your browser
Not sure where to start? watch the training videos linked in the [Introduction to the technology](#introduction-to-the-technology) section below.
@@ -59,13 +59,13 @@ Table of Contents
Introduction to the technology
------------------------------
You can find more information on the technologies used in this project (Angular.io, Typescript, Angular Universal, RxJS, etc) on the [LYRASIS wiki](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+UI+Technology+Stack)
You can find more information on the technologies used in this project (Angular.io, Angular CLI, Typescript, Angular Universal, RxJS, etc) on the [LYRASIS wiki](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+UI+Technology+Stack)
Requirements
------------
- [Node.js](https://nodejs.org), [npm](https://www.npmjs.com/), and [yarn](https://yarnpkg.com)
- Ensure you're running node `v10.x` or `v12.x`, npm >= `v5.x` and yarn >= `v1.x`
- [Node.js](https://nodejs.org) and [yarn](https://yarnpkg.com)
- Ensure you're running node `v10.x` or `v12.x` and yarn >= `v1.x`
If you have [`nvm`](https://github.com/creationix/nvm#install-script) or [`nvm-windows`](https://github.com/coreybutler/nvm-windows) installed, which is highly recommended, you can run `nvm install --lts && nvm use` to install and start using the latest Node LTS.
@@ -77,25 +77,53 @@ Installing
### Configuring
Default configuration file is located in `config/` folder.
Default configuration file is located in `src/environments/` folder.
To change the default configuration values, create local files that override the parameters you need to change:
To change the default configuration values, create local files that override the parameters you need to change. You can use `environment.template.ts` as a starting point.
- Create a new `environment.dev.js` file in `config/` for `devel` environment;
- Create a new `environment.prod.js` file in `config/` for `production` environment;
- Create a new `environment.dev.ts` file in `src/environments/` for a `development` environment;
- Create a new `environment.prod.ts` file in `src/environments/` for a `production` environment;
To use the configuration parameters in your component:
The server settings can also be overwritten using an environment file.
This file should be called `.env` and be placed in the project root.
The following settings can be overwritten in this file:
```bash
import { GLOBAL_CONFIG, GlobalConfig } from '../config';
DSPACE_HOST # The host name of the angular application
DSPACE_PORT # The port number of the angular application
DSPACE_NAMESPACE # The namespace of the angular application
DSPACE_SSL # Whether the angular application uses SSL [true/false]
constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig) {}
DSPACE_REST_HOST # The host name of the REST application
DSPACE_REST_PORT # The port number of the REST application
DSPACE_REST_NAMESPACE # The namespace of the REST application
DSPACE_REST_SSL # Whether the angular REST uses SSL [true/false]
```
The same settings can also be overwritten by setting system environment variables instead, E.g.:
```bash
export DSPACE_HOST=dspace7.4science.cloud
```
The priority works as follows: **environment variable** overrides **variable in `.env` file** overrides **`environment.(prod, dev or test).ts`** overrides **`environment.common.ts`**
#### Using environment variables in code
To use environment variables in a UI component, use:
```typescript
import { environment } from '../environment.ts';
```
This file is generated by the script located in `scripts/set-env.ts`. This script will run automatically before every build, or can be manually triggered using the appropriate `config` script in `package.json`
Running the app
---------------
After you have installed all dependencies you can now run the app. Run `yarn run watch` to start a local server which will watch for changes, rebuild the code, and reload the server for you. You can visit it at `http://localhost:3000`.
After you have installed all dependencies you can now run the app. Run `yarn run start:dev` to start a local server which will watch for changes, rebuild the code, and reload the server for you. You can visit it at `http://localhost:4000`.
### Running in production mode
@@ -115,14 +143,6 @@ yarn run build:prod
This will build the application and put the result in the `dist` folder
### Deploy
```bash
# deploy production in standalone pm2 container
yarn run deploy
# remove production from standalone pm2 container
yarn run undeploy
```
### Running the application with Docker
See [Docker Runtime Options](docker/README.md)
@@ -155,17 +175,15 @@ If you would like to contribute by testing a Pull Request (PR), here's how to do
* Click it, and follow "Step 1" of those instructions to checkout the pull down the PR branch.
2. `yarn run clean` (This resets your local dependencies to ensure you are up-to-date with this PR)
3. `yarn install` (Updates your local dependencies to those in the PR)
4. `yarn start` (Rebuilds the project, and deploys to localhost:3000, by default)
5. At this point, the code from the PR will be deployed to http://localhost:3000. Test it out, and ensure that it does what is described in the PR (or fixes the bug described in the ticket linked to the PR).
4. `yarn start` (Rebuilds the project, and deploys to localhost:4000, by default)
5. At this point, the code from the PR will be deployed to http://localhost:4000. Test it out, and ensure that it does what is described in the PR (or fixes the bug described in the ticket linked to the PR).
Once you have tested the Pull Request, please add a comment and/or approval to the PR to let us know whether you found it to be successful (or not). Thanks!
### Unit Tests
Unit tests use Karma. You can find the configuration file at the same level of this README file:`./karma.conf.js` If you are going to use a remote test enviroment you need to edit the `./karma.conf.js`. Follow the instructions you will find inside it. To executing tests whenever any file changes you can modify the 'autoWatch' option to 'true' and 'singleRun' option to 'false'. A coverage report is also available at: http://localhost:9876/ after you run: `yarn run coverage`.
To correctly run the tests you need to run the build once with: `yarn run build`.
Unit tests use Karma. You can find the configuration file at the same level of this README file:`./karma.conf.js` If you are going to use a remote test environment you need to edit the `./karma.conf.js`. Follow the instructions you will find inside it. To executing tests whenever any file changes you can modify the 'autoWatch' option to 'true' and 'singleRun' option to 'false'. A coverage report is also available at: http://localhost:9876/ after you run: `yarn run coverage`.
The default browser is Google Chrome.
@@ -177,17 +195,13 @@ and run: `yarn run test`
E2E tests use Protractor + Selenium server + browsers. You can find the configuration file at the same level of this README file:`./protractor.conf.js` Protractor is installed as 'local' as a dev dependency.
If you are going to use a remote test enviroment you need to edit the './protractor.conf.js'. Follow the instructions you will find inside it.
If you are going to use a remote test enviroment you need to edit the './e2e//protractor.conf.js'. Follow the instructions you will find inside it.
The default browser is Google Chrome.
Protractor needs a functional instance of the DSpace interface to run the E2E tests, so you need to run:`yarn run watch`
or any command that bring up the DSpace interface.
Place your tests at the following path: `./e2e`
and run: `yarn run e2e`
and run: `ng e2e`
### Continuous Integration (CI) Test
@@ -200,7 +214,7 @@ See [`./docs`](docs) for further documentation.
### Building code documentation
To build the code documentation we use [TYPEDOC](http://typedoc.org). TYPEDOC is a documentation generator for TypeScript projects. It extracts informations from properly formatted comments that can be written within the code files. Follow the instructions [here](http://typedoc.org/guides/doccomments/) to know how to make those comments.
To build the code documentation we use [TYPEDOC](http://typedoc.org). TYPEDOC is a documentation generator for TypeScript projects. It extracts information from properly formatted comments that can be written within the code files. Follow the instructions [here](http://typedoc.org/guides/doccomments/) to know how to make those comments.
Run:`yarn run docs` to produce the documentation that will be available in the 'doc' folder.
@@ -388,7 +402,7 @@ Frequently asked questions
- Where do I write my tests?
- You can write your tests next to your component files. e.g. for `src/app/home/home.component.ts` call it `src/app/home/home.component.spec.ts`
- How do I start the app when I get `EACCES` and `EADDRINUSE` errors?
- The `EADDRINUSE` error means the port `3000` is currently being used and `EACCES` is lack of permission to build files to `./dist/`
- The `EADDRINUSE` error means the port `4000` is currently being used and `EACCES` is lack of permission to build files to `./dist/`
- What are the naming conventions for Angular 2?
- See [the official angular 2 style guide](https://angular.io/styleguide)
- Why is the size of my app larger in development?

View File

@@ -1,13 +1,157 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"defaultCollection": "@ngrx/schematics"
},
"newProjectRoot": "projects",
"projects": {
"core": {
"dspace-angular-cli": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"projectType": "application"
"sourceRoot": "src",
"prefix": "ds",
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack/webpack.common.ts",
"mergeStrategies": {
"loaders": "prepend"
},
},
"outputPath": "dist/browser",
"index": "src/index.html",
"main": "src/main.browser.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"optimization": true,
"outputHashing": "all",
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "3mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "dspace-angular-cli:build",
"port": 4000
},
"configurations": {
"production": {
"browserTarget": "dspace-angular-cli:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "dspace-angular-cli:build"
}
},
"test": {
"builder": "@angular-builders/custom-webpack:karma",
"options": {
"customWebpackConfig": {
"path": "./webpack/webpack.common.ts",
"mergeStrategies": {
"loaders": "prepend"
}
},
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "dspace-angular-cli:serve"
},
"configurations": {
"production": {
"devServerTarget": "dspace-angular-cli:serve:production"
}
}
},
"server": {
"builder": "@angular-builders/custom-webpack:server",
"options": {
"customWebpackConfig": {
"path": "./webpack/webpack.prod.ts",
"mergeStrategies": {
"loaders": "prepend"
}
},
"outputPath": "dist/server",
"main": "src/main.server.ts",
"tsConfig": "tsconfig.server.json"
},
"configurations": {
"production": {
"sourceMap": false,
"optimization": {
"scripts": false,
"styles": true
}
}
}
}
}
}
}
}
},
"defaultProject": "dspace-angular-cli"
}

View File

@@ -1,17 +0,0 @@
# Copyright 2015-2016, Google, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# [START app_yaml]
runtime: nodejs
env: flex
# [END app_yaml]

11
browserslist Normal file
View File

@@ -0,0 +1,11 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -1,4 +0,0 @@
// This configuration is currently only being used for unit tests, end-to-end tests use environment.dev.ts
module.exports = {
};

View File

@@ -11,7 +11,7 @@
- Docker compose file that provides a DSpace CLI container to work with a running DSpace REST container.
- cli.assetstore.yml
- Docker compose file that will download and install data into a DSpace REST assetstore. This script points to a default dataset that will be utilized for CI testing.
- environment.dev.js
- environment.dev.ts
- Environment file for running DSpace Angular in Docker
- local.cfg
- Environment file for running the DSpace 7 REST API in Docker.

View File

@@ -7,7 +7,7 @@ services:
environment:
DSPACE_HOST: dspace-angular
DSPACE_NAMESPACE: /
DSPACE_PORT: '3000'
DSPACE_PORT: '4000'
DSPACE_SSL: "false"
image: dspace/dspace-angular:latest
build:
@@ -16,11 +16,11 @@ services:
networks:
dspacenet:
ports:
- published: 3000
target: 3000
- published: 4000
target: 4000
- published: 9876
target: 9876
stdin_open: true
tty: true
volumes:
- ./environment.dev.js:/app/config/environment.dev.js
- ./environment.dev.ts:/app/src/environments/environment.dev.ts

View File

@@ -1,11 +1,13 @@
/*
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
module.exports = {
// This file is based on environment.template.ts provided by Angular UI
export const environment = {
// Default to using the local REST API (running in Docker)
rest: {
ssl: false,
host: 'localhost',

View File

@@ -1,5 +1,6 @@
dspace.dir=/dspace
db.url=jdbc:postgresql://dspacedb:5432/dspace
dspace.server.url=http://localhost:8080/server
dspace.ui.url=http://localhost:4000
dspace.name=DSpace Started with Docker Compose
solr.server=http://dspacesolr:8983/solr

View File

@@ -1,23 +1,23 @@
# Configuration
Default configuration file is located in `config/` folder. All configuration options should be listed in the default configuration file `config/environment.default.js`. Please do not change this file directly! To change the default configuration values, create local files that override the parameters you need to change:
Default configuration file is located in `src/environments/` folder. All configuration options should be listed in the default configuration file `src/environments/environment.common.ts`. Please do not change this file directly! To change the default configuration values, create local files that override the parameters you need to change. You can use `environment.template.ts` as a starting point.
- Create a new `environment.dev.js` file in `config/` for `devel` environment;
- Create a new `environment.prod.js` file in `config/` for `production` environment;
- Create a new `environment.dev.ts` file in `src/environments/` for `development` environment;
- Create a new `environment.prod.ts` file in `src/environments/` for `production` environment;
Some few configuration options can be overridden by setting environment variables. These and the variable names are listed below.
## Nodejs server
When you start dspace-angular on node, it spins up an http server on which it listens for incoming connections. You can define the ip address and port the server should bind itsself to, and if ssl should be enabled not. By default it listens on `localhost:3000`. If you want it to listen on all your network connections, configure it to bind itself to `0.0.0.0`.
When you start dspace-angular on node, it spins up an http server on which it listens for incoming connections. You can define the ip address and port the server should bind itsself to, and if ssl should be enabled not. By default it listens on `localhost:4000`. If you want it to listen on all your network connections, configure it to bind itself to `0.0.0.0`.
To change this configuration, change the options `ui.host`, `ui.port` and `ui.ssl` in the appropriate configuration file (see above):
```
module.exports = {
// Angular Universal server settings.
export const environment = {
// Angular UI settings.
ui: {
ssl: false,
host: 'localhost',
port: 3000,
port: 4000,
nameSpace: '/'
}
};
@@ -27,7 +27,7 @@ Alternately you can set the following environment variables. If any of these are
```
DSPACE_SSL=true
DSPACE_HOST=localhost
DSPACE_PORT=3000
DSPACE_PORT=4000
DSPACE_NAMESPACE=/
```
@@ -35,14 +35,14 @@ Alternately you can set the following environment variables. If any of these are
dspace-angular connects to your DSpace installation by using its REST endpoint. To do so, you have to define the ip address, port and if ssl should be enabled. You can do this in a configuration file (see above) by adding the following options:
```
module.exports = {
export const environment = {
// The REST API server settings.
rest: {
ssl: true,
host: 'dspace7.4science.it',
host: 'dspace7.4science.cloud',
port: 443,
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
nameSpace: '/dspace-spring-rest/api'
nameSpace: '/server/api'
}
};
```
@@ -50,9 +50,9 @@ module.exports = {
Alternately you can set the following environment variables. If any of these are set, it will override all configuration files:
```
DSPACE_REST_SSL=true
DSPACE_REST_HOST=localhost
DSPACE_REST_PORT=3000
DSPACE_REST_NAMESPACE=/
DSPACE_REST_HOST=dspace7.4science.cloud
DSPACE_REST_PORT=443
DSPACE_REST_NAMESPACE=/server/api
```
## Supporting analytics services other than Google Analytics
@@ -62,4 +62,4 @@ Angulartics can be configured to work with a number of other services besides Go
In order to start using one of these services, select it from the [Angulartics Providers page](https://angulartics.github.io/angulartics2/#providers), and follow the instructions on how to configure it.
The Google Analytics script was added in [`main.browser.ts`](https://github.com/DSpace/dspace-angular/blob/ff04760f4af91ac3e7add5e7424a46cb2439e874/src/main.browser.ts#L33) instead of the `<head>` tag in `index.html` to ensure events get sent when the page is shown in a client's browser, and not when it's rendered on the universal server. Likely you'll want to do the same when adding a new service.
The Google Analytics script was added in [`main.browser.ts`](https://github.com/DSpace/dspace-angular/blob/ff04760f4af91ac3e7add5e7424a46cb2439e874/src/main.browser.ts#L33) instead of the `<head>` tag in `index.html` to ensure events get sent when the page is shown in a client's browser, and not when it's rendered on the universal server. Likely you'll want to do the same when adding a new service.

View File

@@ -1,16 +0,0 @@
import { browser, element, by } from 'protractor';
export class ProtractorPage {
navigateTo() {
return browser.get('/')
.then(() => browser.waitForAngular());
}
getPageTitleText() {
return browser.getTitle();
}
getHomePageNewsText() {
return element(by.css('ds-home-news')).getText();
}
}

10
e2e/protractor-ci.conf.js Normal file
View File

@@ -0,0 +1,10 @@
const config = require('./protractor.conf').config;
config.capabilities = {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--no-sandbox', '--disable-gpu']
}
};
exports.config = config;

View File

@@ -12,10 +12,10 @@ exports.config = {
// Change to 'false' to run tests using a remote Selenium server
directConnect: true,
// Change if the website to test is not on the localhost
baseUrl: 'http://localhost:3000/',
baseUrl: 'http://localhost:4000/',
// -----------------------------------------------------------------
specs: [
'./e2e/**/*.e2e-spec.ts'
'./src/**/*.e2e-spec.ts'
],
// -----------------------------------------------------------------
// Browser and Capabilities: PhantomJS
@@ -67,7 +67,7 @@ exports.config = {
//],
plugins: [{
path: 'node_modules/protractor-istanbul-plugin'
path: '../node_modules/protractor-istanbul-plugin'
}],
framework: 'jasmine',
@@ -79,7 +79,7 @@ exports.config = {
useAllAngular2AppRoots: true,
beforeLaunch: function () {
require('ts-node').register({
project: 'e2e'
project: './e2e/tsconfig.json'
});
},
onPrepare: function () {

View File

@@ -9,11 +9,14 @@ describe('protractor App', () => {
it('should display translated title "DSpace Angular :: Home"', () => {
page.navigateTo();
page.waitUntilNotLoading();
expect<any>(page.getPageTitleText()).toEqual('DSpace Angular :: Home');
});
it('should contain a news section', () => {
page.navigateTo()
.then(() => expect<any>(page.getHomePageNewsText()).toBeDefined());
page.navigateTo();
page.waitUntilNotLoading();
const text = page.getHomePageNewsText();
expect<any>(text).toBeDefined();
});
});

23
e2e/src/app.po.ts Normal file
View File

@@ -0,0 +1,23 @@
import { browser, element, by, protractor, promise } from 'protractor';
export class ProtractorPage {
navigateTo() {
return browser.get('/')
.then(() => browser.waitForAngular());
}
getPageTitleText() {
return browser.getTitle();
}
getHomePageNewsText() {
return element(by.css('ds-home-news')).getText();
}
waitUntilNotLoading(): promise.Promise<unknown> {
const loading = element(by.css('.loader'))
const EC = protractor.ExpectedConditions;
const notLoading = EC.not(EC.presenceOf(loading));
return browser.wait(notLoading, 10000);
}
}

View File

@@ -1,6 +1,5 @@
import { ProtractorPage } from './search-page.po';
import { browser } from 'protractor';
import { promise } from 'selenium-webdriver';
describe('protractor SearchPage', () => {
let page: ProtractorPage;
@@ -23,9 +22,11 @@ describe('protractor SearchPage', () => {
.then(() => page.getRandomScopeOption())
.then((scopeString: string) => {
page.navigateToSearchWithScopeParameter(scopeString);
page.getCurrentScope().then((s: string) => {
expect<string>(s).toEqual(scopeString);
});
page.waitUntilNotLoading();
page.getCurrentScope()
.then((s: string) => {
expect<string>(s).toEqual(scopeString);
})
});
});
@@ -33,13 +34,16 @@ describe('protractor SearchPage', () => {
page.navigateToSearch()
.then(() => page.getRandomScopeOption())
.then((scopeString: string) => {
page.setCurrentScope(scopeString);
page.submitSearchForm();
browser.wait(() => {
return browser.getCurrentUrl().then((url: string) => {
return url.indexOf('scope=' + encodeURI(scopeString)) !== -1;
});
});
page.setCurrentScope(scopeString)
.then(() => page.submitSearchForm())
.then(() => page.waitUntilNotLoading())
.then(() => () => {
browser.wait(() => {
return browser.getCurrentUrl().then((url: string) => {
return url.indexOf('scope=' + encodeURI(scopeString)) !== -1;
})
})
})
});
});

View File

@@ -27,7 +27,7 @@ export class ProtractorPage {
}
setCurrentScope(scope: string) {
element(by.css('#search-form option[value="' + scope + '"]')).click();
return element(by.css('#search-form option[value="' + scope + '"]')).click();
}
setCurrentQuery(query: string) {
@@ -35,7 +35,7 @@ export class ProtractorPage {
}
submitSearchForm() {
element(by.css('#search-form button.search-button')).click();
return element(by.css('#search-form button.search-button')).click();
}
getRandomScopeOption(): promise.Promise<string> {
@@ -46,4 +46,10 @@ export class ProtractorPage {
});
}
waitUntilNotLoading(): promise.Promise<unknown> {
const loading = element(by.css('.loader'));
const EC = protractor.ExpectedConditions;
const notLoading = EC.not(EC.presenceOf(loading));
return browser.wait(notLoading, 10000);
}
}

View File

@@ -1,176 +1,37 @@
/**
* @author: @AngularClass
*/
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
var testWebpackConfig = require('./webpack/webpack.test.js')({
env: 'test'
});
// Uncomment and change to run tests on a remote Selenium server
var webdriverConfig = {
hostname: 'localhost',
port: 4444
};
var configuration = {
client: {
jasmine: {
random: false
}
},
// base path that will be used to resolve all patterns (e.g. files, exclude)
config.set({
basePath: '',
/*
* Frameworks to use
*
* available frameworks: https://npmjs.org/browse/keyword/karma-adapter
*/
frameworks: ['jasmine'],
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require("istanbul-instrumenter-loader"),
require('karma-chrome-launcher'),
require('karma-coverage'),
require("karma-istanbul-preprocessor"),
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
require('karma-mocha-reporter'),
require('karma-phantomjs-launcher'),
require('karma-remap-coverage'),
require('karma-remap-istanbul'),
require('karma-sourcemap-loader'),
require('karma-webdriver-launcher'),
require('karma-webpack')
],
// list of files to exclude
exclude: [],
/*
* list of files / patterns to load in the browser
*
* we are building the test environment in ./spec-bundle.js
*/
files: [{
pattern: './spec-bundle.js',
watched: false,
}],
/*
* preprocess matching files before serving them to the browser
* available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
*/
preprocessors: {
'./spec-bundle.js': [
'istanbul',
'webpack',
'sourcemap'
]
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
// Webpack Config at ./webpack.test.js
webpack: testWebpackConfig,
// save interim raw coverage report in memory
coverageReporter: {
type: 'in-memory'
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/dspace-angular-cli'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
remapCoverageReporter: {
'text-summary': null, // to show summary in console
html: './coverage/html',
cobertura: './coverage/cobertura.xml'
},
remapIstanbulReporter: {
remapOptions: {}, //additional remap options
reports: {
json: './coverage/coverage.json',
lcovonly: './coverage/lcov.info',
html: './coverage/html/',
}
},
/**
* Webpack please don't spam the console when running in karma!
*/
webpackMiddleware: {
/**
* webpack-dev-middleware configuration
* i.e.
*/
noInfo: true,
/**
* and use stats to turn off verbose output
*/
stats: {
/**
* options i.e.
*/
chunks: false
}
},
/*
* test results reporter to use
*
* possible values: 'dots', 'progress'
* available reporters: https://npmjs.org/browse/keyword/karma-reporter
*/
reporters: [
'mocha',
'coverage',
'remap-coverage',
'karma-remap-istanbul'
],
// Karma web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
/*
* level of logging
* possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
*/
logLevel: config.LOG_WARN,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
/*
* start these browsers
* available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
*/
browsers: [
'Chrome'
],
customLaunchers: {
// Remote Selenium Server with Chrome - launcher
'SeleniumChrome': {
base: 'WebDriver',
config: webdriverConfig,
browserName: 'chrome'
},
// Remote Selenium Server with Firefox - launcher
'SeleniumFirefox': {
base: 'WebDriver',
config: webdriverConfig,
browserName: 'firefox'
}
},
reporters: ['mocha', 'kjhtml'],
mochaReporter: {
ignoreSkipped: true
ignoreSkipped: true,
output: 'autowatch'
},
browserNoActivityTimeout: 30000
};
config.set(configuration);
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

5
mock-nodemon.json Normal file
View File

@@ -0,0 +1,5 @@
{
"watch": ["src/environments/mock-environment.ts"],
"ext": "ts",
"exec": "ts-node --project ./tsconfig.ts-node.json scripts/set-mock-env.ts"
}

View File

@@ -1,9 +1,6 @@
{
"watch": [
"dist",
"config",
"src/index.html"
],
"ext": "js ts json html",
"delay": "50"
"watch": ["src/environments"],
"ext": "ts",
"ignore": ["src/environments/environment.ts", "src/environments/mock-environment.ts"],
"exec": "ts-node --project ./tsconfig.ts-node.json scripts/set-env.ts --dev"
}

View File

@@ -1,21 +1,38 @@
{
"name": "dspace-angular",
"version": "0.0.1",
"description": "Angular Universal UI for DSpace",
"repository": {
"type": "git",
"url": "https://github.com/dspace/dspace-angular.git"
},
"license": "BSD-2-Clause",
"engines": {
"node": "10.* || >= 12.*"
},
"resolutions": {
"serialize-javascript": ">= 2.1.2",
"set-value": ">= 2.0.1"
},
"name": "dspace-angular-cli",
"version": "0.0.0",
"scripts": {
"global": "npm install -g @angular/cli marked node-gyp nodemon node-nightly npm-check-updates npm-run-all rimraf typescript ts-node typedoc webpack webpack-bundle-analyzer pm2 rollup",
"ng": "ng",
"config:dev": "ts-node --project ./tsconfig.ts-node.json scripts/set-env.ts --dev",
"config:prod": "ts-node --project ./tsconfig.ts-node.json scripts/set-env.ts --prod",
"config:test": "ts-node --project ./tsconfig.ts-node.json scripts/set-mock-env.ts",
"config:test:watch": "nodemon --config mock-nodemon.json",
"config:dev:watch": "nodemon",
"prestart:dev": "yarn run config:dev",
"prebuild": "yarn run config:dev",
"pretest": "yarn run config:test",
"pretest:watch": "yarn run config:test",
"pretest:headless": "yarn run config:test",
"prebuild:prod": "yarn run config:prod",
"pree2e": "yarn run config:prod",
"pree2e:ci": "yarn run config:prod",
"start": "yarn run start:prod",
"serve": "ts-node --project ./tsconfig.ts-node.json scripts/serve.ts",
"start:dev": "npm-run-all --parallel config:dev:watch serve",
"start:prod": "yarn run build:prod && yarn run serve:ssr",
"build": "ng build",
"build:prod": "yarn run build:ssr",
"build:ssr": "yarn run build:client-and-server-bundles && yarn run compile:server",
"build:client-and-server-bundles": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng build --prod && ng run dspace-angular-cli:server:production --bundleDependencies all",
"test:watch": "npm-run-all --parallel config:test:watch test",
"test": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng test --sourceMap=true --watch=true",
"test:headless": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng test --watch=false --sourceMap=true --browsers=ChromeHeadless --code-coverage",
"lint": "ng lint",
"e2e": "ng e2e",
"e2e:ci": "ng e2e --protractor-config=./e2e/protractor-ci.conf.js",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"ci": "ng lint && yarn run build:prod && yarn test:headless && yarn run e2e:ci",
"clean:coverage": "rimraf coverage",
"clean:dist": "rimraf dist",
"clean:doc": "rimraf doc",
@@ -24,108 +41,67 @@
"clean:bld": "rimraf build",
"clean:node": "rimraf node_modules",
"clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json && yarn run clean:bld",
"clean": "yarn run clean:prod && yarn run clean:node",
"prebuild": "yarn run clean:bld && yarn run clean:dist",
"prebuild:ci": "yarn run prebuild",
"prebuild:prod": "yarn run prebuild",
"build": "node ./scripts/webpack.js --progress --mode development",
"build:ci": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode development && node ./scripts/webpack.js --env.aot --env.client --mode development",
"build:prod": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode production && node ./scripts/webpack.js --env.aot --env.client --mode production",
"postbuild:prod": "yarn run rollup",
"rollup": "rollup -c rollup.config.js",
"prestart": "yarn run build:prod",
"prestart:dev": "yarn run build",
"start": "yarn run server",
"start:dev": "yarn run server",
"deploy": "pm2 start dist/server.js",
"predeploy": "npm run build:prod",
"preundeploy": "pm2 stop dist/server.js",
"undeploy": "pm2 delete dist/server.js",
"postundeploy": "npm run clean:dist",
"server": "node dist/server.js",
"server:watch": "nodemon dist/server.js",
"server:watch:debug": "nodemon --debug dist/server.js",
"syncbuilddir": "node ./scripts/sync-build-dir.js",
"webpack:watch": "node ./scripts/webpack.js -w --mode development",
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch",
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug",
"predebug": "yarn run build",
"predebug:server": "yarn run build",
"debug": "node --debug-brk dist/server.js",
"debug:server": "node-nightly --inspect --debug-brk dist/server.js",
"debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --mode development",
"debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server --mode production",
"ci": "yarn run lint && yarn run build:ci && yarn run test:headless && npm-run-all -p -r server e2e",
"protractor": "node node_modules/protractor/bin/protractor",
"pree2e": "yarn run webdriver:update",
"e2e": "yarn run protractor",
"pretest": "yarn run clean:bld",
"pretest:headless": "yarn run pretest",
"pretest:watch": "yarn run pretest",
"test": "karma start --single-run",
"test:headless": "karma start --single-run --browsers ChromeHeadless",
"test:watch": "karma start --no-single-run --auto-watch",
"webdriver:start": "node node_modules/protractor/bin/webdriver-manager start --seleniumPort 4444",
"webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone --gecko false",
"lint": "tslint \"src/**/*.ts\" && tslint \"e2e/**/*.ts\"",
"docs": "typedoc --options typedoc.json ./src/",
"coverage": "http-server -c-1 -o -p 9875 ./coverage",
"postinstall": "yarn run patch-protractor",
"patch-protractor": "ncp node_modules/webdriver-manager node_modules/protractor/node_modules/webdriver-manager",
"sync-i18n": "node ./scripts/sync-i18n-files.js"
"clean": "yarn run clean:prod && yarn run clean:node && yarn run clean:env",
"clean:env": "rimraf src/environments/environment.ts",
"sync-i18n": "yarn run config:dev && ts-node --project ./tsconfig.ts-node.json scripts/sync-i18n-files.ts"
},
"browser": {
"fs": false,
"path": false,
"http": false,
"https": false
},
"private": true,
"resolutions": {
"minimist": "^1.2.5"
},
"dependencies": {
"@angular/animations": "^8.2.14",
"@angular/animations": "~8.2.14",
"@angular/cdk": "8.2.3",
"@angular/cli": "^8.3.25",
"@angular/common": "^8.2.14",
"@angular/core": "^8.2.14",
"@angular/forms": "^8.2.14",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"@angular/platform-server": "^8.2.14",
"@angular/router": "^8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~8.2.14",
"@angular/platform-server": "~8.2.14",
"@angular/router": "~8.2.14",
"@angularclass/bootloader": "1.0.1",
"@ng-bootstrap/ng-bootstrap": "^5.2.1",
"@ng-bootstrap/ng-bootstrap": "5.2.1",
"@ng-dynamic-forms/core": "8.1.1",
"@ng-dynamic-forms/ui-ng-bootstrap": "8.1.1",
"@ngrx/effects": "^8.6.0",
"@ngrx/router-store": "^8.6.0",
"@ngrx/store": "^8.6.0",
"@nguniversal/express-engine": "^8.2.6",
"@nguniversal/express-engine": "8.2.6",
"@nguniversal/module-map-ngfactory-loader": "v8.2.6",
"@ngx-translate/core": "11.0.1",
"@ngx-translate/http-loader": "4.0.0",
"@nicky-lenaers/ngx-scroll-to": "^3.0.1",
"angular-idle-preload": "3.0.0",
"angular2-text-mask": "9.0.0",
"angulartics2": "7.5.2",
"body-parser": "1.18.2",
"bootstrap": "4.3.1",
"caniuse-lite": "^1.0.30000697",
"cerialize": "0.1.18",
"compression": "1.7.1",
"cli-progress": "^3.8.0",
"cookie-parser": "1.4.3",
"core-js": "^3.6.4",
"debug-loader": "^0.0.1",
"deepmerge": "^4.2.2",
"express": "4.16.2",
"express-session": "1.15.6",
"fast-json-patch": "^2.0.7",
"file-saver": "^1.3.8",
"filesize": "^6.1.0",
"font-awesome": "4.7.0",
"fork-ts-checker-webpack-plugin": "^0.4.10",
"hammerjs": "^2.0.8",
"http-server": "0.11.1",
"https": "1.0.0",
"js-cookie": "2.2.0",
"js.clone": "0.0.3",
"json5": "^2.1.0",
"jsonschema": "1.2.2",
"jwt-decode": "^2.2.0",
"methods": "1.1.2",
"moment": "^2.22.1",
"moment-range": "^4.0.2",
"morgan": "^1.9.1",
"ng-mocks": "^8.1.0",
"ng2-file-upload": "1.2.1",
"ng2-file-upload": "1.4.0",
"ng2-nouislider": "^1.8.2",
"ngx-bootstrap": "^5.3.2",
"ngx-infinite-scroll": "6.0.1",
@@ -134,124 +110,74 @@
"ngx-sortablejs": "^3.1.4",
"nouislider": "^11.0.0",
"pem": "1.13.2",
"postcss-cli": "^6.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "6.5.4",
"rxjs": "~6.4.0",
"rxjs-spy": "^7.5.1",
"sass-resources-loader": "^2.0.0",
"sortablejs": "1.7.0",
"text-mask-core": "5.0.1",
"ts-loader": "^5.2.1",
"ts-md5": "^1.2.4",
"url-parse": "^1.4.7",
"uuid": "^3.2.1",
"tslib": "^1.10.0",
"webfontloader": "1.6.28",
"webpack-cli": "^3.2.0",
"zone.js": "^0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.803.25",
"@angular/compiler": "^8.2.14",
"@angular/compiler-cli": "^8.2.14",
"@angular-builders/custom-webpack": "8.4.1",
"@angular-devkit/build-angular": "~0.803.25",
"@angular/cli": "~8.3.25",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@fortawesome/fontawesome-free": "^5.5.0",
"@ngrx/entity": "^8.6.0",
"@ngrx/schematics": "^8.6.0",
"@ngrx/store-devtools": "^8.6.0",
"@ngtools/webpack": "^8.3.25",
"@schematics/angular": "^0.7.5",
"@types/acorn": "^4.0.3",
"@types/cookie-parser": "1.4.1",
"@types/deep-freeze": "0.1.1",
"@types/express": "^4.11.1",
"@types/express-serve-static-core": "4.16.0",
"@types/express": "^4.17.0",
"@types/file-saver": "^1.3.0",
"@types/hammerjs": "2.0.35",
"@types/jasmine": "^3.3.9",
"@types/jasminewd2": "~2.0.3",
"@types/js-cookie": "2.1.0",
"@types/json5": "^0.0.30",
"@types/lodash": "^4.14.110",
"@types/memory-cache": "0.2.0",
"@types/mime": "2.0.0",
"@types/node": "^11.11.2",
"@types/serve-static": "1.13.2",
"@types/uuid": "^3.4.3",
"@types/webfontloader": "1.6.29",
"@typescript-eslint/eslint-plugin": "^2.12.0",
"@typescript-eslint/parser": "^2.12.0",
"ajv": "^6.1.1",
"ajv-keywords": "^3.1.0",
"angular2-template-loader": "0.6.2",
"autoprefixer": "^9.1.3",
"caniuse-lite": "^1.0.30000697",
"cli-progress": "^3.3.1",
"codelyzer": "^5.1.0",
"commander": "^3.0.2",
"@types/node": "11.15.3",
"codelyzer": "^5.0.0",
"compression-webpack-plugin": "^3.0.1",
"copy-webpack-plugin": "^5.1.1",
"copyfiles": "^2.1.1",
"coveralls": "3.0.0",
"css-loader": "3.4.0",
"cssnano": "^4.1.10",
"deep-freeze": "0.0.1",
"eslint": "^6.7.2",
"exports-loader": "^0.7.0",
"html-webpack-plugin": "3.2.0",
"imports-loader": "0.8.0",
"istanbul-instrumenter-loader": "3.0.1",
"dotenv": "^8.2.0",
"fork-ts-checker-webpack-plugin": "^0.4.10",
"html-webpack-plugin": "^3.2.0",
"jasmine-core": "^3.3.0",
"jasmine-marbles": "0.3.1",
"jasmine-spec-reporter": "4.2.1",
"karma": "4.0.1",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "2.0.0",
"karma-coverage": "1.1.2",
"karma-istanbul-preprocessor": "0.0.2",
"jasmine-spec-reporter": "~4.2.1",
"karma": "^5.0.9",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"karma-mocha-reporter": "2.2.5",
"karma-phantomjs-launcher": "1.0.4",
"karma-remap-coverage": "^0.1.5",
"karma-remap-istanbul": "0.6.0",
"karma-sourcemap-loader": "0.3.7",
"karma-webdriver-launcher": "^1.0.7",
"karma-webpack": "3.0.0",
"ncp": "^2.0.0",
"nodemon": "^1.15.0",
"npm-run-all": "4.1.3",
"nodemon": "^2.0.2",
"npm-run-all": "^4.1.5",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss": "^7.0.2",
"postcss-apply": "0.11.0",
"postcss-cli": "^6.0.0",
"postcss-cssnext": "3.1.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-responsive-type": "1.0.0",
"postcss-smart-import": "0.7.6",
"protractor": "^5.4.2",
"protractor": "^7.0.0",
"protractor-istanbul-plugin": "2.0.0",
"raw-loader": "0.5.1",
"rimraf": "2.6.2",
"rollup": "^0.65.0",
"rollup-plugin-commonjs": "^9.1.6",
"rollup-plugin-node-globals": "1.2.1",
"rollup-plugin-node-resolve": "^3.0.3",
"rollup-plugin-terser": "^2.0.2",
"sass-loader": "7.3.1",
"rimraf": "^3.0.2",
"script-ext-html-webpack-plugin": "2.1.4",
"source-map": "0.7.3",
"source-map-loader": "0.2.4",
"string-replace-loader": "^2.1.1",
"terser-webpack-plugin": "^2.3.1",
"to-string-loader": "1.1.5",
"ts-helpers": "1.1.2",
"ts-node": "4.1.0",
"tslint": "5.11.0",
"typedoc": "^0.9.0",
"typescript": "3.5.3",
"webdriver-manager": "^12.1.7",
"webpack": "^4.29.6",
"ts-loader": "^5.2.0",
"ts-node": "^8.8.1",
"tslint": "~5.15.0",
"typescript": "~3.5.3",
"webpack": "^4.0.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-dev-middleware": "3.2.0",
"webpack-dev-server": "^3.1.11",
"webpack-import-glob-loader": "^1.6.3",
"webpack-merge": "4.1.4",
"webpack-cli": "^3.1.0",
"webpack-node-externals": "1.7.2"
}
}

View File

@@ -1,6 +1,6 @@
module.exports = {
plugins: [
require('postcss-smart-import')(),
require('postcss-import')(),
require('postcss-cssnext')(),
require('postcss-apply')(),
require('postcss-responsive-type')()

View File

@@ -1,21 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import terser from 'rollup-plugin-terser'
export default {
input: 'dist/client.js',
output: {
file: 'dist/client.js',
format: 'iife',
},
plugins: [
nodeResolve({
jsnext: true,
module: true
}),
commonjs({
include: 'node_modules/rxjs/**'
}),
terser.terser()
]
}

11
scripts/serve.ts Normal file
View File

@@ -0,0 +1,11 @@
import { environment } from '../src/environments/environment';
import * as child from 'child_process';
/**
* Calls `ng serve` with the following arguments configured for the UI in the environment file: host, port, nameSpace, ssl
*/
child.spawn(
`ng serve --host ${environment.ui.host} --port ${environment.ui.port} --servePath ${environment.ui.nameSpace} --ssl ${environment.ui.ssl}`,
{ stdio:'inherit', shell: true }
);

116
scripts/set-env.ts Normal file
View File

@@ -0,0 +1,116 @@
import { writeFile } from 'fs';
import { environment as commonEnv } from '../src/environments/environment.common';
import { GlobalConfig } from '../src/config/global-config.interface';
import { ServerConfig } from '../src/config/server-config.interface';
import { hasValue } from '../src/app/shared/empty.util';
// Configure Angular `environment.ts` file path
const targetPath = './src/environments/environment.ts';
// Load node modules
const colors = require('colors');
require('dotenv').config();
const merge = require('deepmerge');
const environment = process.argv[2];
let environmentFilePath;
let production = false;
switch (environment) {
case '--prod':
case '--production':
production = true;
console.log(`Building ${colors.red.bold(`production`)} environment`);
environmentFilePath = '../src/environments/environment.prod.ts';
break;
case '--test':
console.log(`Building ${colors.blue.bold(`test`)} environment`);
environmentFilePath = '../src/environments/environment.test.ts';
break;
default:
console.log(`Building ${colors.green.bold(`development`)} environment`);
environmentFilePath = '../src/environments/environment.dev.ts';
}
const processEnv = {
ui: createServerConfig(
process.env.DSPACE_HOST,
process.env.DSPACE_PORT,
process.env.DSPACE_NAMESPACE,
process.env.DSPACE_SSL),
rest: createServerConfig(
process.env.DSPACE_REST_HOST,
process.env.DSPACE_REST_PORT,
process.env.DSPACE_REST_NAMESPACE,
process.env.DSPACE_REST_SSL)
} as GlobalConfig;
import(environmentFilePath)
.then((file) => generateEnvironmentFile(merge.all([commonEnv, file.environment, processEnv])))
.catch(() => {
console.log(colors.yellow.bold(`No specific environment file found for ` + environment));
generateEnvironmentFile(merge(commonEnv, processEnv))
});
function generateEnvironmentFile(file: GlobalConfig): void {
file.production = production;
buildBaseUrls(file);
const contents = `export const environment = ` + JSON.stringify(file);
writeFile(targetPath, contents, (err) => {
if (err) {
throw console.error(err);
} else {
console.log(`Angular ${colors.bold('environment.ts')} file generated correctly at ${colors.bold(targetPath)} \n`);
}
});
}
// allow to override a few important options by environment variables
function createServerConfig(host?: string, port?: string, nameSpace?: string, ssl?: string): ServerConfig {
const result = {} as any;
if (hasValue(host)) {
result.host = host;
}
if (hasValue(nameSpace)) {
result.nameSpace = nameSpace;
}
if (hasValue(port)) {
result.port = Number(port);
}
if (hasValue(ssl)) {
result.ssl = ssl.trim().match(/^(true|1|yes)$/i) ? true : false;
}
return result;
}
function buildBaseUrls(config: GlobalConfig): void {
for (const key in config) {
if (config.hasOwnProperty(key) && config[key].host) {
config[key].baseUrl = [
getProtocol(config[key].ssl),
getHost(config[key].host),
getPort(config[key].port),
getNameSpace(config[key].nameSpace)
].join('');
}
}
}
function getProtocol(ssl: boolean): string {
return ssl ? 'https://' : 'http://';
}
function getHost(host: string): string {
return host;
}
function getPort(port: number): string {
return port ? (port !== 80 && port !== 443) ? ':' + port : '' : '';
}
function getNameSpace(nameSpace: string): string {
return nameSpace ? nameSpace.charAt(0) === '/' ? nameSpace : '/' + nameSpace : '';
}

11
scripts/set-mock-env.ts Normal file
View File

@@ -0,0 +1,11 @@
import { copyFile } from 'fs';
// Configure Angular `environment.ts` file path
const sourcePath = './src/environments/mock-environment.ts';
const targetPath = './src/environments/environment.ts';
// destination.txt will be created or overwritten by default.
copyFile(sourcePath, targetPath, (err) => {
if (err) throw err;
console.log(sourcePath + ' was copied to ' + targetPath);
});

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env node
import { projectRoot} from '../webpack/helpers';
const commander = require('commander');
const fs = require('fs');
const JSON5 = require('json5');
const _cliProgress = require('cli-progress');
const _ = require('lodash');
const {projectRoot} = require('../webpack/helpers');
const program = new commander.Command();
program.version('1.0.0', '-v, --version');
@@ -13,8 +12,8 @@ const NEW_MESSAGE_TODO = '// TODO New key - Add a translation';
const MESSAGE_CHANGED_TODO = '// TODO Source message changed - Revise the translation';
const COMMENTS_CHANGED_TODO = '// TODO Source comments changed - Revise the translation';
const DEFAULT_SOURCE_FILE_LOCATION = 'resources/i18n/en.json5';
const LANGUAGE_FILES_LOCATION = 'resources/i18n';
const DEFAULT_SOURCE_FILE_LOCATION = 'src/assets/i18n/en.json5';
const LANGUAGE_FILES_LOCATION = 'src/assets/i18n';
parseCliInput();

246
server.ts Normal file
View File

@@ -0,0 +1,246 @@
/**
* *** NOTE ON IMPORTING FROM ANGULAR AND NGUNIVERSAL IN THIS FILE ***
*
* If your application uses third-party dependencies, you'll need to
* either use Webpack or the Angular CLI's `bundleDependencies` feature
* in order to adequately package them for use on the server without a
* node_modules directory.
*
* However, due to the nature of the CLI's `bundleDependencies`, importing
* Angular in this file will create a different instance of Angular than
* the version in the compiled application code. This leads to unavoidable
* conflicts. Therefore, please do not explicitly import from @angular or
* @nguniversal in this file. You can export any needed resources
* from your application's main.server.ts file, as seen below with the
* import for `ngExpressEngine`.
*/
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import 'rxjs';
import * as fs from 'fs';
import * as pem from 'pem';
import * as https from 'https';
import * as morgan from 'morgan';
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as compression from 'compression';
import * as cookieParser from 'cookie-parser';
import { join } from 'path';
import { enableProdMode, NgModuleFactory, Type } from '@angular/core';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
import { environment } from './src/environments/environment';
/*
* Set path for the browser application's dist folder
*/
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { ServerAppModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap } = require('./dist/server/main');
/*
* Create a new express application
*/
const app = express();
/*
* If production mode is enabled in the environment file:
* - Enable Angular's production mode
* - Enable compression for response bodies. See [compression](https://github.com/expressjs/compression)
*/
if (environment.production) {
enableProdMode();
app.use(compression());
}
/*
* Enable request logging
* See [morgan](https://github.com/expressjs/morgan)
*/
app.use(morgan('dev'));
/*
* Add cookie parser middleware
* See [morgan](https://github.com/expressjs/cookie-parser)
*/
app.use(cookieParser());
/*
* Add parser for request bodies
* See [morgan](https://github.com/expressjs/body-parser)
*/
app.use(bodyParser.json());
/*
* Render html pages by running angular server side
*/
app.engine('html', (_, options, callback) =>
ngExpressEngine({
bootstrap: ServerAppModuleNgFactory,
providers: [
{
provide: REQUEST,
useValue: (options as any).req,
},
{
provide: RESPONSE,
useValue: (options as any).req.res,
},
provideModuleMap(LAZY_MODULE_MAP)
],
})(_, (options as any), callback)
);
/*
* Register the view engines for html and ejs
*/
app.set('view engine', 'ejs');
app.set('view engine', 'html');
/*
* Set views folder path to directory where template files are stored
*/
app.set('views', DIST_FOLDER);
/*
* Adds a cache control header to the response
* The cache control value can be configured in the environments file and defaults to max-age=60
*/
function cacheControl(req, res, next) {
// instruct browser to revalidate
res.header('Cache-Control', environment.cache.control || 'max-age=60');
next();
}
/*
* Serve static resources (images, i18n messages, …)
*/
app.get('*.*', cacheControl, express.static(DIST_FOLDER, { index: false }));
/*
* The callback function to serve server side angular
*/
function ngApp(req, res) {
// Object to be set to window.dspace when CSR is used
// this allows us to pass the info in the original request
// to the dspace7-angular instance running in the client's browser
const dspace = {
originalRequest: {
headers: req.headers,
body: req.body,
method: req.method,
params: req.params,
reportProgress: req.reportProgress,
withCredentials: req.withCredentials,
responseType: req.responseType,
urlWithParams: req.urlWithParams
}
};
// callback function for the case when SSR throws an error.
function onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
if (!res._headerSent) {
console.warn('Error in SSR, serving for direct CSR. Error details : ', error);
res.sendFile('index.csr.ejs', {
root: DIST_FOLDER,
scripts: `<script>window.dspace = ${JSON.stringify(dspace)}</script>`
});
}
}
if (environment.universal.preboot) {
// If preboot is enabled, create a new zone for SSR, and
// register the error handler for when it throws an error
Zone.current.fork({ name: 'CSR fallback', onHandleError }).run(() => {
res.render(DIST_FOLDER + '/index.html', {
req,
res,
preboot: environment.universal.preboot,
async: environment.universal.async,
time: environment.universal.time,
baseUrl: environment.ui.nameSpace,
originUrl: environment.ui.baseUrl,
requestUrl: req.originalUrl
});
});
} else {
// If preboot is disabled, just serve the client side ejs template and pass it the required
// variables
console.log('Universal off, serving for direct CSR');
res.render('index-csr.ejs', {
root: DIST_FOLDER,
scripts: `<script>window.dspace = ${JSON.stringify(dspace)}</script>`
});
}
}
// Register the ngApp callback function to handle incoming requests
app.get('*', ngApp);
/*
* Callback function for when the server has started
*/
function serverStarted() {
console.log(`[${new Date().toTimeString()}] Listening at ${environment.ui.baseUrl}`);
}
/*
* Create an HTTPS server with the configured port and host
* @param keys SSL credentials
*/
function createHttpsServer(keys) {
https.createServer({
key: keys.serviceKey,
cert: keys.certificate
}, app).listen(environment.ui.port, environment.ui.host, () => {
serverStarted();
});
}
/*
* If SSL is enabled
* - Read credentials from configuration files
* - Call script to start an HTTPS server with these credentials
* When SSL is disabled
* - Start an HTTP server on the configured port and host
*/
if (environment.ui.ssl) {
let serviceKey;
try {
serviceKey = fs.readFileSync('./config/ssl/key.pem');
} catch (e) {
console.warn('Service key not found at ./config/ssl/key.pem');
}
let certificate;
try {
certificate = fs.readFileSync('./config/ssl/cert.pem');
} catch (e) {
console.warn('Certificate not found at ./config/ssl/key.pem');
}
if (serviceKey && certificate) {
createHttpsServer({
serviceKey: serviceKey,
certificate: certificate
});
} else {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
pem.createCertificate({
days: 1,
selfSigned: true
}, (error, keys) => {
createHttpsServer(keys);
});
}
} else {
app.listen(environment.ui.port, environment.ui.host, () => {
serverStarted();
});
}

View File

@@ -1,48 +0,0 @@
/**
* @author: @AngularClass
*/
/*
* When testing with webpack and ES6, we have to do some extra
* things to get testing to work right. Because we are gonna write tests
* in ES6 too, we have to compile those as well. That's handled in
* karma.conf.js with the karma-webpack plugin. This is the entry
* file for webpack test. Just like webpack will create a bundle.js
* file for our client, when we run test, it will compile and bundle them
* all here! Crazy huh. So we need to do some setup
*/
Error.stackTraceLimit = Infinity;
require('core-js/es');
require('core-js/features/reflect');
// Typescript emit helpers polyfill
require('ts-helpers');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy'); // since zone.js 0.6.15
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch'); // put here since zone.js 0.6.14
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
// RxJS
require('rxjs');
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(
browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting()
);
var tests = require.context('./src', true, /\.spec\.ts$/);
tests.keys().forEach(tests);
// includes all modules into test coverage
const modules = require.context('./src/app', true, /\.module\.ts$/);
modules.keys().forEach(modules);

View File

@@ -6,7 +6,7 @@ import { GroupsRegistryComponent } from './group-registry/groups-registry.compon
import { URLCombiner } from '../../core/url-combiner/url-combiner';
import { getAccessControlModulePath } from '../admin-routing.module';
const GROUP_EDIT_PATH = 'groups';
export const GROUP_EDIT_PATH = 'groups';
export function getGroupEditPath(id: string) {
return new URLCombiner(getAccessControlModulePath(), GROUP_EDIT_PATH, id).toString();

View File

@@ -15,15 +15,15 @@ import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { EPerson } from '../../../core/eperson/models/eperson.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../shared/mocks/mock-form-builder-service';
import { MockTranslateLoader } from '../../../shared/mocks/mock-translate-loader';
import { getMockTranslateService } from '../../../shared/mocks/mock-translate.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson-mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { RouterStub } from '../../../shared/testing/router-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
import { EPeopleRegistryComponent } from './epeople-registry.component';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../shared/mocks/translate.service.mock';
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../shared/testing/router.stub';
describe('EPeopleRegistryComponent', () => {
let component: EPeopleRegistryComponent;
@@ -89,7 +89,7 @@ describe('EPeopleRegistryComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],

View File

@@ -1,6 +1,6 @@
import { EPersonMock } from '../../../shared/testing/eperson-mock';
import { EPeopleRegistryCancelEPersonAction, EPeopleRegistryEditEPersonAction } from './epeople-registry.actions';
import { ePeopleRegistryReducer, EPeopleRegistryState } from './epeople-registry.reducers';
import { EPersonMock } from '../../../shared/testing/eperson.mock';
const initialState: EPeopleRegistryState = {
editEPerson: null,

View File

@@ -14,6 +14,18 @@
[formLayout]="formLayout"
(cancel)="onCancel()"
(submitForm)="onSubmit()">
<button class="btn btn-light" [disabled]="!(canReset$ | async)">
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
</button>
<button class="btn btn-light" [disabled]="!(canDelete$ | async)">
<i class="fa fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}}
</button>
<button *ngIf="!isImpersonated" class="btn btn-light" [disabled]="!(canImpersonate$ | async)" (click)="impersonate()">
<i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}}
</button>
<button *ngIf="isImpersonated" class="btn btn-light" (click)="stopImpersonating()">
<i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}}
</button>
</ds-form>
<div *ngIf="epersonService.getActiveEPerson() | async">

View File

@@ -22,15 +22,17 @@ import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service
import { PageInfo } from '../../../../core/shared/page-info.model';
import { UUIDService } from '../../../../core/shared/uuid.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../../shared/mocks/mock-form-builder-service';
import { getMockTranslateService } from '../../../../shared/mocks/mock-translate.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson-mock';
import { MockTranslateLoader } from '../../../../shared/testing/mock-translate-loader';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
import { EPeopleRegistryComponent } from '../epeople-registry.component';
import { EPersonFormComponent } from './eperson-form.component';
import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
import { AuthService } from '../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../../shared/testing/auth-service.stub';
describe('EPersonFormComponent', () => {
let component: EPersonFormComponent;
@@ -40,6 +42,7 @@ describe('EPersonFormComponent', () => {
let mockEPeople;
let ePersonDataServiceStub: any;
let authService: AuthServiceStub;
beforeEach(async(() => {
mockEPeople = [EPersonMock, EPersonMock2];
@@ -104,12 +107,13 @@ describe('EPersonFormComponent', () => {
};
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
authService = new AuthServiceStub();
TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],
@@ -125,6 +129,7 @@ describe('EPersonFormComponent', () => {
{ provide: Store, useValue: {} },
{ provide: RemoteDataBuildService, useValue: {} },
{ provide: HALEndpointService, useValue: {} },
{ provide: AuthService, useValue: authService },
EPeopleRegistryComponent
],
schemas: [NO_ERRORS_SCHEMA]
@@ -228,4 +233,40 @@ describe('EPersonFormComponent', () => {
});
});
describe('impersonate', () => {
let ePersonId;
beforeEach(() => {
spyOn(authService, 'impersonate').and.callThrough();
ePersonId = 'testEPersonId';
component.epersonInitial = Object.assign(new EPerson(), {
id: ePersonId
});
component.impersonate();
});
it('should call authService.impersonate', () => {
expect(authService.impersonate).toHaveBeenCalledWith(ePersonId);
});
it('should set isImpersonated to true', () => {
expect(component.isImpersonated).toBe(true);
});
});
describe('stopImpersonating', () => {
beforeEach(() => {
spyOn(authService, 'stopImpersonatingAndRefresh').and.callThrough();
component.stopImpersonating();
});
it('should call authService.stopImpersonatingAndRefresh', () => {
expect(authService.stopImpersonatingAndRefresh).toHaveBeenCalled();
});
it('should set isImpersonated to false', () => {
expect(component.isImpersonated).toBe(false);
});
});
});

View File

@@ -7,7 +7,7 @@ import {
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription, combineLatest } from 'rxjs';
import { Subscription, combineLatest, of } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable';
import { take } from 'rxjs/operators';
import { RestResponse } from '../../../../core/cache/response.models';
@@ -22,6 +22,7 @@ import { hasValue } from '../../../../shared/empty.util';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { AuthService } from '../../../../core/auth/auth.service';
@Component({
selector: 'ds-eperson-form',
@@ -105,6 +106,24 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
@Output() cancelForm: EventEmitter<any> = new EventEmitter();
/**
* Observable whether or not the admin is allowed to reset the EPerson's password
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return false)
*/
canReset$: Observable<boolean> = of(false);
/**
* Observable whether or not the admin is allowed to delete the EPerson
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return false)
*/
canDelete$: Observable<boolean> = of(false);
/**
* Observable whether or not the admin is allowed to impersonate the EPerson
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return true)
*/
canImpersonate$: Observable<boolean> = of(true);
/**
* List of subscriptions
*/
@@ -129,13 +148,22 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
epersonInitial: EPerson;
/**
* Whether or not this EPerson is currently being impersonated
*/
isImpersonated = false;
constructor(public epersonService: EPersonDataService,
public groupsDataService: GroupDataService,
private formBuilderService: FormBuilderService,
private translateService: TranslateService,
private notificationsService: NotificationsService,) {
private notificationsService: NotificationsService,
private authService: AuthService) {
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
this.epersonInitial = eperson;
if (hasValue(eperson)) {
this.isImpersonated = this.authService.isImpersonatingUser(eperson.id);
}
}));
}
@@ -364,6 +392,22 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
}));
}
/**
* Start impersonating the EPerson
*/
impersonate() {
this.authService.impersonate(this.epersonInitial.id);
this.isImpersonated = true;
}
/**
* Stop impersonating the EPerson
*/
stopImpersonating() {
this.authService.stopImpersonatingAndRefresh();
this.isImpersonated = false;
}
/**
* Cancel the current edit when component is destroyed & unsub all subscriptions
*/

View File

@@ -23,15 +23,15 @@ import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service
import { PageInfo } from '../../../../core/shared/page-info.model';
import { UUIDService } from '../../../../core/shared/uuid.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../../shared/mocks/mock-form-builder-service';
import { MockRouter } from '../../../../shared/mocks/mock-router';
import { getMockTranslateService } from '../../../../shared/mocks/mock-translate.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock';
import { MockTranslateLoader } from '../../../../shared/testing/mock-translate-loader';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
import { GroupFormComponent } from './group-form.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
describe('GroupFormComponent', () => {
let component: GroupFormComponent;
@@ -90,13 +90,13 @@ describe('GroupFormComponent', () => {
};
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
router = new MockRouter();
router = new RouterMock();
TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],

View File

@@ -16,17 +16,17 @@ import { EPerson } from '../../../../../core/eperson/models/eperson.model';
import { Group } from '../../../../../core/eperson/models/group.model';
import { PageInfo } from '../../../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../../../shared/mocks/mock-form-builder-service';
import { MockRouter } from '../../../../../shared/mocks/mock-router';
import { getMockTranslateService } from '../../../../../shared/mocks/mock-translate.service';
import { NotificationsService } from '../../../../../shared/notifications/notifications.service';
import { EPersonMock, EPersonMock2 } from '../../../../../shared/testing/eperson-mock';
import { GroupMock, GroupMock2 } from '../../../../../shared/testing/group-mock';
import { MockTranslateLoader } from '../../../../../shared/testing/mock-translate-loader';
import { NotificationsServiceStub } from '../../../../../shared/testing/notifications-service-stub';
import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { MembersListComponent } from './members-list.component';
import { EPersonMock, EPersonMock2 } from '../../../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
import { getMockTranslateService } from '../../../../../shared/mocks/translate.service.mock';
import { getMockFormBuilderService } from '../../../../../shared/mocks/form-builder-service.mock';
import { TranslateLoaderMock } from '../../../../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../../../../shared/testing/notifications-service.stub';
import { RouterMock } from '../../../../../shared/mocks/router.mock';
describe('MembersListComponent', () => {
let component: MembersListComponent;
@@ -119,7 +119,7 @@ describe('MembersListComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],
@@ -129,7 +129,7 @@ describe('MembersListComponent', () => {
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: FormBuilderService, useValue: builderService },
{ provide: Router, useValue: new MockRouter() },
{ provide: Router, useValue: new RouterMock() },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@@ -14,16 +14,16 @@ import { GroupDataService } from '../../../../../core/eperson/group-data.service
import { Group } from '../../../../../core/eperson/models/group.model';
import { PageInfo } from '../../../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../../../shared/mocks/mock-form-builder-service';
import { MockRouter } from '../../../../../shared/mocks/mock-router';
import { getMockTranslateService } from '../../../../../shared/mocks/mock-translate.service';
import { NotificationsService } from '../../../../../shared/notifications/notifications.service';
import { GroupMock, GroupMock2 } from '../../../../../shared/testing/group-mock';
import { MockTranslateLoader } from '../../../../../shared/testing/mock-translate-loader';
import { NotificationsServiceStub } from '../../../../../shared/testing/notifications-service-stub';
import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { SubgroupsListComponent } from './subgroups-list.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
import { RouterMock } from '../../../../../shared/mocks/router.mock';
import { getMockFormBuilderService } from '../../../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../../../shared/mocks/translate.service.mock';
import { TranslateLoaderMock } from '../../../../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../../../../shared/testing/notifications-service.stub';
describe('SubgroupsListComponent', () => {
let component: SubgroupsListComponent;
@@ -82,7 +82,7 @@ describe('SubgroupsListComponent', () => {
return observableOf(new RestResponse(true, 200, 'Success'));
}
};
routerStub = new MockRouter();
routerStub = new RouterMock();
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
TestBed.configureTestingModule({
@@ -90,7 +90,7 @@ describe('SubgroupsListComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],

View File

@@ -15,15 +15,15 @@ import { EPerson } from '../../../core/eperson/models/eperson.model';
import { Group } from '../../../core/eperson/models/group.model';
import { RouteService } from '../../../core/services/route.service';
import { PageInfo } from '../../../core/shared/page-info.model';
import { MockRouter } from '../../../shared/mocks/mock-router';
import { MockTranslateLoader } from '../../../shared/mocks/mock-translate-loader';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson-mock';
import { GroupMock, GroupMock2 } from '../../../shared/testing/group-mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { routeServiceStub } from '../../../shared/testing/route-service-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
import { GroupsRegistryComponent } from './groups-registry.component';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { TranslateLoaderMock } from '../../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { routeServiceStub } from '../../../shared/testing/route-service.stub';
import { RouterMock } from '../../../shared/mocks/router.mock';
describe('GroupRegistryComponent', () => {
let component: GroupsRegistryComponent;
@@ -82,7 +82,7 @@ describe('GroupRegistryComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
useClass: TranslateLoaderMock
}
}),
],
@@ -92,7 +92,7 @@ describe('GroupRegistryComponent', () => {
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: RouteService, useValue: routeServiceStub },
{ provide: Router, useValue: new MockRouter() },
{ provide: Router, useValue: new RouterMock() },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@@ -47,7 +47,7 @@ export class GroupsRegistryComponent implements OnInit {
// Current search in groups registry
currentSearchQuery: string;
constructor(private groupService: GroupDataService,
constructor(public groupService: GroupDataService,
private ePersonDataService: EPersonDataService,
private translateService: TranslateService,
private notificationsService: NotificationsService,

View File

@@ -4,6 +4,7 @@ import { NgModule } from '@angular/core';
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
import { URLCombiner } from '../../core/url-combiner/url-combiner';
import { getRegistriesModulePath } from '../admin-routing.module';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
const BITSTREAMFORMATS_MODULE_PATH = 'bitstream-formats';
@@ -14,16 +15,28 @@ export function getBitstreamFormatsModulePath() {
@NgModule({
imports: [
RouterModule.forChild([
{path: 'metadata', component: MetadataRegistryComponent, data: {title: 'admin.registries.metadata.title'}},
{
path: 'metadata/:schemaName',
component: MetadataSchemaComponent,
data: {title: 'admin.registries.schema.title'}
path: 'metadata',
resolve: { breadcrumb: I18nBreadcrumbResolver },
data: {title: 'admin.registries.metadata.title', breadcrumbKey: 'admin.registries.metadata'},
children: [
{
path: '',
component: MetadataRegistryComponent
},
{
path: ':schemaName',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: MetadataSchemaComponent,
data: {title: 'admin.registries.schema.title', breadcrumbKey: 'admin.registries.schema'}
}
]
},
{
path: BITSTREAMFORMATS_MODULE_PATH,
resolve: { breadcrumb: I18nBreadcrumbResolver },
loadChildren: './bitstream-formats/bitstream-formats.module#BitstreamFormatsModule',
data: {title: 'admin.registries.bitstream-formats.title'}
data: {title: 'admin.registries.bitstream-formats.title', breadcrumbKey: 'admin.registries.bitstream-formats'}
},
])
]

View File

@@ -11,8 +11,8 @@ import { BitstreamFormatDataService } from '../../../../core/data/bitstream-form
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
import { RouterStub } from '../../../../shared/testing/router-stub';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { AddBitstreamFormatComponent } from './add-bitstream-format.component';
describe('AddBitstreamFormatComponent', () => {

View File

@@ -4,6 +4,7 @@ import { BitstreamFormatsResolver } from './bitstream-formats.resolver';
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
import { I18nBreadcrumbResolver } from '../../../core/breadcrumbs/i18n-breadcrumb.resolver';
const BITSTREAMFORMAT_EDIT_PATH = ':id/edit';
const BITSTREAMFORMAT_ADD_PATH = 'add';
@@ -17,14 +18,18 @@ const BITSTREAMFORMAT_ADD_PATH = 'add';
},
{
path: BITSTREAMFORMAT_ADD_PATH,
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AddBitstreamFormatComponent,
data: {breadcrumbKey: 'admin.registries.bitstream-formats.create'}
},
{
path: BITSTREAMFORMAT_EDIT_PATH,
component: EditBitstreamFormatComponent,
resolve: {
bitstreamFormat: BitstreamFormatsResolver
}
bitstreamFormat: BitstreamFormatsResolver,
breadcrumb: I18nBreadcrumbResolver
},
data: {breadcrumbKey: 'admin.registries.bitstream-formats.edit'}
},
])
],

View File

@@ -11,10 +11,10 @@ import { PaginationComponent } from '../../../shared/pagination/pagination.compo
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { HostWindowService } from '../../../shared/host-window.service';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../core/shared/bitstream-format-support-level';
import { cold, getTestScheduler, hot } from 'jasmine-marbles';

View File

@@ -12,8 +12,8 @@ import { RemoteData } from '../../../../core/data/remote-data';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
import { RouterStub } from '../../../../shared/testing/router-stub';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
describe('EditBitstreamFormatComponent', () => {

View File

@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { RouterStub } from '../../../../shared/testing/router-stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { FormatFormComponent } from './format-form.component';

View File

@@ -11,7 +11,6 @@
<ds-pagination
*ngIf="(metadataSchemas | async)?.payload?.totalElements > 0"
[paginationOptions]="config"
[pageInfoState]="(metadataSchemas | async)?.payload"
[collectionSize]="(metadataSchemas | async)?.payload?.totalElements"
[hideGear]="true"
[hidePagerWhenSinglePage]="true"

View File

@@ -10,14 +10,14 @@ import { RegistryService } from '../../../core/registry/registry.service';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { HostWindowService } from '../../../shared/host-window.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
describe('MetadataRegistryComponent', () => {
let comp: MetadataRegistryComponent;

View File

@@ -4,7 +4,7 @@ import { Observable, combineLatest as observableCombineLatest } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { map, take } from 'rxjs/operators';
import { filter, map, switchMap, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util';
import { RestResponse } from '../../../core/cache/response.models';
import { zip } from 'rxjs/internal/observable/zip';
@@ -12,6 +12,8 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { Route, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { toFindListOptions } from '../../../shared/pagination/pagination.utils';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Component({
selector: 'ds-metadata-registry',
@@ -37,6 +39,11 @@ export class MetadataRegistryComponent {
pageSize: 25
});
/**
* Whether or not the list of MetadataSchemas needs an update
*/
needsUpdate$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
constructor(private registryService: RegistryService,
private notificationsService: NotificationsService,
private router: Router,
@@ -50,14 +57,17 @@ export class MetadataRegistryComponent {
*/
onPageChange(event) {
this.config.currentPage = event;
this.updateSchemas();
this.forceUpdateSchemas();
}
/**
* Update the list of schemas by fetching it from the rest api or cache
*/
private updateSchemas() {
this.metadataSchemas = this.registryService.getMetadataSchemas(this.config);
this.metadataSchemas = this.needsUpdate$.pipe(
filter((update) => update === true),
switchMap(() => this.registryService.getMetadataSchemas(toFindListOptions(this.config)))
);
}
/**
@@ -65,8 +75,7 @@ export class MetadataRegistryComponent {
* a new REST call
*/
public forceUpdateSchemas() {
this.registryService.clearMetadataSchemaRequests().subscribe();
this.updateSchemas();
this.needsUpdate$.next(true);
}
/**
@@ -125,6 +134,7 @@ export class MetadataRegistryComponent {
* Delete all the selected metadata schemas
*/
deleteSchemas() {
this.registryService.clearMetadataSchemaRequests().subscribe();
this.registryService.getSelectedMetadataSchemas().pipe(take(1)).subscribe(
(schemas) => {
const tasks$ = [];

View File

@@ -21,7 +21,8 @@ describe('MetadataSchemaFormComponent', () => {
const registryServiceStub = {
getActiveMetadataSchema: () => observableOf(undefined),
createOrUpdateMetadataSchema: (schema: MetadataSchema) => observableOf(schema),
cancelEditMetadataSchema: () => {}
cancelEditMetadataSchema: () => {},
clearMetadataSchemaRequests: () => observableOf(undefined)
};
const formBuilderServiceStub = {
createFormGroup: () => {

View File

@@ -128,6 +128,7 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
* Emit the updated/created schema using the EventEmitter submitForm
*/
onSubmit() {
this.registryService.clearMetadataSchemaRequests().subscribe();
this.registryService.getActiveMetadataSchema().pipe(take(1)).subscribe(
(schema) => {
const values = {
@@ -139,7 +140,7 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
this.submitForm.emit(newSchema);
});
} else {
this.registryService.createOrUpdateMetadataSchema(Object.assign(new MetadataSchema(), {
this.registryService.createOrUpdateMetadataSchema(Object.assign(new MetadataSchema(), schema, {
id: schema.id,
prefix: (values.prefix ? values.prefix : schema.prefix),
namespace: (values.namespace ? values.namespace : schema.namespace)
@@ -148,6 +149,7 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
});
}
this.clearFields();
this.registryService.cancelEditMetadataSchema();
}
);
}

View File

@@ -27,9 +27,11 @@ describe('MetadataFieldFormComponent', () => {
/* tslint:disable:no-empty */
const registryServiceStub = {
getActiveMetadataField: () => observableOf(undefined),
createOrUpdateMetadataField: (field: MetadataField) => observableOf(field),
createMetadataField: (field: MetadataField) => observableOf(field),
updateMetadataField: (field: MetadataField) => observableOf(field),
cancelEditMetadataField: () => {},
cancelEditMetadataSchema: () => {},
clearMetadataFieldRequests: () => observableOf(undefined)
};
const formBuilderServiceStub = {
createFormGroup: () => {
@@ -74,7 +76,6 @@ describe('MetadataFieldFormComponent', () => {
const scopeNote = 'fakeScopeNote';
const expected = Object.assign(new MetadataField(), {
schema: metadataSchema,
element: element,
qualifier: qualifier,
scopeNote: scopeNote

View File

@@ -153,22 +153,21 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
* Emit the updated/created field using the EventEmitter submitForm
*/
onSubmit() {
this.registryService.clearMetadataFieldRequests().subscribe();
this.registryService.getActiveMetadataField().pipe(take(1)).subscribe(
(field) => {
const values = {
schema: this.metadataSchema,
element: this.element.value,
qualifier: this.qualifier.value,
scopeNote: this.scopeNote.value
};
if (field == null) {
this.registryService.createOrUpdateMetadataField(Object.assign(new MetadataField(), values)).subscribe((newField) => {
this.registryService.createMetadataField(Object.assign(new MetadataField(), values), this.metadataSchema).subscribe((newField) => {
this.submitForm.emit(newField);
});
} else {
this.registryService.createOrUpdateMetadataField(Object.assign(new MetadataField(), {
this.registryService.updateMetadataField(Object.assign(new MetadataField(), field, {
id: field.id,
schema: this.metadataSchema,
element: (values.element ? values.element : field.element),
qualifier: (values.qualifier ? values.qualifier : field.qualifier),
scopeNote: (values.scopeNote ? values.scopeNote : field.scopeNote)
@@ -177,6 +176,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
});
}
this.clearFields();
this.registryService.cancelEditMetadataField();
}
);
}

View File

@@ -1,36 +1,37 @@
<div class="container">
<div class="metadata-schema row">
<div class="col-12">
<div class="col-12" *ngVar="(metadataSchema$ | async) as schema">
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{(metadataSchema | async)?.payload?.prefix}}"</h2>
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{schema?.prefix}}"</h2>
<p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:namespace }}</p>
<p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:{ namespace: schema?.namespace } }}</p>
<ds-metadata-field-form
[metadataSchema]="(metadataSchema | async)?.payload"
[metadataSchema]="schema"
(submitForm)="forceUpdateFields()"></ds-metadata-field-form>
<h3>{{'admin.registries.schema.fields.head' | translate}}</h3>
<ds-pagination
*ngIf="(metadataFields | async)?.payload?.totalElements > 0"
[paginationOptions]="config"
[pageInfoState]="(metadataFields | async)?.payload"
[collectionSize]="(metadataFields | async)?.payload?.totalElements"
[hideGear]="false"
[hidePagerWhenSinglePage]="true"
(pageChange)="onPageChange($event)">
<div class="table-responsive">
<table id="metadata-fields" class="table table-striped table-hover">
<thead>
<ng-container *ngVar="(metadataFields$ | async)?.payload as fields">
<ds-pagination
*ngIf="fields?.totalElements > 0"
[paginationOptions]="config"
[pageInfoState]="fields"
[collectionSize]="fields?.totalElements"
[hideGear]="false"
[hidePagerWhenSinglePage]="true"
(pageChange)="onPageChange($event)">
<div class="table-responsive">
<table id="metadata-fields" class="table table-striped table-hover">
<thead>
<tr>
<th></th>
<th scope="col">{{'admin.registries.schema.fields.table.field' | translate}}</th>
<th scope="col">{{'admin.registries.schema.fields.table.scopenote' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let field of (metadataFields | async)?.payload?.page"
</thead>
<tbody>
<tr *ngFor="let field of fields?.page"
[ngClass]="{'table-primary' : isActive(field) | async}">
<td>
<label>
@@ -39,22 +40,23 @@
(change)="selectMetadataField(field, $event)">
</label>
</td>
<td class="selectable-row" (click)="editField(field)">{{(metadataSchema | async)?.payload?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td>
<td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td>
<td class="selectable-row" (click)="editField(field)">{{field.scopeNote}}</td>
</tr>
</tbody>
</table>
</tbody>
</table>
</div>
</ds-pagination>
<div *ngIf="fields?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
{{'admin.registries.schema.fields.no-items' | translate}}
</div>
</ds-pagination>
<div *ngIf="(metadataFields | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
{{'admin.registries.schema.fields.no-items' | translate}}
</div>
<div>
<button [routerLink]="['/admin/registries/metadata']" class="btn btn-primary">{{'admin.registries.schema.return' | translate}}</button>
<button *ngIf="(metadataFields | async)?.payload?.page?.length > 0" type="submit" class="btn btn-danger float-right" (click)="deleteFields()">{{'admin.registries.schema.fields.table.delete' | translate}}</button>
</div>
<div>
<button [routerLink]="['/admin/registries/metadata']" class="btn btn-primary">{{'admin.registries.schema.return' | translate}}</button>
<button *ngIf="fields?.page?.length > 0" type="submit" class="btn btn-danger float-right" (click)="deleteFields()">{{'admin.registries.schema.fields.table.delete' | translate}}</button>
</div>
</ng-container>
</div>
</div>

View File

@@ -10,18 +10,19 @@ import { RegistryService } from '../../../core/registry/registry.service';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { HostWindowService } from '../../../shared/host-window.service';
import { RouterStub } from '../../../shared/testing/router-stub';
import { RouterStub } from '../../../shared/testing/router.stub';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { RestResponse } from '../../../core/cache/response.models';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { VarDirective } from '../../../shared/utils/var.directive';
describe('MetadataSchemaComponent', () => {
let comp: MetadataSchemaComponent;
@@ -60,7 +61,7 @@ describe('MetadataSchemaComponent', () => {
element: 'contributor',
qualifier: 'advisor',
scopeNote: null,
schema: mockSchemasList[0]
schema: createSuccessfulRemoteDataObject$(mockSchemasList[0])
},
{
id: 2,
@@ -72,7 +73,7 @@ describe('MetadataSchemaComponent', () => {
element: 'contributor',
qualifier: 'author',
scopeNote: null,
schema: mockSchemasList[0]
schema: createSuccessfulRemoteDataObject$(mockSchemasList[0])
},
{
id: 3,
@@ -84,7 +85,7 @@ describe('MetadataSchemaComponent', () => {
element: 'contributor',
qualifier: 'editor',
scopeNote: 'test scope note',
schema: mockSchemasList[1]
schema: createSuccessfulRemoteDataObject$(mockSchemasList[1])
},
{
id: 4,
@@ -96,15 +97,15 @@ describe('MetadataSchemaComponent', () => {
element: 'contributor',
qualifier: 'illustrator',
scopeNote: null,
schema: mockSchemasList[1]
schema: createSuccessfulRemoteDataObject$(mockSchemasList[1])
}
];
const mockSchemas = createSuccessfulRemoteDataObject$(new PaginatedList(null, mockSchemasList));
/* tslint:disable:no-empty */
const registryServiceStub = {
getMetadataSchemas: () => mockSchemas,
getMetadataFieldsBySchema: (schema: MetadataSchema) => createSuccessfulRemoteDataObject$(new PaginatedList(null, mockFieldsList.filter((value) => value.schema === schema))),
getMetadataSchemaByName: (schemaName: string) => createSuccessfulRemoteDataObject$(mockSchemasList.filter((value) => value.prefix === schemaName)[0]),
getMetadataFieldsBySchema: (schema: MetadataSchema) => createSuccessfulRemoteDataObject$(new PaginatedList(null, mockFieldsList.filter((value) => value.id === 3 || value.id === 4))),
getMetadataSchemaByPrefix: (schemaName: string) => createSuccessfulRemoteDataObject$(mockSchemasList.filter((value) => value.prefix === schemaName)[0]),
getActiveMetadataField: () => observableOf(undefined),
getSelectedMetadataFields: () => observableOf([]),
editMetadataField: (schema) => {},
@@ -124,7 +125,7 @@ describe('MetadataSchemaComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
declarations: [MetadataSchemaComponent, PaginationComponent, EnumKeysPipe],
declarations: [MetadataSchemaComponent, PaginationComponent, EnumKeysPipe, VarDirective],
providers: [
{ provide: RegistryService, useValue: registryServiceStub },
{ provide: ActivatedRoute, useValue: activatedRouteStub },

View File

@@ -5,7 +5,7 @@ import { Observable, combineLatest as observableCombineLatest } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { map, take } from 'rxjs/operators';
import { map, switchMap, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util';
import { RestResponse } from '../../../core/cache/response.models';
import { zip } from 'rxjs/internal/observable/zip';
@@ -13,6 +13,11 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { TranslateService } from '@ngx-translate/core';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
import { toFindListOptions } from '../../../shared/pagination/pagination.utils';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { combineLatest } from 'rxjs/internal/observable/combineLatest';
import { followLink } from '../../../shared/utils/follow-link-config.model';
@Component({
selector: 'ds-metadata-schema',
@@ -24,21 +29,15 @@ import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
* The admin can create, edit or delete metadata fields here.
*/
export class MetadataSchemaComponent implements OnInit {
/**
* The namespace of the metadata schema
*/
namespace;
/**
* The metadata schema
*/
metadataSchema: Observable<RemoteData<MetadataSchema>>;
metadataSchema$: Observable<MetadataSchema>;
/**
* A list of all the fields attached to this metadata schema
*/
metadataFields: Observable<RemoteData<PaginatedList<MetadataField>>>;
metadataFields$: Observable<RemoteData<PaginatedList<MetadataField>>>;
/**
* Pagination config used to display the list of metadata fields
@@ -49,6 +48,11 @@ export class MetadataSchemaComponent implements OnInit {
pageSizeOptions: [25, 50, 100, 200]
});
/**
* Whether or not the list of MetadataFields needs an update
*/
needsUpdate$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
constructor(private registryService: RegistryService,
private route: ActivatedRoute,
private notificationsService: NotificationsService,
@@ -68,7 +72,7 @@ export class MetadataSchemaComponent implements OnInit {
* @param params
*/
initialize(params) {
this.metadataSchema = this.registryService.getMetadataSchemaByName(params.schemaName);
this.metadataSchema$ = this.registryService.getMetadataSchemaByPrefix(params.schemaName).pipe(getFirstSucceededRemoteDataPayload());
this.updateFields();
}
@@ -78,18 +82,20 @@ export class MetadataSchemaComponent implements OnInit {
*/
onPageChange(event) {
this.config.currentPage = event;
this.updateFields();
this.forceUpdateFields();
}
/**
* Update the list of fields by fetching it from the rest api or cache
*/
private updateFields() {
this.metadataSchema.subscribe((schemaData) => {
const schema = schemaData.payload;
this.metadataFields = this.registryService.getMetadataFieldsBySchema(schema, this.config);
this.namespace = {namespace: schemaData.payload.namespace};
});
this.metadataFields$ = combineLatest(this.metadataSchema$, this.needsUpdate$).pipe(
switchMap(([schema, update]: [MetadataSchema, boolean]) => {
if (update) {
return this.registryService.getMetadataFieldsBySchema(schema, toFindListOptions(this.config), followLink('schema'));
}
})
);
}
/**
@@ -97,8 +103,7 @@ export class MetadataSchemaComponent implements OnInit {
* a new REST call
*/
public forceUpdateFields() {
this.registryService.clearMetadataFieldRequests().subscribe();
this.updateFields();
this.needsUpdate$.next(true);
}
/**
@@ -157,6 +162,7 @@ export class MetadataSchemaComponent implements OnInit {
* Delete all the selected metadata fields
*/
deleteFields() {
this.registryService.clearMetadataFieldRequests().subscribe();
this.registryService.getSelectedMetadataFields().pipe(take(1)).subscribe(
(fields) => {
const tasks$ = [];

View File

@@ -3,10 +3,12 @@ import { RouterModule } from '@angular/router';
import { getAdminModulePath } from '../app-routing.module';
import { AdminSearchPageComponent } from './admin-search-page/admin-search-page.component';
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
import { URLCombiner } from '../core/url-combiner/url-combiner';
const REGISTRIES_MODULE_PATH = 'registries';
const ACCESS_CONTROL_MODULE_PATH = 'access-control';
export const ACCESS_CONTROL_MODULE_PATH = 'access-control';
export function getRegistriesModulePath() {
return new URLCombiner(getAdminModulePath(), REGISTRIES_MODULE_PATH).toString();
@@ -32,8 +34,18 @@ export function getAccessControlModulePath() {
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AdminSearchPageComponent,
data: { title: 'admin.search.title', breadcrumbKey: 'admin.search' }
}
]),
},
{
path: 'workflow',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AdminWorkflowPageComponent,
data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' }
},
])
],
providers: [
I18nBreadcrumbResolver,
I18nBreadcrumbsService
]
})
export class AdminRoutingModule {

View File

@@ -10,7 +10,6 @@ import { Bitstream } from '../../../../../core/shared/bitstream.model';
import { Item } from '../../../../../core/shared/item.model';
import { mockTruncatableService } from '../../../../../shared/mocks/mock-trucatable.service';
import { SharedModule } from '../../../../../shared/shared.module';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
@@ -18,6 +17,7 @@ import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { ItemAdminSearchResultGridElementComponent } from './item-admin-search-result-grid-element.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
describe('ItemAdminSearchResultGridElementComponent', () => {
let component: ItemAdminSearchResultGridElementComponent;

View File

@@ -1,9 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MenuService } from '../../../shared/menu/menu.service';
import { MenuServiceStub } from '../../../shared/testing/menu-service-stub';
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service-stub';
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
import { Component } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AdminSidebarSectionComponent } from './admin-sidebar-section.component';

View File

@@ -4,15 +4,17 @@ import { TranslateModule } from '@ngx-translate/core';
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import { AdminSidebarComponent } from './admin-sidebar.component';
import { MenuService } from '../../shared/menu/menu.service';
import { MenuServiceStub } from '../../shared/testing/menu-service-stub';
import { MenuServiceStub } from '../../shared/testing/menu-service.stub';
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
import { CSSVariableServiceStub } from '../../shared/testing/css-variable-service-stub';
import { AuthServiceStub } from '../../shared/testing/auth-service-stub';
import { CSSVariableServiceStub } from '../../shared/testing/css-variable-service.stub';
import { AuthServiceStub } from '../../shared/testing/auth-service.stub';
import { AuthService } from '../../core/auth/auth.service';
import { of as observableOf } from 'rxjs';
import { By } from '@angular/platform-browser';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute } from '@angular/router';
describe('AdminSidebarComponent', () => {
let comp: AdminSidebarComponent;
@@ -21,13 +23,14 @@ describe('AdminSidebarComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), NoopAnimationsModule],
imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule],
declarations: [AdminSidebarComponent],
providers: [
{ provide: Injector, useValue: {} },
{ provide: MenuService, useValue: menuService },
{ provide: CSSVariableService, useClass: CSSVariableServiceStub },
{ provide: AuthService, useClass: AuthServiceStub },
{ provide: ActivatedRoute, useValue: {} },
{
provide: NgbModal, useValue: {
open: () => {/*comment*/}

View File

@@ -93,7 +93,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
/**
* Initialize all menu sections and items for this menu
*/
private createMenu() {
createMenu() {
const menuList = [
/* News */
{
@@ -145,11 +145,17 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
this.modalService.open(CreateItemParentSelectorComponent);
}
} as OnClickMenuItemModel,
// model: {
// type: MenuItemType.LINK,
// text: 'menu.section.new_item',
// link: '/submit'
// } as LinkMenuItemModel,
},
{
id: 'new_process',
parentID: 'new',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.new_process',
link: '/processes/new'
} as LinkMenuItemModel,
},
{
id: 'new_item_version',
@@ -439,8 +445,36 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
icon: 'cogs',
index: 9
},
/* Processes */
{
id: 'processes',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.processes',
link: '/processes'
} as LinkMenuItemModel,
icon: 'terminal',
index: 10
},
/* Workflow */
{
id: 'workflow',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.workflow',
link: '/admin/workflow'
} as LinkMenuItemModel,
icon: 'user-check',
index: 10
},
];
menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, menuSection));
menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, Object.assign(menuSection, {
shouldPersistOnRouteChange: true
})));
}

View File

@@ -1,4 +1,4 @@
::ng-deep {
:host ::ng-deep {
.fa-chevron-right {
padding-left: $spacer/2;
font-size: 0.5rem;
@@ -16,4 +16,4 @@
display: flex;
flex-direction: column;
}
}
}

View File

@@ -2,9 +2,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ExpandableAdminSidebarSectionComponent } from './expandable-admin-sidebar-section.component';
import { MenuService } from '../../../shared/menu/menu.service';
import { MenuServiceStub } from '../../../shared/testing/menu-service-stub';
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service-stub';
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
import { of as observableOf } from 'rxjs';
import { Component } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

View File

@@ -0,0 +1 @@
<ds-configuration-search-page configuration="workflowAdmin" [context]="context"></ds-configuration-search-page>

View File

@@ -0,0 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminWorkflowPageComponent } from './admin-workflow-page.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('AdminSearchPageComponent', () => {
let component: AdminWorkflowPageComponent;
let fixture: ComponentFixture<AdminWorkflowPageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AdminWorkflowPageComponent ],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AdminWorkflowPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,18 @@
import { Component, OnInit } from '@angular/core';
import { Context } from '../../core/shared/context.model';
@Component({
selector: 'ds-admin-workflow-page',
templateUrl: './admin-workflow-page.component.html',
styleUrls: ['./admin-workflow-page.component.scss']
})
/**
* Component that represents a workflow item search page for administrators
*/
export class AdminWorkflowPageComponent {
/**
* The context of this page
*/
context: Context = Context.AdminWorkflowSearch;
}

View File

@@ -0,0 +1,12 @@
<ng-template dsListableObject>
</ng-template>
<div #badges class="position-absolute ml-1">
<div class="workflow-badge">
<span class="badge badge-info">{{ "admin.workflow.item.workflow" | translate }}</span>
</div>
</div>
<ul #buttons class="list-group list-group-flush">
<li class="list-group-item">
<ds-workflow-item-admin-workflow-actions-element *ngIf="object" class="d-flex justify-content-between" [wfi]="dso" [small]="true"></ds-workflow-item-admin-workflow-actions-element>
</li>
</ul>

View File

@@ -0,0 +1,84 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule } from '@ngx-translate/core';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { RouterTestingModule } from '@angular/router/testing';
import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './workflow-item-search-result-admin-workflow-grid-element.component';
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
import { LinkService } from '../../../../../core/cache/builders/link.service';
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
import { Item } from '../../../../../core/shared/item.model';
import { PublicationGridElementComponent } from '../../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component';
import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
import { getMockLinkService } from '../../../../../shared/mocks/link-service.mock';
describe('WorkflowItemAdminWorkflowGridElementComponent', () => {
let component: WorkflowItemSearchResultAdminWorkflowGridElementComponent;
let fixture: ComponentFixture<WorkflowItemSearchResultAdminWorkflowGridElementComponent>;
let id;
let wfi;
let itemRD$;
let linkService;
let object;
function init() {
itemRD$ = createSuccessfulRemoteDataObject$(new Item());
id = '780b2588-bda5-4112-a1cd-0b15000a5339';
object = new WorkflowItemSearchResult()
wfi = new WorkflowItem();
wfi.item = itemRD$;
object.indexableObject = wfi;
linkService = getMockLinkService();
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule(
{
declarations: [WorkflowItemSearchResultAdminWorkflowGridElementComponent, PublicationGridElementComponent, ListableObjectDirective],
imports: [
NoopAnimationsModule,
TranslateModule.forRoot(),
RouterTestingModule.withRoutes([]),
],
providers: [
{ provide: LinkService, useValue: linkService },
{ provide: TruncatableService, useValue: {} },
{ provide: BitstreamDataService, useValue: {} },
],
schemas: [NO_ERRORS_SCHEMA]
})
.overrideComponent(WorkflowItemSearchResultAdminWorkflowGridElementComponent, {
set: {
entryComponents: [PublicationGridElementComponent]
}
})
.compileComponents();
}));
beforeEach(() => {
linkService.resolveLink.and.callFake((a) => a);
fixture = TestBed.createComponent(WorkflowItemSearchResultAdminWorkflowGridElementComponent);
component = fixture.componentInstance;
component.object = object;
component.linkTypes = CollectionElementLinkType;
component.index = 0;
component.viewModes = ViewMode;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retrieve the item using the link service', () => {
expect(linkService.resolveLink).toHaveBeenCalledWith(wfi, followLink('item'));
});
});

View File

@@ -0,0 +1,98 @@
import { Component, ComponentFactoryResolver, ElementRef, ViewChild } from '@angular/core';
import { Item } from '../../../../../core/shared/item.model';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { getListableObjectComponent, listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { Context } from '../../../../../core/shared/context.model';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
import { GenericConstructor } from '../../../../../core/shared/generic-constructor';
import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive';
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
import { Observable } from 'rxjs';
import { LinkService } from '../../../../../core/cache/builders/link.service';
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
import { RemoteData } from '../../../../../core/data/remote-data';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators';
import { take } from 'rxjs/operators';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
@Component({
selector: 'ds-workflow-item-search-result-admin-workflow-grid-element',
styleUrls: ['./workflow-item-search-result-admin-workflow-grid-element.component.scss'],
templateUrl: './workflow-item-search-result-admin-workflow-grid-element.component.html'
})
/**
* The component for displaying a grid element for an workflow item on the admin workflow search page
*/
export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkflowItemSearchResult, WorkflowItem> {
/**
* Directive used to render the dynamic component in
*/
@ViewChild(ListableObjectDirective, { static: true }) listableObjectDirective: ListableObjectDirective;
/**
* The html child that contains the badges html
*/
@ViewChild('badges', { static: true }) badges: ElementRef;
/**
* The html child that contains the button html
*/
@ViewChild('buttons', { static: true }) buttons: ElementRef;
/**
* The item linked to the workflow item
*/
public item$: Observable<Item>;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private linkService: LinkService,
protected truncatableService: TruncatableService,
protected bitstreamDataService: BitstreamDataService
) {
super(truncatableService, bitstreamDataService);
}
/**
* Setup the dynamic child component
* Initialize the item object from the workflow item
*/
ngOnInit(): void {
super.ngOnInit();
this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
this.item$.pipe(take(1)).subscribe((item: Item) => {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent(item));
const viewContainerRef = this.listableObjectDirective.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(
componentFactory,
0,
undefined,
[
[this.badges.nativeElement],
[this.buttons.nativeElement]
]);
(componentRef.instance as any).object = item;
(componentRef.instance as any).index = this.index;
(componentRef.instance as any).linkType = this.linkType;
(componentRef.instance as any).listID = this.listID;
componentRef.changeDetectorRef.detectChanges();
}
)
}
/**
* Fetch the component depending on the item's relationship type, view mode and context
* @returns {GenericConstructor<Component>}
*/
private getComponent(item: Item): GenericConstructor<Component> {
return getListableObjectComponent(item.getRenderTypes(), ViewMode.GridElement, undefined)
}
}

View File

@@ -0,0 +1,10 @@
<div class="workflow-badge">
<span class="badge badge-info">{{ "admin.workflow.item.workflow" | translate }}</span>
</div>
<ds-listable-object-component-loader *ngIf="item$ | async"
[object]="item$ | async"
[viewMode]="viewModes.ListElement"
[index]="index"
[linkType]="linkType"
[listID]="listID"></ds-listable-object-component-loader>
<ds-workflow-item-admin-workflow-actions-element [wfi]="dso" [small]="false"></ds-workflow-item-admin-workflow-actions-element>

View File

@@ -0,0 +1,76 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule } from '@ngx-translate/core';
import { mockTruncatableService } from '../../../../../shared/mocks/mock-trucatable.service';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { RouterTestingModule } from '@angular/router/testing';
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './workflow-item-search-result-admin-workflow-list-element.component';
import { LinkService } from '../../../../../core/cache/builders/link.service';
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
import { Item } from '../../../../../core/shared/item.model';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
import { getMockLinkService } from '../../../../../shared/mocks/link-service.mock';
describe('WorkflowItemAdminWorkflowListElementComponent', () => {
let component: WorkflowItemSearchResultAdminWorkflowListElementComponent;
let fixture: ComponentFixture<WorkflowItemSearchResultAdminWorkflowListElementComponent>;
let id;
let wfi;
let itemRD$;
let linkService;
let object;
function init() {
itemRD$ = createSuccessfulRemoteDataObject$(new Item());
id = '780b2588-bda5-4112-a1cd-0b15000a5339';
object = new WorkflowItemSearchResult()
wfi = new WorkflowItem();
wfi.item = itemRD$;
object.indexableObject = wfi;
linkService = getMockLinkService();
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule(
{
declarations: [WorkflowItemSearchResultAdminWorkflowListElementComponent],
imports: [
NoopAnimationsModule,
TranslateModule.forRoot(),
RouterTestingModule.withRoutes([]),
],
providers: [
{ provide: TruncatableService, useValue: mockTruncatableService },
{ provide: LinkService, useValue: linkService },
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
linkService.resolveLink.and.callFake((a) => a);
fixture = TestBed.createComponent(WorkflowItemSearchResultAdminWorkflowListElementComponent);
component = fixture.componentInstance;
component.object = object;
component.linkTypes = CollectionElementLinkType;
component.index = 0;
component.viewModes = ViewMode;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retrieve the item using the link service', () => {
expect(linkService.resolveLink).toHaveBeenCalledWith(wfi, followLink('item'));
});
});

View File

@@ -0,0 +1,44 @@
import { Component, OnInit } from '@angular/core';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { Context } from '../../../../../core/shared/context.model';
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
import { Observable } from 'rxjs';
import { LinkService } from '../../../../../core/cache/builders/link.service';
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
import { RemoteData } from '../../../../../core/data/remote-data';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators';
import { Item } from '../../../../../core/shared/item.model';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch)
@Component({
selector: 'ds-workflow-item-search-result-admin-workflow-list-element',
styleUrls: ['./workflow-item-search-result-admin-workflow-list-element.component.scss'],
templateUrl: './workflow-item-search-result-admin-workflow-list-element.component.html'
})
/**
* The component for displaying a list element for an workflow item on the admin workflow search page
*/
export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
/**
* The item linked to the workflow item
*/
public item$: Observable<Item>;
constructor(private linkService: LinkService, protected truncatableService: TruncatableService) {
super(truncatableService);
}
/**
* Initialize the item object from the workflow item
*/
ngOnInit(): void {
super.ngOnInit();
this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
}
}

View File

@@ -0,0 +1,7 @@
<a [ngClass]="{'btn-sm': small}" class="btn btn-light my-1 delete-link" [routerLink]="[getDeletePath()]" [title]="'admin.workflow.item.delete' | translate">
<i class="fa fa-trash"></i><span *ngIf="!small" class="d-none d-sm-inline"> {{"admin.workflow.item.delete" | translate}}</span>
</a>
<a [ngClass]="{'btn-sm': small}" class="btn btn-light my-1 send-back-link" [routerLink]="[getSendBackPath()]" [title]="'admin.workflow.item.send-back' | translate">
<i class="fa fa-hand-point-left"></i><span *ngIf="!small" class="d-none d-sm-inline"> {{"admin.workflow.item.send-back" | translate}}</span>
</a>

View File

@@ -0,0 +1,68 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { Item } from '../../../core/shared/item.model';
import {
ITEM_EDIT_DELETE_PATH,
ITEM_EDIT_MOVE_PATH,
ITEM_EDIT_PRIVATE_PATH,
ITEM_EDIT_PUBLIC_PATH,
ITEM_EDIT_REINSTATE_PATH,
ITEM_EDIT_WITHDRAW_PATH
} from '../../../+item-page/edit-item-page/edit-item-page.routing.module';
import { getItemEditPath } from '../../../+item-page/item-page-routing.module';
import { URLCombiner } from '../../../core/url-combiner/url-combiner';
import { WorkflowItemAdminWorkflowActionsComponent } from './workflow-item-admin-workflow-actions.component';
import { WorkflowItem } from '../../../core/submission/models/workflowitem.model';
import { getWorkflowItemDeletePath, getWorkflowItemSendBackPath } from '../../../+workflowitems-edit-page/workflowitems-edit-page-routing.module';
describe('WorkflowItemAdminWorkflowActionsComponent', () => {
let component: WorkflowItemAdminWorkflowActionsComponent;
let fixture: ComponentFixture<WorkflowItemAdminWorkflowActionsComponent>;
let id;
let wfi;
function init() {
id = '780b2588-bda5-4112-a1cd-0b15000a5339';
wfi = new WorkflowItem();
wfi.id = id;
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
RouterTestingModule.withRoutes([])
],
declarations: [WorkflowItemAdminWorkflowActionsComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WorkflowItemAdminWorkflowActionsComponent);
component = fixture.componentInstance;
component.wfi = wfi;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should render a delete button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.delete-link'));
const link = button.nativeElement.href;
expect(link).toContain(new URLCombiner(getWorkflowItemDeletePath(wfi.id)).toString());
});
it('should render a move button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.send-back-link'));
const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getWorkflowItemSendBackPath(wfi.id)).toString());
});
});

View File

@@ -0,0 +1,39 @@
import { Component, Input } from '@angular/core';
import { WorkflowItem } from '../../../core/submission/models/workflowitem.model';
import { getWorkflowItemDeletePath, getWorkflowItemSendBackPath } from '../../../+workflowitems-edit-page/workflowitems-edit-page-routing.module';
@Component({
selector: 'ds-workflow-item-admin-workflow-actions-element',
styleUrls: ['./workflow-item-admin-workflow-actions.component.scss'],
templateUrl: './workflow-item-admin-workflow-actions.component.html'
})
/**
* The component for displaying the actions for a list element for an item on the admin workflow search page
*/
export class WorkflowItemAdminWorkflowActionsComponent {
/**
* The workflow item to perform the actions on
*/
@Input() public wfi: WorkflowItem;
/**
* Whether or not to use small buttons
*/
@Input() public small: boolean;
/**
* Returns the path to the delete page of this workflow item
*/
getDeletePath(): string {
return getWorkflowItemDeletePath(this.wfi.id)
}
/**
* Returns the path to the send back page of this workflow item
*/
getSendBackPath(): string {
return getWorkflowItemSendBackPath(this.wfi.id);
}
}

View File

@@ -12,6 +12,10 @@ import { ItemAdminSearchResultGridElementComponent } from './admin-search-page/a
import { CommunityAdminSearchResultGridElementComponent } from './admin-search-page/admin-search-results/admin-search-result-grid-element/community-search-result/community-admin-search-result-grid-element.component';
import { CollectionAdminSearchResultGridElementComponent } from './admin-search-page/admin-search-results/admin-search-result-grid-element/collection-search-result/collection-admin-search-result-grid-element.component';
import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin-search-results/item-admin-search-result-actions.component';
import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component';
import { WorkflowItemAdminWorkflowActionsComponent } from './admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component';
import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component';
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
@NgModule({
imports: [
@@ -23,13 +27,19 @@ import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin
],
declarations: [
AdminSearchPageComponent,
AdminWorkflowPageComponent,
ItemAdminSearchResultListElementComponent,
CommunityAdminSearchResultListElementComponent,
CollectionAdminSearchResultListElementComponent,
ItemAdminSearchResultGridElementComponent,
CommunityAdminSearchResultGridElementComponent,
CollectionAdminSearchResultGridElementComponent,
ItemAdminSearchResultActionsComponent
ItemAdminSearchResultActionsComponent,
WorkflowItemSearchResultAdminWorkflowListElementComponent,
WorkflowItemSearchResultAdminWorkflowGridElementComponent,
WorkflowItemAdminWorkflowActionsComponent
],
entryComponents: [
ItemAdminSearchResultListElementComponent,
@@ -38,7 +48,11 @@ import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin
ItemAdminSearchResultGridElementComponent,
CommunityAdminSearchResultGridElementComponent,
CollectionAdminSearchResultGridElementComponent,
ItemAdminSearchResultActionsComponent
ItemAdminSearchResultActionsComponent,
WorkflowItemSearchResultAdminWorkflowListElementComponent,
WorkflowItemSearchResultAdminWorkflowGridElementComponent,
WorkflowItemAdminWorkflowActionsComponent
]
})
export class AdminModule {

View File

@@ -8,17 +8,16 @@ import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe';
import { ActivatedRoute, Router } from '@angular/router';
import { BrowseService } from '../../core/browse/browse.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { MockRouter } from '../../shared/mocks/mock-router';
import { RouterMock } from '../../shared/mocks/router.mock';
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
import { Community } from '../../core/shared/community.model';
import { Item } from '../../core/shared/item.model';
import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-options.model';
import { toRemoteData } from '../+browse-by-metadata-page/browse-by-metadata-page.component.spec';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('BrowseByDatePageComponent', () => {
let comp: BrowseByDatePageComponent;
@@ -71,11 +70,10 @@ describe('BrowseByDatePageComponent', () => {
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
declarations: [BrowseByDatePageComponent, EnumKeysPipe, VarDirective],
providers: [
{ provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: BrowseService, useValue: mockBrowseService },
{ provide: DSpaceObjectDataService, useValue: mockDsoService },
{ provide: Router, useValue: new MockRouter() },
{ provide: Router, useValue: new RouterMock() },
{ provide: ChangeDetectorRef, useValue: mockCdRef }
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -11,9 +11,9 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util';
import { ActivatedRoute, Router } from '@angular/router';
import { BrowseService } from '../../core/browse/browse.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
import { environment } from '../../../environments/environment';
@Component({
selector: 'ds-browse-by-date-page',
@@ -33,8 +33,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
*/
defaultMetadataField = 'dc.date.issued';
public constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
protected route: ActivatedRoute,
public constructor(protected route: ActivatedRoute,
protected browseService: BrowseService,
protected dsoService: DSpaceObjectDataService,
protected router: Router,
@@ -77,7 +76,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
updateStartsWithOptions(definition: string, metadataField: string, scope?: string) {
this.subs.push(
this.browseService.getFirstItemFor(definition, scope).subscribe((firstItemRD: RemoteData<Item>) => {
let lowerLimit = this.config.browseBy.defaultLowerLimit;
let lowerLimit = environment.browseBy.defaultLowerLimit;
if (hasValue(firstItemRD.payload)) {
const date = firstItemRD.payload.firstMetadataValue(metadataField);
if (hasValue(date)) {
@@ -88,8 +87,8 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
}
const options = [];
const currentYear = new Date().getFullYear();
const oneYearBreak = Math.floor((currentYear - this.config.browseBy.oneYearLimit) / 5) * 5;
const fiveYearBreak = Math.floor((currentYear - this.config.browseBy.fiveYearLimit) / 10) * 10;
const oneYearBreak = Math.floor((currentYear - environment.browseBy.oneYearLimit) / 5) * 5;
const fiveYearBreak = Math.floor((currentYear - environment.browseBy.fiveYearLimit) / 10) * 10;
if (lowerLimit <= fiveYearBreak) {
lowerLimit -= 10;
} else if (lowerLimit <= oneYearBreak) {

View File

@@ -7,7 +7,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
@@ -19,10 +19,10 @@ import { SortDirection } from '../../core/cache/models/sort-options.model';
import { Item } from '../../core/shared/item.model';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { Community } from '../../core/shared/community.model';
import { MockRouter } from '../../shared/mocks/mock-router';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { RouterMock } from '../../shared/mocks/router.mock';
import { BrowseEntry } from '../../core/shared/browse-entry.model';
import { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('BrowseByMetadataPageComponent', () => {
let comp: BrowseByMetadataPageComponent;
@@ -91,7 +91,7 @@ describe('BrowseByMetadataPageComponent', () => {
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: BrowseService, useValue: mockBrowseService },
{ provide: DSpaceObjectDataService, useValue: mockDsoService },
{ provide: Router, useValue: new MockRouter() }
{ provide: Router, useValue: new RouterMock() }
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@@ -1,17 +1,17 @@
import { BrowseBySwitcherComponent } from './browse-by-switcher.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
import { ActivatedRoute } from '@angular/router';
import * as decorator from './browse-by-decorator';
import createSpy = jasmine.createSpy;
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { environment } from '../../../environments/environment';
describe('BrowseBySwitcherComponent', () => {
let comp: BrowseBySwitcherComponent;
let fixture: ComponentFixture<BrowseBySwitcherComponent>;
const types = ENV_CONFIG.browseBy.types;
const types = environment.browseBy.types;
const params = new BehaviorSubject(createParamsWithId('initialValue'));
@@ -23,7 +23,6 @@ describe('BrowseBySwitcherComponent', () => {
TestBed.configureTestingModule({
declarations: [ BrowseBySwitcherComponent ],
providers: [
{ provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
{ provide: ActivatedRoute, useValue: activatedRouteStub }
],
schemas: [ NO_ERRORS_SCHEMA ]

View File

@@ -1,10 +1,10 @@
import { Component, Inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
import { map, tap } from 'rxjs/operators';
import { getComponentByBrowseByType } from './browse-by-decorator';
import { environment } from '../../../environments/environment';
@Component({
selector: 'ds-browse-by-switcher',
@@ -20,8 +20,7 @@ export class BrowseBySwitcherComponent implements OnInit {
*/
browseByComponent: Observable<any>;
public constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
protected route: ActivatedRoute) {
public constructor(protected route: ActivatedRoute) {
}
/**
@@ -31,7 +30,7 @@ export class BrowseBySwitcherComponent implements OnInit {
this.browseByComponent = this.route.params.pipe(
map((params) => {
const id = params.id;
return this.config.browseBy.types.find((config: BrowseByTypeConfig) => config.id === id);
return environment.browseBy.types.find((config: BrowseByTypeConfig) => config.id === id);
}),
map((config: BrowseByTypeConfig) => getComponentByBrowseByType(config.type))
);

View File

@@ -1,7 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router';
import { Item } from '../../core/shared/item.model';
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
@@ -13,12 +13,11 @@ import { toRemoteData } from '../+browse-by-metadata-page/browse-by-metadata-pag
import { BrowseByTitlePageComponent } from './browse-by-title-page.component';
import { ItemDataService } from '../../core/data/item-data.service';
import { Community } from '../../core/shared/community.model';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { BrowseService } from '../../core/browse/browse.service';
import { MockRouter } from '../../shared/mocks/mock-router';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { RouterMock } from '../../shared/mocks/router.mock';
import { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('BrowseByTitlePageComponent', () => {
let comp: BrowseByTitlePageComponent;
@@ -70,7 +69,7 @@ describe('BrowseByTitlePageComponent', () => {
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: BrowseService, useValue: mockBrowseService },
{ provide: DSpaceObjectDataService, useValue: mockDsoService },
{ provide: Router, useValue: new MockRouter() }
{ provide: Router, useValue: new RouterMock() }
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@@ -1,7 +1,6 @@
import { first } from 'rxjs/operators';
import { BrowseByGuard } from './browse-by-guard';
import { of as observableOf } from 'rxjs';
import { ENV_CONFIG } from '../../config';
describe('BrowseByGuard', () => {
describe('canActivate', () => {
@@ -25,7 +24,7 @@ describe('BrowseByGuard', () => {
translateService = {
instant: () => field
};
guard = new BrowseByGuard(ENV_CONFIG, dsoService, translateService);
guard = new BrowseByGuard(dsoService, translateService);
});
it('should return true, and sets up the data correctly, with a scope and value', () => {

View File

@@ -6,7 +6,7 @@ import { map } from 'rxjs/operators';
import { getSucceededRemoteData } from '../core/shared/operators';
import { TranslateService } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
import { environment } from '../../environments/environment';
@Injectable()
/**
@@ -14,8 +14,7 @@ import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
*/
export class BrowseByGuard implements CanActivate {
constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
protected dsoService: DSpaceObjectDataService,
constructor(protected dsoService: DSpaceObjectDataService,
protected translate: TranslateService) {
}
@@ -24,7 +23,7 @@ export class BrowseByGuard implements CanActivate {
const id = route.params.id || route.queryParams.id || route.data.id;
let metadataField = route.data.metadataField;
if (hasNoValue(metadataField) && hasValue(id)) {
const config = this.config.browseBy.types.find((conf) => conf.id === id);
const config = environment.browseBy.types.find((conf) => conf.id === id);
if (hasValue(config) && hasValue(config.metadataField)) {
metadataField = config.metadataField;
}

View File

@@ -7,11 +7,11 @@ import { CommonModule } from '@angular/common';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SearchFormComponent } from '../../shared/search-form/search-form.component';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
import { RouterStub } from '../../shared/testing/router-stub';
import { SearchServiceStub } from '../../shared/testing/search-service-stub';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
import { RouterStub } from '../../shared/testing/router.stub';
import { SearchServiceStub } from '../../shared/testing/search-service.stub';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { ItemDataService } from '../../core/data/item-data.service';
import { FormsModule } from '@angular/forms';
import { Collection } from '../../core/shared/collection.model';
@@ -20,7 +20,7 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { EventEmitter } from '@angular/core';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service-stub';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { By } from '@angular/platform-browser';
import { PaginatedList } from '../../core/data/paginated-list';
import { PageInfo } from '../../core/shared/page-info.model';
@@ -29,7 +29,7 @@ import { PaginationComponent } from '../../shared/pagination/pagination.componen
import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe';
import { ItemSelectComponent } from '../../shared/object-select/item-select/item-select.component';
import { ObjectSelectService } from '../../shared/object-select/object-select.service';
import { ObjectSelectServiceStub } from '../../shared/testing/object-select-service-stub';
import { ObjectSelectServiceStub } from '../../shared/testing/object-select-service.stub';
import { VarDirective } from '../../shared/utils/var.directive';
import { of as observableOf, of } from 'rxjs/internal/observable/of';
import { RestResponse } from '../../core/cache/response.models';

View File

@@ -9,10 +9,13 @@ import { CreateCollectionPageGuard } from './create-collection-page/create-colle
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
import { URLCombiner } from '../core/url-combiner/url-combiner';
import { getCollectionModulePath } from '../app-routing.module';
import { EditItemTemplatePageComponent } from './edit-item-template-page/edit-item-template-page.component';
import { ItemTemplatePageResolver } from './edit-item-template-page/item-template-page.resolver';
import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-breadcrumb.resolver';
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
import { LinkService } from '../core/cache/builders/link.service';
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
export const COLLECTION_PARENT_PARAMETER = 'parent';
@@ -30,6 +33,7 @@ export function getCollectionCreatePath() {
const COLLECTION_CREATE_PATH = 'create';
const COLLECTION_EDIT_PATH = 'edit';
const ITEMTEMPLATE_PATH = 'itemtemplate';
@NgModule({
imports: [
@@ -58,6 +62,16 @@ const COLLECTION_EDIT_PATH = 'edit';
component: DeleteCollectionPageComponent,
canActivate: [AuthenticatedGuard],
},
{
path: ITEMTEMPLATE_PATH,
component: EditItemTemplatePageComponent,
canActivate: [AuthenticatedGuard],
resolve: {
item: ItemTemplatePageResolver,
breadcrumb: I18nBreadcrumbResolver
},
data: { title: 'collection.edit.template.title', breadcrumbKey: 'collection.edit.template' }
},
{
path: '',
component: CollectionPageComponent,
@@ -75,6 +89,7 @@ const COLLECTION_EDIT_PATH = 'edit';
],
providers: [
CollectionPageResolver,
ItemTemplatePageResolver,
CollectionBreadcrumbResolver,
DSOBreadcrumbsService,
LinkService,

View File

@@ -8,6 +8,8 @@ import { CollectionPageRoutingModule } from './collection-page-routing.module';
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
import { CollectionFormComponent } from './collection-form/collection-form.component';
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
import { EditItemTemplatePageComponent } from './edit-item-template-page/edit-item-template-page.component';
import { EditItemPageModule } from '../+item-page/edit-item-page/edit-item-page.module';
import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
import { SearchService } from '../core/shared/search/search.service';
import { StatisticsModule } from '../statistics/statistics.module';
@@ -17,13 +19,15 @@ import { StatisticsModule } from '../statistics/statistics.module';
CommonModule,
SharedModule,
CollectionPageRoutingModule,
StatisticsModule.forRoot()
StatisticsModule.forRoot(),
EditItemPageModule
],
declarations: [
CollectionPageComponent,
CreateCollectionPageComponent,
DeleteCollectionPageComponent,
CollectionFormComponent,
EditItemTemplatePageComponent,
CollectionItemMapperComponent
],
exports: [

View File

@@ -11,7 +11,7 @@ import { of as observableOf } from 'rxjs';
import { CommunityDataService } from '../../core/data/community-data.service';
import { CreateCollectionPageComponent } from './create-collection-page.component';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
describe('CreateCollectionPageComponent', () => {
let comp: CreateCollectionPageComponent;

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