Compare commits
	
		
			80 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 64ade901de | |||
| eb0dd3f781 | |||
| 66e6cd80d3 | |||
| 42851686ca | |||
| e3943d868a | |||
| 7654b795c7 | |||
| 489244f1a9 | |||
| cbcce336d6 | |||
| 52a96b2a4f | |||
| ce6002a631 | |||
| 84a9cf069a | |||
| 83f19a7572 | |||
| a1a4c8b56d | |||
| d8901126d0 | |||
| 854db4ece8 | |||
| 07f2e65fc7 | |||
| ccf09f97d5 | |||
| 8f9a4ebc04 | |||
| f1833f13d5 | |||
| 6a81e369fa | |||
| 597e9e1ea9 | |||
| 9bb027ec4c | |||
| fbbbaa5d49 | |||
| aaec5a3fc9 | |||
| 7cd24cd51d | |||
| c81b34c1d0 | |||
| 7b1acc494d | |||
| 6ff90694e2 | |||
| 157c7c66b5 | |||
| 93249258c6 | |||
| 01c01a46fa | |||
| 0e2a10fe94 | |||
| 0b9f3de47c | |||
| bc239eead1 | |||
| 7a09869b0c | |||
| bdc0de6ada | |||
| 6870a7f9b1 | |||
| ace1a1b063 | |||
| d87b879cc3 | |||
| b497cebe76 | |||
| 0fa107a75b | |||
| 35b18d72fd | |||
| 4b80f30afb | |||
| ad34e455ce | |||
| 01fdd0bee2 | |||
| 32ffa345cd | |||
| 6fc3c16073 | |||
| 7d58657c80 | |||
| fcd657c10e | |||
| 4ab77c5557 | |||
| 2bbaa500f4 | |||
| 722a20e141 | |||
| 041c24a837 | |||
| 39a3baa00b | |||
| f7acbb1eaa | |||
| e6fbf7aa5b | |||
| 87926e69db | |||
| 36a084eab6 | |||
| a9e319e0c0 | |||
| ea23b97231 | |||
| 7df76f9642 | |||
| f6db117a5e | |||
| 23c3cd605d | |||
| 77690702c0 | |||
| e0093480d9 | |||
| c7679b7a67 | |||
| e6ac34bde8 | |||
| 8c4b595c30 | |||
| be629e5c6b | |||
| 63569684a3 | |||
| 5937a0d7ce | |||
| 4512272c1c | |||
| ce1f3842e0 | |||
| ee01c3a059 | |||
| 81c1537bad | |||
| 98ecfab032 | |||
| b948b8c1a4 | |||
| f856c6ae37 | |||
| 2dd2580530 | |||
| f0c100aee4 | 
							
								
								
									
										24
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -4,18 +4,6 @@ type: docker | |||||||
| name: build:dev | name: build:dev | ||||||
|  |  | ||||||
| steps: | steps: | ||||||
|   - name: build dev |  | ||||||
|     image: plugins/docker |  | ||||||
|     depends_on: [clone] |  | ||||||
|     settings: |  | ||||||
|       username: |  | ||||||
|         from_secret: DOCKER_REGISTRY_USER |  | ||||||
|       password: |  | ||||||
|         from_secret: DOCKER_REGISTRY_PASSWORD |  | ||||||
|       repo: registry.odit.services/lfk/frontend |  | ||||||
|       tags: |  | ||||||
|         - dev |  | ||||||
|       registry: registry.odit.services |  | ||||||
|   - name: run full license export |   - name: run full license export | ||||||
|     depends_on: ["clone"] |     depends_on: ["clone"] | ||||||
|     image: node:alpine |     image: node:alpine | ||||||
| @@ -33,6 +21,18 @@ steps: | |||||||
|       remote: git@git.odit.services:lfk/frontend.git |       remote: git@git.odit.services:lfk/frontend.git | ||||||
|       ssh_key: |       ssh_key: | ||||||
|         from_secret: GITLAB_SSHKEY |         from_secret: GITLAB_SSHKEY | ||||||
|  |   - name: build dev | ||||||
|  |     image: plugins/docker | ||||||
|  |     depends_on: [clone] | ||||||
|  |     settings: | ||||||
|  |       username: | ||||||
|  |         from_secret: DOCKER_REGISTRY_USER | ||||||
|  |       password: | ||||||
|  |         from_secret: DOCKER_REGISTRY_PASSWORD | ||||||
|  |       repo: registry.odit.services/lfk/frontend | ||||||
|  |       tags: | ||||||
|  |         - dev | ||||||
|  |       registry: registry.odit.services | ||||||
|  |  | ||||||
| trigger: | trigger: | ||||||
|   branch: |   branch: | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,9 +2,105 @@ | |||||||
|  |  | ||||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||||
|  |  | ||||||
|  | #### [0.3.1](https://git.odit.services/lfk/frontend/compare/0.3.0...0.3.1) | ||||||
|  |  | ||||||
|  | - Merge pull request 'feature/16-org-management' (#35) from feature/16-org-management into dev [`#16`](https://git.odit.services/lfk/frontend/issues/16) | ||||||
|  | - 🏃♂️🏃♂️🏃♂️ basic UI components for team management [`d87b879`](https://git.odit.services/lfk/frontend/commit/d87b879cc3d6c771a8a9932409e39068e1b2acdb) | ||||||
|  | - ✨ TeamDetail with edit,delete [`ccf09f9`](https://git.odit.services/lfk/frontend/commit/ccf09f97d5fb476113f24a9559a48bccd75fd0a5) | ||||||
|  | - 🔒 ConfirmTeamDeletion in TeamsOverview [`cbcce33`](https://git.odit.services/lfk/frontend/commit/cbcce336d68b0752daeaf4b5608c43ff6fa11c0d) | ||||||
|  | - 🔒 ConfirmOrgDeletion in OrgDetail [`d890112`](https://git.odit.services/lfk/frontend/commit/d8901126d0cc91cabe3b94a30a83f36e6288126d) | ||||||
|  | - ✨ basic TeamsOverview [`597e9e1`](https://git.odit.services/lfk/frontend/commit/597e9e1ea9da7c73bdcb8ef1ae1a13dfa68ff5a3) | ||||||
|  | - ✨ UX - ConfirmOrgDeletion cancel event reflection in datatable [`84a9cf0`](https://git.odit.services/lfk/frontend/commit/84a9cf069a4aa0940eaacc87ea67e745deabe939) | ||||||
|  | - 🧹 Dashboard - drop header bar [`f1833f1`](https://git.odit.services/lfk/frontend/commit/f1833f13d57595c23abf29bce1a2795cbb05a116) | ||||||
|  | - 🤝 attribution/ credits for icons and illustrations [`eb0dd3f`](https://git.odit.services/lfk/frontend/commit/eb0dd3f781f739c6511588a8e153c14a39096025) | ||||||
|  | - ✨ added new empty states [`66e6cd8`](https://git.odit.services/lfk/frontend/commit/66e6cd80d39ef18a29fd8ac80fbac929bd0c4f8c) | ||||||
|  | - Merge pull request 'feature/14-team-management' (#36) from feature/14-team-management into dev [`4285168`](https://git.odit.services/lfk/frontend/commit/42851686caae69e6672f48cd7df77ee4c2e49092) | ||||||
|  | - 🐞 fix Dashboard sidebar responsiveness [`6a81e36`](https://git.odit.services/lfk/frontend/commit/6a81e369fa20f0bb2846365a45f96e91e95fe2e7) | ||||||
|  | - ✨ AddTeamModal working [`9bb027e`](https://git.odit.services/lfk/frontend/commit/9bb027ec4c73483907d396180f739dc3a11b2404) | ||||||
|  | - 🧹 TeamDetail cleanup [`7654b79`](https://git.odit.services/lfk/frontend/commit/7654b795c756ca198bad77068823032714408535) | ||||||
|  | - 🔒 re-enable confirmation in OrgOverview [`ce6002a`](https://git.odit.services/lfk/frontend/commit/ce6002a631dd3c140f3892c750d052e89c135653) | ||||||
|  | - 🧹 TeamsOverview - formatting [`6870a7f`](https://git.odit.services/lfk/frontend/commit/6870a7f9b1fce2f06182dafa502f6dc4bb818bd3) | ||||||
|  | - 🔒 ConfirmOrgDeletion in OrgOverview [`83f19a7`](https://git.odit.services/lfk/frontend/commit/83f19a7572255b5c095c68d688a963dbe3cf4a75) | ||||||
|  | - 🧹 Team cleanups [`07f2e65`](https://git.odit.services/lfk/frontend/commit/07f2e65fc722c0328ee5a8dc4d01fc89c906fa86) | ||||||
|  | - 🔒 ConfirmTeamDeletion in TeamDetail [`489244f`](https://git.odit.services/lfk/frontend/commit/489244f1a9636b9807e751073443f1c767f7b8ca) | ||||||
|  | - 🐞 fix deletion in TeamDetail + TeamsOverview [`e3943d8`](https://git.odit.services/lfk/frontend/commit/e3943d868a6131ea561c4000159b77ff70a4af8b) | ||||||
|  | - 🐞 fix component mount in TeamsEmptyState [`ace1a1b`](https://git.odit.services/lfk/frontend/commit/ace1a1b06379d922df2593c3a7aec77d5f958512) | ||||||
|  | - new license file version [CI SKIP] [`aaec5a3`](https://git.odit.services/lfk/frontend/commit/aaec5a3fc94e13c6d29ea16ab110151aa6dc1156) | ||||||
|  | - 🧹 drop tmp modification from UsersOverview [`854db4e`](https://git.odit.services/lfk/frontend/commit/854db4ece8388a70b8a50c5b4c7ce9be974a2616) | ||||||
|  |  | ||||||
|  | #### [0.3.0](https://git.odit.services/lfk/frontend/compare/0.2.1...0.3.0) | ||||||
|  |  | ||||||
|  | > 15 January 2021 | ||||||
|  |  | ||||||
|  | - Merge pull request 'feature/16-org-management' (#32) from feature/16-org-management into dev [`#16`](https://git.odit.services/lfk/frontend/issues/16) | ||||||
|  | - Merge commit 'fcd657c10ea14290455cfb0bf2de89375a664143' into dev [`#31`](https://git.odit.services/lfk/frontend/issues/31) | ||||||
|  | - ✨ added Org base components [`bdc0de6`](https://git.odit.services/lfk/frontend/commit/bdc0de6adab2db95e6075a993bd50317e9e36eb5) | ||||||
|  | - 🚀RELEASE v0.3.0 [`7cd24cd`](https://git.odit.services/lfk/frontend/commit/7cd24cd51d52efff22f4ee0817f2d89f6efb35ed) | ||||||
|  | - 🏬 OrgDetail ui [`7a09869`](https://git.odit.services/lfk/frontend/commit/7a09869b0ca9d5dd38cf0c0010b71ab9ce6c6f40) | ||||||
|  | - 🏁 finish basic functionality of AddOrgModal + OrgDetail [`9324925`](https://git.odit.services/lfk/frontend/commit/93249258c6b0f34da22f0ed5d290b437d221a8fd) | ||||||
|  | - ✨ basic functionality in OrgDetail [`0e2a10f`](https://git.odit.services/lfk/frontend/commit/0e2a10fe94075b3cda8ef3ebae6a6159a2e6bbf9) | ||||||
|  | - 🐞 fix sidebar mobile-md scaling [`fcd657c`](https://git.odit.services/lfk/frontend/commit/fcd657c10ea14290455cfb0bf2de89375a664143) | ||||||
|  | - 🔨 reorder CI build order for correct license exporting [`7d58657`](https://git.odit.services/lfk/frontend/commit/7d58657c800e9e494c1d1f098ad0dc34d1f0cd8d) | ||||||
|  | - 💬 AddOrgModal bindings [`bc239ee`](https://git.odit.services/lfk/frontend/commit/bc239eead1d1a29c9662d94db797c6bf23e43166) | ||||||
|  | - ✨ improvements in OrgOverview [`0b9f3de`](https://git.odit.services/lfk/frontend/commit/0b9f3de47c0c8b750c38da07e53927ba55ef3499) | ||||||
|  | - 🔨 config compatibility for new Snowpack V3 bundler [`32ffa34`](https://git.odit.services/lfk/frontend/commit/32ffa345cde67b1affe2750add620522c0a24577) | ||||||
|  | - 🧹 general component cleanup [`157c7c6`](https://git.odit.services/lfk/frontend/commit/157c7c66b57c3a5053c780682402d3615fbc046a) | ||||||
|  | - ⏫ basic dependency bump [`6fc3c16`](https://git.odit.services/lfk/frontend/commit/6fc3c16073555fffd55773218c5c2eed361f076b) | ||||||
|  | - 🌎 i18n [`01c01a4`](https://git.odit.services/lfk/frontend/commit/01c01a46faa9332a2e437861fdb42afe962da833) | ||||||
|  | - ⏫ bump gridjs to 3.2.2 [`6ff9069`](https://git.odit.services/lfk/frontend/commit/6ff90694e288356e16f5226a6e0a054e6fec8b3f) | ||||||
|  | - [tmp] - disable serviceworker [`0fa107a`](https://git.odit.services/lfk/frontend/commit/0fa107a75bc33046758bc42523262a566da9f60f) | ||||||
|  | - new license file version [CI SKIP] [`ad34e45`](https://git.odit.services/lfk/frontend/commit/ad34e455ceedc0e0ccca5ccd86f7f011a7667873) | ||||||
|  | - ⏫ Bump Dockerfile builder to 15.5.1-alpine3.12 [`01fdd0b`](https://git.odit.services/lfk/frontend/commit/01fdd0bee2199bb58373aecc9942591a2d45011a) | ||||||
|  | - new license file version [CI SKIP] [`87926e6`](https://git.odit.services/lfk/frontend/commit/87926e69dbd5b93b2c98cd68fb31913259e3cc00) | ||||||
|  | - 🐳 Dockerfile - drop js sourcemaps [`4b80f30`](https://git.odit.services/lfk/frontend/commit/4b80f30afbfb8c16b9395fb310f309c516c48a17) | ||||||
|  |  | ||||||
|  | #### [0.2.1](https://git.odit.services/lfk/frontend/compare/0.2.0...0.2.1) | ||||||
|  |  | ||||||
|  | > 13 January 2021 | ||||||
|  |  | ||||||
|  | - 🔒 UserDetail - WIP on Permissions [`36a084e`](https://git.odit.services/lfk/frontend/commit/36a084eab6bd0c922da29ebb2d260ba803bf9675) | ||||||
|  | - 👪 UserDetail - group edit support [`a9e319e`](https://git.odit.services/lfk/frontend/commit/a9e319e0c0f2bfaba42bc3af875462e394489dc2) | ||||||
|  | - 🙋♂️ UserDetails - group updating [`041c24a`](https://git.odit.services/lfk/frontend/commit/041c24a837d58ff46362699b54e8088f22ba2daa) | ||||||
|  | - ⚡ shared state reactivity - AddUserModal-Users-UsersOverview [`f7acbb1`](https://git.odit.services/lfk/frontend/commit/f7acbb1eaa14ddf41e29ff1db631520123218289) | ||||||
|  | - ✨ AddUserModal + UserDetail - optional username field [`7df76f9`](https://git.odit.services/lfk/frontend/commit/7df76f9642b528586fd654f27148b5502400ffdf) | ||||||
|  | - UserDetail - fixed group updating [`e6fbf7a`](https://git.odit.services/lfk/frontend/commit/e6fbf7aa5b230733ffd92fdfe851b9f86001c859) | ||||||
|  | - 🚀RELEASE v0.2.1 [`2bbaa50`](https://git.odit.services/lfk/frontend/commit/2bbaa500f4ca56e41613cac12228f4e3327180ab) | ||||||
|  | - 💬 UserDetail - info Toasts [`ea23b97`](https://git.odit.services/lfk/frontend/commit/ea23b972315db39e1f800366d52e3bacf9eaf58b) | ||||||
|  | - 🔨 optimized release script [`23c3cd6`](https://git.odit.services/lfk/frontend/commit/23c3cd605db950a5620ea709748216f7ea034385) | ||||||
|  | - 🐞 fix package release script: locales directory [`722a20e`](https://git.odit.services/lfk/frontend/commit/722a20e141079302da8876be1ccc55026c588048) | ||||||
|  | - ⏫ bump @odit/lfk-client-js to 0.0.11 [`f6db117`](https://git.odit.services/lfk/frontend/commit/f6db117a5eca5c9692a4c5d83159917a712a0e63) | ||||||
|  | - 🐞 UserDetail - fix permission reactivity by assignments [`39a3baa`](https://git.odit.services/lfk/frontend/commit/39a3baa00b0575ee3150c7ae26f32995e2e857d9) | ||||||
|  |  | ||||||
|  | #### [0.2.0](https://git.odit.services/lfk/frontend/compare/0.1.6...0.2.0) | ||||||
|  |  | ||||||
|  | > 11 January 2021 | ||||||
|  |  | ||||||
|  | - 🔒 added rendering based on permission level [`5937a0d`](https://git.odit.services/lfk/frontend/commit/5937a0d7ce970d38ddb0e4c6a02d11f8c8b53e9b) | ||||||
|  | - ❌ UserDetail - delete [`4512272`](https://git.odit.services/lfk/frontend/commit/4512272c1c2a5c861d8ac4c9908244df125dc3d9) | ||||||
|  | - 🖊 UserDetail - reactivity on edit + update functionality [`ce1f384`](https://git.odit.services/lfk/frontend/commit/ce1f3842e0f581d9e94ea6079cf223d945f7465d) | ||||||
|  | - 🚀RELEASE v0.2.0 [`7769070`](https://git.odit.services/lfk/frontend/commit/77690702c0461b71ff1b65a44bfdc331d5a42c3e) | ||||||
|  | - [tmp] - disable darkmode + re-enable sw [`c7679b7`](https://git.odit.services/lfk/frontend/commit/c7679b7a67b362a7fbf796f612892bdfac50731c) | ||||||
|  | - 🕕 set manual refresh time to 2min [`be629e5`](https://git.odit.services/lfk/frontend/commit/be629e5c6b076bf9a28dcc953e97478d244d8413) | ||||||
|  | - 🐞 [tmp] - nginx.conf - disable .js file caching [`e6ac34b`](https://git.odit.services/lfk/frontend/commit/e6ac34bde8d288a45e83fc6723a2bbe952f2622a) | ||||||
|  | - ℹ update jwtinfo store on token refresh [`6356968`](https://git.odit.services/lfk/frontend/commit/63569684a392bf0c24c9c2efd7945114d1a230a5) | ||||||
|  |  | ||||||
|  | #### [0.1.6](https://git.odit.services/lfk/frontend/compare/0.1.5...0.1.6) | ||||||
|  |  | ||||||
|  | > 10 January 2021 | ||||||
|  |  | ||||||
|  | - ✨ UsersOverview - user delete [`f0c100a`](https://git.odit.services/lfk/frontend/commit/f0c100aee47d6a5aeb0995db79b268f33bf316e9) | ||||||
|  | - 🔒 UserDetail - added basic layout for permission change [`81c1537`](https://git.odit.services/lfk/frontend/commit/81c1537bada2c87127385d9110d48459cd1b505f) | ||||||
|  | - 🚀RELEASE v0.1.6 [`ee01c3a`](https://git.odit.services/lfk/frontend/commit/ee01c3a059c435add68938657955cbd2c5851c50) | ||||||
|  | - 📧 UserDetail - email input [`f856c6a`](https://git.odit.services/lfk/frontend/commit/f856c6ae3792c93aee148339d89e3978db6e9293) | ||||||
|  | - ✨ UserDetail multiselect layout for groups [`98ecfab`](https://git.odit.services/lfk/frontend/commit/98ecfab0325e35c5418775f7162049b56e5f332f) | ||||||
|  | - UserDetail - placeholder for permission picker 🔒 [`b948b8c`](https://git.odit.services/lfk/frontend/commit/b948b8c1a48e5b4bc6a083139d26100ef4499970) | ||||||
|  |  | ||||||
| #### [0.1.5](https://git.odit.services/lfk/frontend/compare/0.1.4...0.1.5) | #### [0.1.5](https://git.odit.services/lfk/frontend/compare/0.1.4...0.1.5) | ||||||
|  |  | ||||||
|  | > 10 January 2021 | ||||||
|  |  | ||||||
| - Merge commit '16f572480ad55425890061f9dad65fe85f2f39ad' into dev [`#30`](https://git.odit.services/lfk/frontend/issues/30) | - Merge commit '16f572480ad55425890061f9dad65fe85f2f39ad' into dev [`#30`](https://git.odit.services/lfk/frontend/issues/30) | ||||||
|  | - 🚀RELEASE v0.1.5 [`330755c`](https://git.odit.services/lfk/frontend/commit/330755c63e3405533a5da79c84ef4f379eb43e1c) | ||||||
| - ⤵ load dynamic build info in Footer component [`c089bb3`](https://git.odit.services/lfk/frontend/commit/c089bb39298fb1067093c2fa81101130c214947c) | - ⤵ load dynamic build info in Footer component [`c089bb3`](https://git.odit.services/lfk/frontend/commit/c089bb39298fb1067093c2fa81101130c214947c) | ||||||
| - 📅 dynamic copyright year in Footer component [`b8a9e4f`](https://git.odit.services/lfk/frontend/commit/b8a9e4f272f925999b9a032dd009f7498acbfae0) | - 📅 dynamic copyright year in Footer component [`b8a9e4f`](https://git.odit.services/lfk/frontend/commit/b8a9e4f272f925999b9a032dd009f7498acbfae0) | ||||||
| - 👀 improved Footer layout + display on Login component [`43b4065`](https://git.odit.services/lfk/frontend/commit/43b406592ebe115cea04a8dbf36874c0a5bdd7e9) | - 👀 improved Footer layout + display on Login component [`43b4065`](https://git.odit.services/lfk/frontend/commit/43b406592ebe115cea04a8dbf36874c0a5bdd7e9) | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| FROM node:15.4.0-alpine3.12 | FROM node:15.5.1-alpine3.12 | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| RUN npm i -g pnpm | RUN npm i -g pnpm | ||||||
| COPY package.json ./ | COPY package.json ./ | ||||||
| @@ -11,6 +11,7 @@ RUN pnpm run build | |||||||
| # final image | # final image | ||||||
| FROM alpine | FROM alpine | ||||||
| COPY --from=0 /app/build /app | COPY --from=0 /app/build /app | ||||||
|  | RUN rm -rf build/sw.js.map build/workbox-*.js.map | ||||||
| RUN rm -rf /app/build/_dist_/components | RUN rm -rf /app/build/_dist_/components | ||||||
| RUN rm -rf /app/build/_dist_/locales | RUN rm -rf /app/build/_dist_/locales | ||||||
| RUN rm -rf /app/build-manifest.json | RUN rm -rf /app/build-manifest.json | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ http { | |||||||
|         location / { |         location / { | ||||||
|             try_files $uri $uri/ /index.html; |             try_files $uri $uri/ /index.html; | ||||||
|         } |         } | ||||||
|         location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { |         location ~* \.(?:ico|css|gif|jpe?g|png)$ { | ||||||
|             expires 1y; |             expires 1y; | ||||||
|             add_header Pragma public; |             add_header Pragma public; | ||||||
|             add_header Cache-Control "public"; |             add_header Cache-Control "public"; | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,19 +1,18 @@ | |||||||
| { | { | ||||||
| 	"name": "@odit/lfk-frontend", | 	"name": "@odit/lfk-frontend", | ||||||
| 	"version": "0.1.5", | 	"version": "0.3.1", | ||||||
| 	"scripts": { | 	"scripts": { | ||||||
| 		"i18n-order": "node order.js", | 		"i18n-order": "node order.js", | ||||||
| 		"dev": "snowpack dev", | 		"dev": "snowpack dev", | ||||||
| 		"build": "snowpack build", | 		"build": "snowpack build", | ||||||
| 		"build:sw": "workbox generateSW workbox-config.js", | 		"build:sw": "workbox generateSW workbox-config.js", | ||||||
| 		"release": "release-it", | 		"release": "release-it", | ||||||
| 		"changelog": "npx auto-changelog --commit-limit false --template https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs", |  | ||||||
| 		"licenses:export": "license-exporter --json -o public" | 		"licenses:export": "license-exporter --json -o public" | ||||||
| 	}, | 	}, | ||||||
| 	"dependencies": { | 	"dependencies": { | ||||||
| 		"@odit/lfk-client-js": "0.0.10", | 		"@odit/lfk-client-js": "0.0.12", | ||||||
| 		"filepond": "4.25.1", | 		"filepond": "4.25.1", | ||||||
| 		"gridjs": "3.2.1", | 		"gridjs": "3.2.2", | ||||||
| 		"localforage": "1.9.0", | 		"localforage": "1.9.0", | ||||||
| 		"lodash.isequal": "^4.5.0", | 		"lodash.isequal": "^4.5.0", | ||||||
| 		"svelte-filepond": "0.0.1", | 		"svelte-filepond": "0.0.1", | ||||||
| @@ -26,13 +25,13 @@ | |||||||
| 	}, | 	}, | ||||||
| 	"devDependencies": { | 	"devDependencies": { | ||||||
| 		"@odit/license-exporter": "0.0.9", | 		"@odit/license-exporter": "0.0.9", | ||||||
| 		"@snowpack/plugin-svelte": "3.4.1", | 		"@snowpack/plugin-svelte": "3.5.1", | ||||||
| 		"auto-changelog": "^2.2.1", | 		"auto-changelog": "^2.2.1", | ||||||
| 		"autoprefixer": "10.2.1", | 		"autoprefixer": "10.2.1", | ||||||
| 		"postcss": "8.2.4", | 		"postcss": "8.2.4", | ||||||
| 		"postcss-load-config": "3.0.0", | 		"postcss-load-config": "3.0.0", | ||||||
| 		"release-it": "^14.2.2", | 		"release-it": "^14.2.2", | ||||||
| 		"snowpack": "3.0.0-rc.2", | 		"snowpack": "3.0.10", | ||||||
| 		"svelte": "3.31.2", | 		"svelte": "3.31.2", | ||||||
| 		"svelte-preprocess": "4.6.1", | 		"svelte-preprocess": "4.6.1", | ||||||
| 		"workbox-cli": "6.0.2" | 		"workbox-cli": "6.0.2" | ||||||
| @@ -51,7 +50,7 @@ | |||||||
| 			"publish": false | 			"publish": false | ||||||
| 		}, | 		}, | ||||||
| 		"hooks": { | 		"hooks": { | ||||||
| 			"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js  && git add public/index.html" | 			"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js  && git add public/index.html && node order.js  && git add src/locales" | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
|   <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.1.5-RELEASE_INFO</span> |   <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.3.1-RELEASE_INFO</span> | ||||||
|   <noscript>You need to enable JavaScript to run this app.</noscript> |   <noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
|   <script src="/env.js"></script> |   <script src="/env.js"></script> | ||||||
|   <script defer type="module" src="/_dist_/index.js"></script> |   <script defer type="module" src="/_dist_/index.js"></script> | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -5,10 +5,11 @@ module.exports = { | |||||||
| 		src: '/_dist_' | 		src: '/_dist_' | ||||||
| 	}, | 	}, | ||||||
| 	plugins: [ '@snowpack/plugin-svelte' ], | 	plugins: [ '@snowpack/plugin-svelte' ], | ||||||
| 	install: [ | 	routes: [ | ||||||
| 		/* ... */ | 		/* Enable an SPA Fallback in development: */ | ||||||
|  | 		{ match: 'routes', src: '.*', dest: '/index.html' } | ||||||
| 	], | 	], | ||||||
| 	installOptions: { | 	packageOptions: { | ||||||
| 		/* ... */ | 		/* ... */ | ||||||
| 		sourceMap: false | 		sourceMap: false | ||||||
| 	}, | 	}, | ||||||
| @@ -18,13 +19,8 @@ module.exports = { | |||||||
| 	buildOptions: { | 	buildOptions: { | ||||||
| 		/* ... */ | 		/* ... */ | ||||||
| 	}, | 	}, | ||||||
| 	proxy: { |  | ||||||
| 		/* ... */ |  | ||||||
| 	}, |  | ||||||
| 	alias: { | 	alias: { | ||||||
| 		/* ... */ | 		/* ... */ | ||||||
| 	}, | 	}, | ||||||
| 	experiments: { | 	optimize: { bundle: true, minify: true } | ||||||
| 		optimize: { bundle: true, minify: true } |  | ||||||
| 	} |  | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| <script> | <script> | ||||||
|   import "./TailwindStyles.svelte"; |   import "./TailwindStyles.svelte"; | ||||||
|   import "toastify-js/src/toastify.css"; |   import "toastify-js/src/toastify.css"; | ||||||
|  |   import "gridjs/dist/theme/mermaid.css"; | ||||||
|   import { Route, router } from "tinro"; |   import { Route, router } from "tinro"; | ||||||
|   router.subscribe((routeInfo) => { |   router.subscribe((routeInfo) => { | ||||||
|     window.scrollTo(0, 0); |     window.scrollTo(0, 0); | ||||||
| @@ -48,6 +49,7 @@ | |||||||
|   import UserDetail from "./components/UserDetail.svelte"; |   import UserDetail from "./components/UserDetail.svelte"; | ||||||
|   OpenAPI.BASE = config.baseurl; |   OpenAPI.BASE = config.baseurl; | ||||||
|   import { register as registerSW } from "./swmodule"; |   import { register as registerSW } from "./swmodule"; | ||||||
|  |   import TeamDetail from "./components/TeamDetail.svelte"; | ||||||
|   store.init(); |   store.init(); | ||||||
|   // registerSW(); |   // registerSW(); | ||||||
| </script> | </script> | ||||||
| @@ -84,8 +86,13 @@ | |||||||
|         <Route path="/runners"> |         <Route path="/runners"> | ||||||
|           <Runners /> |           <Runners /> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/teams"> |         <Route path="/teams/*"> | ||||||
|           <Teams /> |           <Route path="/"> | ||||||
|  |             <Teams /> | ||||||
|  |           </Route> | ||||||
|  |           <Route path="/:teamid" let:params> | ||||||
|  |             <TeamDetail {params} /> | ||||||
|  |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/orgs/*"> |         <Route path="/orgs/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|   | |||||||
| @@ -163,7 +163,35 @@ | |||||||
|         </div> |         </div> | ||||||
|       {/await} |       {/await} | ||||||
|     </div> |     </div> | ||||||
|     <h2 class="text-4xl font-display font-semibold md:text-5xl">{$_('faq')}</h2> |     <div class="w-full leading-8 mt-8"> | ||||||
|  |       <p class="text-xl font-medium">{$_('icon-image-credits')}</p> | ||||||
|  |       <ul class="list-disc"> | ||||||
|  |         <li> | ||||||
|  |           <a | ||||||
|  |             class="underline" | ||||||
|  |             target="_blank" | ||||||
|  |             rel="noopener noreferrer" | ||||||
|  |             href="https://storyset.com">https://storyset.com</a> | ||||||
|  |         </li> | ||||||
|  |         <li> | ||||||
|  |           <a | ||||||
|  |             class="underline" | ||||||
|  |             target="_blank" | ||||||
|  |             rel="noopener noreferrer" | ||||||
|  |             href="https://undraw.co">https://undraw.co</a> | ||||||
|  |         </li> | ||||||
|  |         <li> | ||||||
|  |           <a | ||||||
|  |             class="underline" | ||||||
|  |             target="_blank" | ||||||
|  |             rel="noopener noreferrer" | ||||||
|  |             href="https://remixicon.com">https://remixicon.com</a> | ||||||
|  |         </li> | ||||||
|  |       </ul> | ||||||
|  |     </div> | ||||||
|  |     <h2 class="mt-4 text-4xl font-display font-semibold md:text-5xl"> | ||||||
|  |       {$_('faq')} | ||||||
|  |     </h2> | ||||||
|     <div class="mt-6 border-t-2 border-gray-100 pt-10"> |     <div class="mt-6 border-t-2 border-gray-100 pt-10"> | ||||||
|       <dl class="md:grid md:grid-cols-2 md:gap-8"> |       <dl class="md:grid md:grid-cols-2 md:gap-8"> | ||||||
|         <div> |         <div> | ||||||
|   | |||||||
							
								
								
									
										162
									
								
								src/components/AddOrgModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/components/AddOrgModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "./outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   export let modal_open; | ||||||
|  |   export let current_organizations; | ||||||
|  |   let name_input_dom; | ||||||
|  |   function focus(el) { | ||||||
|  |     el.focus(); | ||||||
|  |   } | ||||||
|  |   $: name = ""; | ||||||
|  |   $: processed_last_submit = true; | ||||||
|  |   $: isOrgnameValid = name.trim().length !== 0; | ||||||
|  |   $: createbtnenabled = isOrgnameValid; | ||||||
|  |   (() => { | ||||||
|  |     document.onkeydown = (e) => { | ||||||
|  |       e = e || window.event; | ||||||
|  |       if (e.key === "Escape") { | ||||||
|  |         modal_open = false; | ||||||
|  |       } | ||||||
|  |       if (e.keyCode === 13) { | ||||||
|  |         if (createbtnenabled === true) { | ||||||
|  |           createbtnenabled = false; | ||||||
|  |           submit(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |   })(); | ||||||
|  |   function submit() { | ||||||
|  |     if (processed_last_submit === true) { | ||||||
|  |       processed_last_submit = false; | ||||||
|  |       const toast = Toastify({ | ||||||
|  |         text: "Organization is being added...", | ||||||
|  |         duration: -1, | ||||||
|  |       }).showToast(); | ||||||
|  |       RunnerOrganisationService.runnerOrganisationControllerPost({ | ||||||
|  |         name, | ||||||
|  |         address: undefined, | ||||||
|  |         contact: undefined, | ||||||
|  |       }) | ||||||
|  |         .then((result) => { | ||||||
|  |           console.log(result); | ||||||
|  |           name = ""; | ||||||
|  |           modal_open = false; | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: "Organization added", | ||||||
|  |             duration: 500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |           current_organizations = current_organizations.concat([result]); | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |           // | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           processed_last_submit = true; | ||||||
|  |           // | ||||||
|  |           toast.hideToast(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={() => { | ||||||
|  |       modal_open = false; | ||||||
|  |     }}> | ||||||
|  |     <div | ||||||
|  |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  |         <div | ||||||
|  |           class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  |           data-id="modal_backdrop" /> | ||||||
|  |       </div> | ||||||
|  |       <span | ||||||
|  |         class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  |         aria-hidden="true">​</span> | ||||||
|  |       <div | ||||||
|  |         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | ||||||
|  |         role="dialog" | ||||||
|  |         aria-modal="true" | ||||||
|  |         aria-labelledby="modal-headline"> | ||||||
|  |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | ||||||
|  |           <div class="sm:flex sm:items-start"> | ||||||
|  |             <div | ||||||
|  |               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> | ||||||
|  |               <svg | ||||||
|  |                 class="h-6 w-6 text-blue-600" | ||||||
|  |                 fill="currentColor" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24"><path | ||||||
|  |                   d="M17 19h2v-8h-6v8h2v-6h2v6zM3 19V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v5h2v10h1v2H2v-2h1zm4-8v2h2v-2H7zm0 4v2h2v-2H7zm0-8v2h2V7H7z" /></svg> | ||||||
|  |             </div> | ||||||
|  |             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | ||||||
|  |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  |                 Create a new Organization | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   Please provide the required information to add a new | ||||||
|  |                   organization. | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |               <div class="grid grid-cols-6 gap-6"> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="firstname" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">Name</label> | ||||||
|  |                   <input | ||||||
|  |                     use:focus | ||||||
|  |                     autocomplete="off" | ||||||
|  |                     placeholder="Name" | ||||||
|  |                     class:border-red-500={!isOrgnameValid} | ||||||
|  |                     class:focus:border-red-500={!isOrgnameValid} | ||||||
|  |                     class:focus:ring-red-500={!isOrgnameValid} | ||||||
|  |                     bind:value={name} | ||||||
|  |                     bind:this={name_input_dom} | ||||||
|  |                     type="text" | ||||||
|  |                     name="firstname" | ||||||
|  |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|  |                   {#if !isOrgnameValid} | ||||||
|  |                     <span | ||||||
|  |                       class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|  |                       Organization name is required | ||||||
|  |                     </span> | ||||||
|  |                   {/if} | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | ||||||
|  |           <button | ||||||
|  |             disabled={!createbtnenabled} | ||||||
|  |             class:opacity-50={!createbtnenabled} | ||||||
|  |             on:click={submit} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('create')} | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             on:click={() => { | ||||||
|  |               modal_open = false; | ||||||
|  |             }} | ||||||
|  |             type="button" | ||||||
|  |             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('cancel')} | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
							
								
								
									
										181
									
								
								src/components/AddTeamModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/components/AddTeamModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "./outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { | ||||||
|  |     RunnerOrganisationService, | ||||||
|  |     RunnerTeamService, | ||||||
|  |   } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   export let modal_open; | ||||||
|  |   export let current_teams; | ||||||
|  |   let teamname_input_dom; | ||||||
|  |   function focus(el) { | ||||||
|  |     el.focus(); | ||||||
|  |   } | ||||||
|  |   $: teamname = ""; | ||||||
|  |   $: processed_last_submit = true; | ||||||
|  |   $: isTeamNameValid = teamname.trim().length !== 0; | ||||||
|  |   $: createbtnenabled = isTeamNameValid; | ||||||
|  |   (function () { | ||||||
|  |     document.onkeydown = function (e) { | ||||||
|  |       e = e || window.event; | ||||||
|  |       if (e.key === "Escape") { | ||||||
|  |         modal_open = false; | ||||||
|  |       } | ||||||
|  |       if (e.keyCode === 13) { | ||||||
|  |         if (createbtnenabled === true) { | ||||||
|  |           createbtnenabled = false; | ||||||
|  |           submit(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |   })(); | ||||||
|  |   $: parentGroup = undefined; | ||||||
|  |   $: orgs = []; | ||||||
|  |   RunnerOrganisationService.runnerOrganisationControllerGetAll().then((val) => { | ||||||
|  |     orgs = val; | ||||||
|  |   }); | ||||||
|  |   function submit() { | ||||||
|  |     if (processed_last_submit === true) { | ||||||
|  |       processed_last_submit = false; | ||||||
|  |       const toast = Toastify({ | ||||||
|  |         text: "Team is being added...", | ||||||
|  |         duration: -1, | ||||||
|  |       }).showToast(); | ||||||
|  |       RunnerTeamService.runnerTeamControllerPost({ | ||||||
|  |         parentGroup, | ||||||
|  |         name: teamname, | ||||||
|  |       }) | ||||||
|  |         .then((result) => { | ||||||
|  |           teamname = ""; | ||||||
|  |           modal_open = false; | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: "Team added", | ||||||
|  |             duration: 500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |           current_teams.push(result); | ||||||
|  |           current_teams = current_teams; | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |           // | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           processed_last_submit = true; | ||||||
|  |           // | ||||||
|  |           toast.hideToast(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={() => { | ||||||
|  |       modal_open = false; | ||||||
|  |     }}> | ||||||
|  |     <div | ||||||
|  |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  |         <div | ||||||
|  |           class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  |           data-id="modal_backdrop" /> | ||||||
|  |       </div> | ||||||
|  |       <span | ||||||
|  |         class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  |         aria-hidden="true">​</span> | ||||||
|  |       <div | ||||||
|  |         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | ||||||
|  |         role="dialog" | ||||||
|  |         aria-modal="true" | ||||||
|  |         aria-labelledby="modal-headline"> | ||||||
|  |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | ||||||
|  |           <div class="sm:flex sm:items-start"> | ||||||
|  |             <div | ||||||
|  |               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> | ||||||
|  |               <svg | ||||||
|  |                 class="h-6 w-6 text-blue-600" | ||||||
|  |                 fill="currentColor" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 640 512"><path | ||||||
|  |                   fill="currentColor" | ||||||
|  |                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|  |             </div> | ||||||
|  |             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | ||||||
|  |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  |                 Create a new team | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   Please provide the required information to add a new team. | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |               <div class="grid grid-cols-6 gap-6"> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="firstname" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('team-name')}</label> | ||||||
|  |                   <input | ||||||
|  |                     use:focus | ||||||
|  |                     autocomplete="off" | ||||||
|  |                     placeholder={$_('team-name')} | ||||||
|  |                     class:border-red-500={!isTeamNameValid} | ||||||
|  |                     class:focus:border-red-500={!isTeamNameValid} | ||||||
|  |                     class:focus:ring-red-500={!isTeamNameValid} | ||||||
|  |                     bind:value={teamname} | ||||||
|  |                     bind:this={teamname_input_dom} | ||||||
|  |                     type="text" | ||||||
|  |                     name="firstname" | ||||||
|  |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|  |                   {#if !isTeamNameValid} | ||||||
|  |                     <span | ||||||
|  |                       class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|  |                       team name is required | ||||||
|  |                     </span> | ||||||
|  |                   {/if} | ||||||
|  |                 </div> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="firstname" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('organization')}</label> | ||||||
|  |                   <select | ||||||
|  |                     bind:value={parentGroup} | ||||||
|  |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"> | ||||||
|  |                     {#each orgs as t} | ||||||
|  |                       <option value={t.id}>{t.name}</option> | ||||||
|  |                     {/each} | ||||||
|  |                   </select> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | ||||||
|  |           <button | ||||||
|  |             disabled={!createbtnenabled} | ||||||
|  |             class:opacity-50={!createbtnenabled} | ||||||
|  |             on:click={submit} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('create')} | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             on:click={() => { | ||||||
|  |               modal_open = false; | ||||||
|  |             }} | ||||||
|  |             type="button" | ||||||
|  |             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('cancel')} | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
| @@ -2,20 +2,21 @@ | |||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import { clickOutside } from "./outsideclick"; |   import { clickOutside } from "./outsideclick"; | ||||||
|   import { focusTrap } from "svelte-focus-trap"; |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|   import { tracks as tracksstore } from "../store.js"; |  | ||||||
|   import { UserService } from "@odit/lfk-client-js"; |   import { UserService } from "@odit/lfk-client-js"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; |   import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import Toastify from "toastify-js"; |   import Toastify from "toastify-js"; | ||||||
|   import "toastify-js/src/toastify.css"; |  | ||||||
|   export let modal_open; |   export let modal_open; | ||||||
|  |   export let current_users; | ||||||
|   let firstname_input; |   let firstname_input; | ||||||
|   let lastname_input; |   let lastname_input; | ||||||
|   let middlename_input; |   let middlename_input; | ||||||
|  |   let username_input; | ||||||
|   let password_input; |   let password_input; | ||||||
|   let email_input; |   let email_input; | ||||||
|   function focus(el) { |   function focus(el) { | ||||||
|     el.focus(); |     el.focus(); | ||||||
|   } |   } | ||||||
|  |   $: username_input_value = ""; | ||||||
|   $: middlename_input_value = ""; |   $: middlename_input_value = ""; | ||||||
|   $: password_input_value = ""; |   $: password_input_value = ""; | ||||||
|   $: email_input_value = ""; |   $: email_input_value = ""; | ||||||
| @@ -49,17 +50,25 @@ | |||||||
|         text: "User is being added...", |         text: "User is being added...", | ||||||
|         duration: -1, |         duration: -1, | ||||||
|       }).showToast(); |       }).showToast(); | ||||||
|       UserService.userControllerPost({ |       let postdata={ | ||||||
|         firstname: firstname_input_value, |         firstname: firstname_input_value, | ||||||
|         lastname: lastname_input_value, |         lastname: lastname_input_value, | ||||||
|         middlename: middlename_input_value, |         middlename: middlename_input_value, | ||||||
|         email: email_input_value, |         password: password_input_value | ||||||
|         password: password_input_value, |       }; | ||||||
|       }) |       if(email_input_value!==""){ | ||||||
|  |         postdata.email=email_input_value; | ||||||
|  |       } | ||||||
|  |       if(username_input_value!==""){ | ||||||
|  |         postdata.username=username_input_value; | ||||||
|  |       } | ||||||
|  |       UserService.userControllerPost(postdata) | ||||||
|         .then((result) => { |         .then((result) => { | ||||||
|           firstname_input_value = ""; |           firstname_input_value = ""; | ||||||
|           lastname_input_value = ""; |           lastname_input_value = ""; | ||||||
|           middlename_input_value = ""; |           middlename_input_value = ""; | ||||||
|  |           email_input_value = ""; | ||||||
|  |           username_input_value = ""; | ||||||
|           modal_open = false; |           modal_open = false; | ||||||
|           // |           // | ||||||
|           Toastify({ |           Toastify({ | ||||||
| @@ -67,12 +76,8 @@ | |||||||
|             duration: 500, |             duration: 500, | ||||||
|             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|           }).showToast(); |           }).showToast(); | ||||||
|           let storeval = []; |           current_users.push(result); | ||||||
|           tracksstore.subscribe((val) => { |           current_users=current_users; | ||||||
|             storeval = val; |  | ||||||
|           }); |  | ||||||
|           storeval.push(result); |  | ||||||
|           tracksstore.set(storeval); |  | ||||||
|         }) |         }) | ||||||
|         .catch((err) => { |         .catch((err) => { | ||||||
|           // |           // | ||||||
| @@ -213,6 +218,19 @@ | |||||||
|                     </span> |                     </span> | ||||||
|                   {/if} |                   {/if} | ||||||
|                 </div> |                 </div> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="trackname" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('username')}</label> | ||||||
|  |                   <input | ||||||
|  |                     autocomplete="off" | ||||||
|  |                     placeholder={$_('username')} | ||||||
|  |                     bind:value={username_input_value} | ||||||
|  |                     bind:this={username_input} | ||||||
|  |                     type="text" | ||||||
|  |                     name="trackname" | ||||||
|  |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|  |                 </div> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="email" |                     for="email" | ||||||
|   | |||||||
							
								
								
									
										100
									
								
								src/components/ConfirmOrgDeletion.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/components/ConfirmOrgDeletion.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "./outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import { createEventDispatcher } from "svelte"; | ||||||
|  |   export let modal_open; | ||||||
|  |   export let delete_org; | ||||||
|  |   const dispatch = createEventDispatcher(); | ||||||
|  |   function cancelDelete() { | ||||||
|  |     modal_open = false; | ||||||
|  |     dispatch("cancelDelete", { id: delete_org.id }); | ||||||
|  |   } | ||||||
|  |   function deleteOrg() { | ||||||
|  |     RunnerOrganisationService.runnerOrganisationControllerRemove( | ||||||
|  |       delete_org.id, | ||||||
|  |       true | ||||||
|  |     ) | ||||||
|  |       .then((resp) => { | ||||||
|  |         Toastify({ | ||||||
|  |           text: "Organization deleted", | ||||||
|  |           duration: 500, | ||||||
|  |           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |         }).showToast(); | ||||||
|  |         location.replace("./"); | ||||||
|  |       }) | ||||||
|  |       .catch((err) => { | ||||||
|  |         // | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={cancelDelete}> | ||||||
|  |     <div | ||||||
|  |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  |         <div | ||||||
|  |           class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  |           data-id="modal_backdrop" /> | ||||||
|  |       </div> | ||||||
|  |       <span | ||||||
|  |         class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  |         aria-hidden="true">​</span> | ||||||
|  |       <div | ||||||
|  |         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | ||||||
|  |         role="dialog" | ||||||
|  |         aria-modal="true" | ||||||
|  |         aria-labelledby="modal-headline"> | ||||||
|  |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | ||||||
|  |           <div class="sm:flex sm:items-start"> | ||||||
|  |             <div | ||||||
|  |               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> | ||||||
|  |               <svg | ||||||
|  |                 class="h-6 w-6 text-blue-600" | ||||||
|  |                 fill="currentColor" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 640 512"><path | ||||||
|  |                   fill="currentColor" | ||||||
|  |                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|  |             </div> | ||||||
|  |             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | ||||||
|  |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  |                 Attention! | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   Do you want to delete the organization | ||||||
|  |                   {delete_org.name}?<br />All associated teams and runners will | ||||||
|  |                   be deleted too! | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | ||||||
|  |           <button | ||||||
|  |             on:click={deleteOrg} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             Confirm, delete organization and associated teams+runners. | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             on:click={cancelDelete} | ||||||
|  |             type="button" | ||||||
|  |             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             Cancel, keep organization | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
							
								
								
									
										97
									
								
								src/components/ConfirmTeamDeletion.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/components/ConfirmTeamDeletion.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "./outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { RunnerTeamService } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import { createEventDispatcher } from "svelte"; | ||||||
|  |   export let modal_open; | ||||||
|  |   export let delete_team; | ||||||
|  |   const dispatch = createEventDispatcher(); | ||||||
|  |   function cancelDelete() { | ||||||
|  |     modal_open = false; | ||||||
|  |     dispatch("cancelDelete", { id: delete_team.id }); | ||||||
|  |   } | ||||||
|  |   function deleteTeam() { | ||||||
|  |     RunnerTeamService.runnerTeamControllerRemove(delete_team.id, true) | ||||||
|  |       .then((resp) => { | ||||||
|  |         Toastify({ | ||||||
|  |           text: "Team deleted", | ||||||
|  |           duration: 500, | ||||||
|  |           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |         }).showToast(); | ||||||
|  |         location.replace("./"); | ||||||
|  |       }) | ||||||
|  |       .catch((err) => { | ||||||
|  |         // | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={cancelDelete}> | ||||||
|  |     <div | ||||||
|  |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  |         <div | ||||||
|  |           class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  |           data-id="modal_backdrop" /> | ||||||
|  |       </div> | ||||||
|  |       <span | ||||||
|  |         class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  |         aria-hidden="true">​</span> | ||||||
|  |       <div | ||||||
|  |         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | ||||||
|  |         role="dialog" | ||||||
|  |         aria-modal="true" | ||||||
|  |         aria-labelledby="modal-headline"> | ||||||
|  |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | ||||||
|  |           <div class="sm:flex sm:items-start"> | ||||||
|  |             <div | ||||||
|  |               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> | ||||||
|  |               <svg | ||||||
|  |                 class="h-6 w-6 text-blue-600" | ||||||
|  |                 fill="currentColor" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 640 512"><path | ||||||
|  |                   fill="currentColor" | ||||||
|  |                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|  |             </div> | ||||||
|  |             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | ||||||
|  |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  |                 Attention! | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   Do you want to delete the team | ||||||
|  |                   {delete_team.name}?<br />All associated runners will be | ||||||
|  |                   deleted too! | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | ||||||
|  |           <button | ||||||
|  |             on:click={deleteTeam} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             Confirm, delete team and associated runners. | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             on:click={cancelDelete} | ||||||
|  |             type="button" | ||||||
|  |             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             Cancel, keep team | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
| @@ -1,52 +1,28 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import { active } from "tinro"; |  | ||||||
|   import localForage from "localforage"; |   import localForage from "localforage"; | ||||||
|   import { router } from "tinro"; |   import { router } from "tinro"; | ||||||
|  |  | ||||||
|   import store from "../store"; |  | ||||||
|   import NoComponentLoaded from "./NoComponentLoaded.svelte"; |   import NoComponentLoaded from "./NoComponentLoaded.svelte"; | ||||||
|   import { AuthService, OpenAPI } from "@odit/lfk-client-js"; |   import { AuthService } from "@odit/lfk-client-js"; | ||||||
|  |  | ||||||
|   let activePage = "dashboard"; |  | ||||||
|   let dropdown1 = false; |   let dropdown1 = false; | ||||||
|   let navOpen = false; |   $: navOpen = false; | ||||||
|   function ismobile() { |  | ||||||
|     let check = false; |  | ||||||
|     (function (a) { |  | ||||||
|       if ( |  | ||||||
|         /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( |  | ||||||
|           a |  | ||||||
|         ) || |  | ||||||
|         /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( |  | ||||||
|           a.substr(0, 4) |  | ||||||
|         ) |  | ||||||
|       ) |  | ||||||
|         check = true; |  | ||||||
|     })(navigator.userAgent || navigator.vendor || window.opera); |  | ||||||
|     return check; |  | ||||||
|   } |  | ||||||
|   $: mobile = ismobile(); |  | ||||||
|   function logout() { |   function logout() { | ||||||
|     localForage.clear(); |     localForage.clear(); | ||||||
|     location.replace("/"); |     location.replace("/"); | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="min-h-screen bg-gray-50 dark:bg-black dark:text-gray-100"> | <section class="min-h-screen bg-gray-50"> | ||||||
|   <nav |   <nav | ||||||
|     class:hidden={!navOpen && mobile} |     class:-translate-x-full={!navOpen} | ||||||
|     class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 md:translate-x-0"> |     class:translate-x-0={navOpen} | ||||||
|  |     class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 md:translate-x-0 bg-gray-50"> | ||||||
|     <a href="/" class="flex items-center px-4 py-5"> |     <a href="/" class="flex items-center px-4 py-5"> | ||||||
|       <img |       <img src="/lfk-logo.png" alt="Logo" class="h-10" /> | ||||||
|         src="/lfk-logo.png" |  | ||||||
|         alt="Logo" |  | ||||||
|         class="h-10" /> |  | ||||||
|       <h3 class="text-lg">Lauf für Kaya! Admin</h3> |       <h3 class="text-lg">Lauf für Kaya! Admin</h3> | ||||||
|     </a> |     </a> | ||||||
|     <nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> |     <nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/'} |         class:bg-gray-100={$router.path === '/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/"> |         href="/"> | ||||||
| @@ -61,7 +37,6 @@ | |||||||
|         <span>{$_('dashboard-title')}</span> |         <span>{$_('dashboard-title')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path.includes('/orgs/')} |  | ||||||
|         class:bg-gray-100={$router.path.includes('/orgs/')} |         class:bg-gray-100={$router.path.includes('/orgs/')} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/orgs/"> |         href="/orgs/"> | ||||||
| @@ -77,7 +52,6 @@ | |||||||
|         <span>{$_('orgs')}</span> |         <span>{$_('orgs')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/users/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/users/'} |         class:bg-gray-100={$router.path === '/users/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/users/"> |         href="/users/"> | ||||||
| @@ -93,7 +67,6 @@ | |||||||
|         <span>{$_('users')}</span> |         <span>{$_('users')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/runners/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/runners/'} |         class:bg-gray-100={$router.path === '/runners/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/runners/"> |         href="/runners/"> | ||||||
| @@ -109,7 +82,6 @@ | |||||||
|         <span>{$_('runners')}</span> |         <span>{$_('runners')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/teams/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/teams/'} |         class:bg-gray-100={$router.path === '/teams/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/teams/"> |         href="/teams/"> | ||||||
| @@ -125,7 +97,6 @@ | |||||||
|         <span>{$_('teams')}</span> |         <span>{$_('teams')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/tracks/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/tracks/'} |         class:bg-gray-100={$router.path === '/tracks/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/tracks/"> |         href="/tracks/"> | ||||||
| @@ -141,8 +112,7 @@ | |||||||
|         <span>{$_('tracks')}</span> |         <span>{$_('tracks')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={activePage === 'blub'} |         class:bg-gray-100={false} | ||||||
|         class:bg-gray-100={activePage === 'blub'} |  | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="#"> |         href="#"> | ||||||
|         <svg |         <svg | ||||||
| @@ -161,8 +131,7 @@ | |||||||
|       <div> |       <div> | ||||||
|         <div |         <div | ||||||
|           tabindex="0" |           tabindex="0" | ||||||
|           class:dark:bg-gray-900={activePage === 'blub'} |           class:bg-gray-100={false} | ||||||
|           class:bg-gray-100={activePage === 'blub'} |  | ||||||
|           class="flex items-center justify-between px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center justify-between px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           role="button" |           role="button" | ||||||
|           on:click={() => { |           on:click={() => { | ||||||
| @@ -237,7 +206,6 @@ | |||||||
|         <span>{$_('changelog')}</span> |         <span>{$_('changelog')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/settings/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/settings/'} |         class:bg-gray-100={$router.path === '/settings/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/settings/"> |         href="/settings/"> | ||||||
| @@ -254,7 +222,6 @@ | |||||||
|         <span>{$_('settings')}</span> |         <span>{$_('settings')}</span> | ||||||
|       </a> |       </a> | ||||||
|       <a |       <a | ||||||
|         class:dark:bg-gray-900={$router.path === '/about/'} |  | ||||||
|         class:bg-gray-100={$router.path === '/about/'} |         class:bg-gray-100={$router.path === '/about/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/about/"> |         href="/about/"> | ||||||
| @@ -291,65 +258,10 @@ | |||||||
|     </nav> |     </nav> | ||||||
|   </nav> |   </nav> | ||||||
|   <div class="ml-0 transition md:ml-60"> |   <div class="ml-0 transition md:ml-60"> | ||||||
|     <header |  | ||||||
|       class="flex items-center justify-between w-full px-4 border-b h-14"> |  | ||||||
|       <button |  | ||||||
|         on:click={() => { |  | ||||||
|           navOpen = !navOpen; |  | ||||||
|         }} |  | ||||||
|         class="block btn btn-light md:hidden"> |  | ||||||
|         <span class="sr-only">Menu</span> |  | ||||||
|         <svg |  | ||||||
|           class="w-4 h-4" |  | ||||||
|           xmlns="http://www.w3.org/2000/svg" |  | ||||||
|           viewBox="0 0 20 20" |  | ||||||
|           fill="currentColor"> |  | ||||||
|           <path |  | ||||||
|             fill-rule="evenodd" |  | ||||||
|             d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" |  | ||||||
|             clip-rule="evenodd" /> |  | ||||||
|         </svg> |  | ||||||
|       </button> |  | ||||||
|       <!-- <div class="hidden -ml-3 form-icon md:block w-96"> |  | ||||||
|         <svg |  | ||||||
|           xmlns="http://www.w3.org/2000/svg" |  | ||||||
|           fill="none" |  | ||||||
|           viewBox="0 0 24 24" |  | ||||||
|           stroke="currentColor"> |  | ||||||
|           <path |  | ||||||
|             stroke-linecap="round" |  | ||||||
|             stroke-linejoin="round" |  | ||||||
|             stroke-width="2" |  | ||||||
|             d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> |  | ||||||
|         </svg> |  | ||||||
|         <input |  | ||||||
|           class="border-0 form-input" |  | ||||||
|           placeholder="Search for articles..." /> |  | ||||||
|       </div> --> |  | ||||||
|       <div class="flex items-end"> |  | ||||||
|         <a href="#" class="flex text-gray-500"> |  | ||||||
|           <svg |  | ||||||
|             class="flex-shrink-0 w-5 h-5" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             viewBox="0 0 20 20" |  | ||||||
|             fill="currentColor"> |  | ||||||
|             <path |  | ||||||
|               d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z" /> |  | ||||||
|           </svg> |  | ||||||
|         </a> |  | ||||||
|         <a href="/profile/" class="ml-4"> |  | ||||||
|           <img |  | ||||||
|             class="h-8 w-8 rounded-full" |  | ||||||
|             src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" |  | ||||||
|             alt="Profile Picture" /> |  | ||||||
|         </a> |  | ||||||
|       </div> |  | ||||||
|     </header> |  | ||||||
|     <slot> |     <slot> | ||||||
|       <NoComponentLoaded /> |       <NoComponentLoaded /> | ||||||
|     </slot> |     </slot> | ||||||
|   </div> |   </div> | ||||||
|   <!-- Sidebar Backdrop --> |  | ||||||
|   <div |   <div | ||||||
|     on:click={() => { |     on:click={() => { | ||||||
|       navOpen = false; |       navOpen = false; | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
|   import { _, json } from "svelte-i18n"; |   import { _, json } from "svelte-i18n"; | ||||||
|   import { getlang } from "./datatable_i18n"; |   import { getlang } from "./datatable_i18n"; | ||||||
|   import { Grid } from "gridjs"; |   import { Grid } from "gridjs"; | ||||||
|   import "gridjs/dist/theme/mermaid.css"; |  | ||||||
|   // |   // | ||||||
|   let table; |   let table; | ||||||
|   const datatable = new Grid({ |   const datatable = new Grid({ | ||||||
|   | |||||||
| @@ -1,9 +1,12 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   const releaseinfo = document |   $: releaseinfo = ""; | ||||||
|     .getElementById("buildinfo") |   setTimeout(() => { | ||||||
|     .textContent.replace("RELEASE_INFO-", "") |     releaseinfo = document | ||||||
|     .replace("-RELEASE_INFO", ""); |       .getElementById("buildinfo") | ||||||
|  |       .textContent.replace("RELEASE_INFO-", "") | ||||||
|  |       .replace("-RELEASE_INFO", ""); | ||||||
|  |   }, 1500); | ||||||
|   const year = new Date().getFullYear(); |   const year = new Date().getFullYear(); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,83 +1,217 @@ | |||||||
| <script> | <script> | ||||||
|  |   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; | ||||||
|  |   import PromiseError from "./PromiseError.svelte"; | ||||||
|  |   $: delete_triggered = false; | ||||||
|  |   $: save_enabled = !data_changed; | ||||||
|   export let params; |   export let params; | ||||||
|  |   let orgdata = {}; | ||||||
|  |   let original = {}; | ||||||
|  |   $: data_loaded = false; | ||||||
|  |   $: data_changed = JSON.stringify(orgdata) === JSON.stringify(original); | ||||||
|  |   const promise = RunnerOrganisationService.runnerOrganisationControllerGetOne( | ||||||
|  |     params.orgid | ||||||
|  |   ).then((value) => { | ||||||
|  |     data_loaded = true; | ||||||
|  |     orgdata = Object.assign(orgdata, value); | ||||||
|  |     original = Object.assign(original, value); | ||||||
|  |   }); | ||||||
|  |   let modal_open = false; | ||||||
|  |   let delete_org = {}; | ||||||
|  |   function deleteOrganisation() { | ||||||
|  |     // RunnerOrganisationService.runnerOrganisationControllerRemove( | ||||||
|  |     //   original.id, | ||||||
|  |     //   false | ||||||
|  |     // ) | ||||||
|  |     //   .then((resp) => { | ||||||
|  |     //     Toastify({ | ||||||
|  |     //       text: "Organization deleted", | ||||||
|  |     //       duration: 500, | ||||||
|  |     //       backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |     //     }).showToast(); | ||||||
|  |     //     location.replace("./"); | ||||||
|  |     //   }) | ||||||
|  |     //   .catch((err) => { | ||||||
|  |     modal_open = true; | ||||||
|  |     delete_org = original; | ||||||
|  |     // }); | ||||||
|  |   } | ||||||
|  |   function submit() { | ||||||
|  |     if (data_loaded === true && save_enabled) { | ||||||
|  |       Toastify({ | ||||||
|  |         text: "updating organization", | ||||||
|  |         duration: 2500, | ||||||
|  |       }).showToast(); | ||||||
|  |       RunnerOrganisationService.runnerOrganisationControllerPut( | ||||||
|  |         original.id, | ||||||
|  |         orgdata | ||||||
|  |       ) | ||||||
|  |         .then((resp) => { | ||||||
|  |           Object.assign(original, orgdata); | ||||||
|  |           original = orgdata; | ||||||
|  |           Object.assign(original, orgdata); | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: "updated organization", | ||||||
|  |             duration: 2500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |         }) | ||||||
|  |         .catch((err) => {}); | ||||||
|  |     } else { | ||||||
|  |     } | ||||||
|  |   } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <ConfirmOrgDeletion bind:modal_open bind:delete_org /> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | {#if data_loaded} | ||||||
|     Orgs |   <section class="container p-5"> | ||||||
|   </span> |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|   <p class="mb-8 text-lg text-gray-500"> |       {original.name} | ||||||
|     configure the tracks & minimum lap times |       <span data-id="org_actions_${orgdata.id}"> | ||||||
|   </p> |         {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||||
|   <div class="flex flex-row mb-4"> |           {#if delete_triggered} | ||||||
|     <div class="w-full"> |             <button | ||||||
|       <nav class="w-full flex"> |               on:click={deleteOrganisation} | ||||||
|         <ol class="list-none flex flex-row items-center justify-start"> |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button> | ||||||
|           <li class="mr-2 flex items-center"> |             <button | ||||||
|             <svg |               on:click={() => { | ||||||
|               stroke="currentColor" |                 delete_triggered = !delete_triggered; | ||||||
|               fill="none" |               }} | ||||||
|               stroke-width="2" |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> | ||||||
|               viewBox="0 0 24 24" |           {/if} | ||||||
|               stroke-linecap="round" |           {#if !delete_triggered} | ||||||
|               stroke-linejoin="round" |             <button | ||||||
|               class="h-3 w-3 stroke-current" |               on:click={() => { | ||||||
|               height="1em" |                 delete_triggered = true; | ||||||
|               width="1em" |               }} | ||||||
|               xmlns="http://www.w3.org/2000/svg"><path |               type="button" | ||||||
|                 d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-organization')}</button> | ||||||
|               <polyline points="9 22 9 12 15 12 15 22" /></svg> |           {/if} | ||||||
|           </li> |         {/if} | ||||||
|           <li class="flex items-center"> |         {#if !delete_triggered} | ||||||
|             <a class="mr-2" href="/">Home</a><svg |           <button | ||||||
|               stroke="currentColor" |             on:click={submit} | ||||||
|               fill="none" |             disabled={!save_enabled} | ||||||
|               stroke-width="2" |             class:opacity-50={!save_enabled} | ||||||
|               viewBox="0 0 24 24" |             type="button" | ||||||
|               stroke-linecap="round" |             class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('save-changes')}</button> | ||||||
|               stroke-linejoin="round" |         {/if} | ||||||
|               class="h-3 w-3 mr-2 stroke-current" |       </span> | ||||||
|               height="1em" |  | ||||||
|               width="1em" |  | ||||||
|               xmlns="http://www.w3.org/2000/svg"><line |  | ||||||
|                 x1="5" |  | ||||||
|                 y1="12" |  | ||||||
|                 x2="19" |  | ||||||
|                 y2="12" /> |  | ||||||
|               <polyline points="12 5 19 12 12 19" /></svg> |  | ||||||
|           </li> |  | ||||||
|           <li class="mr-2 flex items-center"> |  | ||||||
|             <svg |  | ||||||
|               xmlns="http://www.w3.org/2000/svg" |  | ||||||
|               viewBox="0 0 24 24" |  | ||||||
|               width="24" |  | ||||||
|               height="24"><path fill="none" d="M0 0h24v24H0z" /> |  | ||||||
|               <path |  | ||||||
|                 d="M21 20h2v2H1v-2h2V3a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v17zm-2 0V4H5v16h14zM8 11h3v2H8v-2zm0-4h3v2H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2zm0-4h3v2h-3v-2zm0-4h3v2h-3V7z" /></svg> |  | ||||||
|           </li> |  | ||||||
|           <li class="flex items-center"> |  | ||||||
|             <a class="mr-2" href="./">Orgs</a><svg |  | ||||||
|               stroke="currentColor" |  | ||||||
|               fill="none" |  | ||||||
|               stroke-width="2" |  | ||||||
|               viewBox="0 0 24 24" |  | ||||||
|               stroke-linecap="round" |  | ||||||
|               stroke-linejoin="round" |  | ||||||
|               class="h-3 w-3 mr-2 stroke-current" |  | ||||||
|               height="1em" |  | ||||||
|               width="1em" |  | ||||||
|               xmlns="http://www.w3.org/2000/svg"><line |  | ||||||
|                 x1="5" |  | ||||||
|                 y1="12" |  | ||||||
|                 x2="19" |  | ||||||
|                 y2="12" /> |  | ||||||
|               <polyline points="12 5 19 12 12 19" /></svg> |  | ||||||
|           </li> |  | ||||||
|           <li class="flex items-center"> |  | ||||||
|             <span class="mr-2">Org-Details #{params.orgid}</span> |  | ||||||
|           </li> |  | ||||||
|         </ol> |  | ||||||
|       </nav> |  | ||||||
|     </div> |     </div> | ||||||
|   </div> |     <div class="flex flex-row mb-4"> | ||||||
| </section> |       <div class="w-full"> | ||||||
|  |         <nav class="w-full flex"> | ||||||
|  |           <ol class="list-none flex flex-row items-center justify-start"> | ||||||
|  |             <li class="mr-2 flex items-center"> | ||||||
|  |               <svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><path | ||||||
|  |                   d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> | ||||||
|  |                 <polyline points="9 22 9 12 15 12 15 22" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <a class="mr-2" href="/">Home</a><svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|  |                   x1="5" | ||||||
|  |                   y1="12" | ||||||
|  |                   x2="19" | ||||||
|  |                   y2="12" /> | ||||||
|  |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="mr-2 flex items-center"> | ||||||
|  |               <svg | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|  |                 <path | ||||||
|  |                   d="M21 20h2v2H1v-2h2V3a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v17zm-2 0V4H5v16h14zM8 11h3v2H8v-2zm0-4h3v2H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2zm0-4h3v2h-3v-2zm0-4h3v2h-3V7z" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <a class="mr-2" href="./">Orgs</a><svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|  |                   x1="5" | ||||||
|  |                   y1="12" | ||||||
|  |                   x2="19" | ||||||
|  |                   y2="12" /> | ||||||
|  |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <span class="mr-2">Org-Details #{params.orgid}</span> | ||||||
|  |             </li> | ||||||
|  |           </ol> | ||||||
|  |         </nav> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label for="name" class="font-medium text-gray-700">Name</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder="Name" | ||||||
|  |         type="text" | ||||||
|  |         bind:value={orgdata.name} | ||||||
|  |         name="name" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label | ||||||
|  |         for="contact" | ||||||
|  |         class="font-medium text-gray-700">{$_('contact')}</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder={$_('contact')} | ||||||
|  |         type="text" | ||||||
|  |         bind:value={orgdata.contact} | ||||||
|  |         name="contact" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label | ||||||
|  |         for="address" | ||||||
|  |         class="font-medium text-gray-700">{$_('address')}</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder={$_('address')} | ||||||
|  |         type="text" | ||||||
|  |         bind:value={orgdata.address} | ||||||
|  |         name="address" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | {:else} | ||||||
|  |   {#await promise} | ||||||
|  |     organization detail is being loaded... | ||||||
|  |   {:catch error} | ||||||
|  |     <PromiseError /> | ||||||
|  |   {/await} | ||||||
|  | {/if} | ||||||
|   | |||||||
							
								
								
									
										175
									
								
								src/components/OrgOverview.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								src/components/OrgOverview.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   let modal_open = false; | ||||||
|  |   let delete_org = {}; | ||||||
|  |   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||||
|  |   import "gridjs/dist/theme/mermaid.css"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import OrgsEmptyState from "./OrgsEmptyState.svelte"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; | ||||||
|  |   $: searchvalue = ""; | ||||||
|  |   $: active_deletes = []; | ||||||
|  |   export let current_organizations = []; | ||||||
|  |  | ||||||
|  |   const promise = RunnerOrganisationService.runnerOrganisationControllerGetAll().then( | ||||||
|  |     (val) => { | ||||||
|  |       current_organizations = val; | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <ConfirmOrgDeletion | ||||||
|  |   on:cancelDelete={(event) => { | ||||||
|  |     modal_open = false; | ||||||
|  |     active_deletes[event.detail.id] = false; | ||||||
|  |   }} | ||||||
|  |   bind:modal_open | ||||||
|  |   bind:delete_org /> | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:GET')} | ||||||
|  |   {#await promise} | ||||||
|  |     <div | ||||||
|  |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|  |       role="alert"> | ||||||
|  |       <p class="font-bold">organizations are being loaded...</p> | ||||||
|  |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|  |     </div> | ||||||
|  |   {:then} | ||||||
|  |     {#if current_organizations.length === 0} | ||||||
|  |       <OrgsEmptyState /> | ||||||
|  |     {:else} | ||||||
|  |       <input | ||||||
|  |         type="search" | ||||||
|  |         bind:value={searchvalue} | ||||||
|  |         placeholder={$_('datatable.search')} | ||||||
|  |         aria-label={$_('datatable.search')} | ||||||
|  |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|  |       <div | ||||||
|  |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|  |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|  |           <thead class="bg-gray-50"> | ||||||
|  |             <tr> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 Name | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 Address | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 Contact | ||||||
|  |               </th> | ||||||
|  |               <th scope="col" class="relative px-6 py-3"> | ||||||
|  |                 <span class="sr-only">Action</span> | ||||||
|  |               </th> | ||||||
|  |             </tr> | ||||||
|  |           </thead> | ||||||
|  |           <tbody class="divide-y divide-gray-200"> | ||||||
|  |             {#each current_organizations as o} | ||||||
|  |               {#if Object.values(o) | ||||||
|  |                 .toString() | ||||||
|  |                 .toLowerCase() | ||||||
|  |                 .includes(searchvalue)} | ||||||
|  |                 <tr data-rowid="org_{o.id}"> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {o.name} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {#if o.address} | ||||||
|  |                             {JSON.stringify(o.address)} | ||||||
|  |                           {:else}no address specified{/if} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {#if o.contact} | ||||||
|  |                             {JSON.stringify(o.contact)} | ||||||
|  |                           {:else}no contact specified{/if} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   {#if active_deletes[o.id] === true} | ||||||
|  |                     <td | ||||||
|  |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           active_deletes[o.id] = false; | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel | ||||||
|  |                         Delete</button> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           RunnerOrganisationService.runnerOrganisationControllerRemove(o.id, false) | ||||||
|  |                             .then((resp) => { | ||||||
|  |                               current_organizations = current_organizations.filter((obj) => obj.id !== o.id); | ||||||
|  |                               Toastify({ | ||||||
|  |                                 text: 'Organization deleted', | ||||||
|  |                                 duration: 500, | ||||||
|  |                                 backgroundColor: | ||||||
|  |                                   'linear-gradient(to right, #00b09b, #96c93d)', | ||||||
|  |                               }).showToast(); | ||||||
|  |                             }) | ||||||
|  |                             .catch((err) => { | ||||||
|  |                               modal_open = true; | ||||||
|  |                               delete_org = o; | ||||||
|  |                             }); | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Confirm | ||||||
|  |                         Delete</button> | ||||||
|  |                     </td> | ||||||
|  |                   {:else} | ||||||
|  |                     <td | ||||||
|  |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <a | ||||||
|  |                         href="./{o.id}" | ||||||
|  |                         class="text-indigo-600 hover:text-indigo-900">Edit</a> | ||||||
|  |                       {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:DELETE')} | ||||||
|  |                         <button | ||||||
|  |                           on:click={() => { | ||||||
|  |                             active_deletes[o.id] = true; | ||||||
|  |                           }} | ||||||
|  |                           tabindex="0" | ||||||
|  |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button> | ||||||
|  |                       {/if} | ||||||
|  |                     </td> | ||||||
|  |                   {/if} | ||||||
|  |                 </tr> | ||||||
|  |               {/if} | ||||||
|  |             {/each} | ||||||
|  |           </tbody> | ||||||
|  |         </table> | ||||||
|  |       </div> | ||||||
|  |     {/if} | ||||||
|  |   {:catch error} | ||||||
|  |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|  |       <span class="inline-block align-middle mr-8"> | ||||||
|  |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|  |         {error} | ||||||
|  |       </span> | ||||||
|  |     </div> | ||||||
|  |   {/await} | ||||||
|  | {/if} | ||||||
| @@ -1,13 +1,31 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import AddOrgModal from "./AddOrgModal.svelte"; | ||||||
|  |   export let modal_open = false; | ||||||
|  |   import OrgOverview from "./OrgOverview.svelte"; | ||||||
|  |   console.log(store.state.jwtinfo.userdetails.permissions); | ||||||
|  |   let current_organizations = []; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     Orgs |     {$_('organizations')} | ||||||
|  |     {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:CREATE')} | ||||||
|  |       <button | ||||||
|  |         on:click={() => { | ||||||
|  |           modal_open = true; | ||||||
|  |         }} | ||||||
|  |         type="button" | ||||||
|  |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |         {$_('create-organization')} | ||||||
|  |       </button> | ||||||
|  |     {/if} | ||||||
|   </span> |   </span> | ||||||
|   <p class="mb-8 text-lg text-gray-500"> |   <p class="mb-8 text-lg text-gray-500">manage runner organizations</p> | ||||||
|     add, delete, edit organizations |   <OrgOverview bind:current_organizations /> | ||||||
|   </p> |  | ||||||
|   <nav><a class="underline" href="./1">Org 1</a></nav> |  | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:CREATE')} | ||||||
|  |   <AddOrgModal bind:current_organizations bind:modal_open /> | ||||||
|  | {/if} | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								src/components/OrgsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/components/OrgsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import AddOrgModal from "./AddOrgModal.svelte"; | ||||||
|  |   import org_empty from "./org_empty.svg"; | ||||||
|  |   let modal_open = false; | ||||||
|  |   let current_organizations = []; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="text-center items-center justify-center"> | ||||||
|  |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|  |     <img class="w-full h-44" src={org_empty} alt="" /> | ||||||
|  |     <span class="font-bold">There are no organizations added yet.</span><br /> | ||||||
|  |     <span>Add your first organization</span> | ||||||
|  |   </p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <AddOrgModal bind:modal_open bind:current_organizations /> | ||||||
| @@ -1,5 +1,6 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|  |   import RunnersEmptyState from "./RunnersEmptyState.svelte"; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
| @@ -8,3 +9,4 @@ | |||||||
|   </span> |   </span> | ||||||
|   <p class="mb-8 text-lg text-gray-500">läuft bei ihnen</p> |   <p class="mb-8 text-lg text-gray-500">läuft bei ihnen</p> | ||||||
| </section> | </section> | ||||||
|  | <RunnersEmptyState /> | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/components/RunnersEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/components/RunnersEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   // import AddUserModal from "./AddUserModal.svelte"; | ||||||
|  |   import runners_empty from "./runners_empty.svg"; | ||||||
|  |   // let modal_open = false; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="text-center items-center justify-center"> | ||||||
|  |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|  |     <img class="w-full h-44" src={runners_empty} alt="" /> | ||||||
|  |     <span class="font-bold">There are no runners added yet.</span><br /> | ||||||
|  |     <span>Add your first runner</span> | ||||||
|  |   </p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <!-- <AddUserModal bind:modal_open /> --> | ||||||
							
								
								
									
										223
									
								
								src/components/TeamDetail.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/components/TeamDetail.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | |||||||
|  | <script> | ||||||
|  |   import { | ||||||
|  |     RunnerOrganisationService, | ||||||
|  |     RunnerTeamService, | ||||||
|  |   } from "@odit/lfk-client-js"; | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import PromiseError from "./PromiseError.svelte"; | ||||||
|  |   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; | ||||||
|  |   export let params; | ||||||
|  |   let [teamdata, original, delete_team, orgs, modal_open] = [ | ||||||
|  |     {}, | ||||||
|  |     {}, | ||||||
|  |     {}, | ||||||
|  |     [], | ||||||
|  |     false, | ||||||
|  |   ]; | ||||||
|  |   $: delete_triggered = false; | ||||||
|  |   $: save_enabled = !data_changed; | ||||||
|  |   $: data_loaded = false; | ||||||
|  |   $: data_changed = JSON.stringify(teamdata) === JSON.stringify(original); | ||||||
|  |   // | ||||||
|  |   const promise = RunnerTeamService.runnerTeamControllerGetOne( | ||||||
|  |     params.teamid | ||||||
|  |   ).then((value) => { | ||||||
|  |     data_loaded = true; | ||||||
|  |     teamdata = Object.assign(teamdata, value); | ||||||
|  |     original = Object.assign(original, value); | ||||||
|  |   }); | ||||||
|  |   RunnerOrganisationService.runnerOrganisationControllerGetAll().then((val) => { | ||||||
|  |     orgs = val; | ||||||
|  |   }); | ||||||
|  |   function deleteTeam() { | ||||||
|  |     RunnerTeamService.runnerTeamControllerRemove(original.id, false) | ||||||
|  |       .then((resp) => { | ||||||
|  |         Toastify({ | ||||||
|  |           text: "Organization deleted", | ||||||
|  |           duration: 500, | ||||||
|  |           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |         }).showToast(); | ||||||
|  |         location.replace("./"); | ||||||
|  |       }) | ||||||
|  |       .catch((err) => { | ||||||
|  |         modal_open = true; | ||||||
|  |         delete_team = original; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  |   function submit() { | ||||||
|  |     if (data_loaded === true && save_enabled) { | ||||||
|  |       Toastify({ | ||||||
|  |         text: "updating team", | ||||||
|  |         duration: 2500, | ||||||
|  |       }).showToast(); | ||||||
|  |       teamdata.parentGroup = teamdata.parentGroup.id; | ||||||
|  |       RunnerTeamService.runnerTeamControllerPut(original.id, teamdata) | ||||||
|  |         .then((resp) => { | ||||||
|  |           Object.assign(original, teamdata); | ||||||
|  |           original = teamdata; | ||||||
|  |           Object.assign(original, teamdata); | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: "updated team", | ||||||
|  |             duration: 2500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |         }) | ||||||
|  |         .catch((err) => {}); | ||||||
|  |     } else { | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <ConfirmTeamDeletion bind:modal_open bind:delete_team /> | ||||||
|  | {#if data_loaded} | ||||||
|  |   <section class="container p-5"> | ||||||
|  |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|  |       {original.name} | ||||||
|  |       <span data-id="org_actions_${teamdata.id}"> | ||||||
|  |         {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} | ||||||
|  |           {#if delete_triggered} | ||||||
|  |             <button | ||||||
|  |               on:click={deleteTeam} | ||||||
|  |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button> | ||||||
|  |             <button | ||||||
|  |               on:click={() => { | ||||||
|  |                 delete_triggered = !delete_triggered; | ||||||
|  |               }} | ||||||
|  |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> | ||||||
|  |           {/if} | ||||||
|  |           {#if !delete_triggered} | ||||||
|  |             <button | ||||||
|  |               on:click={() => { | ||||||
|  |                 delete_triggered = true; | ||||||
|  |               }} | ||||||
|  |               type="button" | ||||||
|  |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-team')}</button> | ||||||
|  |           {/if} | ||||||
|  |         {/if} | ||||||
|  |         {#if !delete_triggered} | ||||||
|  |           <button | ||||||
|  |             on:click={submit} | ||||||
|  |             disabled={!save_enabled} | ||||||
|  |             class:opacity-50={!save_enabled} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('save-changes')}</button> | ||||||
|  |         {/if} | ||||||
|  |       </span> | ||||||
|  |     </div> | ||||||
|  |     <div class="flex flex-row mb-4"> | ||||||
|  |       <div class="w-full"> | ||||||
|  |         <nav class="w-full flex"> | ||||||
|  |           <ol class="list-none flex flex-row items-center justify-start"> | ||||||
|  |             <li class="mr-2 flex items-center"> | ||||||
|  |               <svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><path | ||||||
|  |                   d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> | ||||||
|  |                 <polyline points="9 22 9 12 15 12 15 22" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <a class="mr-2" href="/">Home</a><svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|  |                   x1="5" | ||||||
|  |                   y1="12" | ||||||
|  |                   x2="19" | ||||||
|  |                   y2="12" /> | ||||||
|  |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="mr-2 flex items-center"> | ||||||
|  |               <svg | ||||||
|  |                 class="flex-shrink-0 w-5 h-5 mr-2" | ||||||
|  |                 fill="currentColor" | ||||||
|  |                 width="24" | ||||||
|  |                 height="24" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                 viewBox="0 0 640 512"><path | ||||||
|  |                   fill="currentColor" | ||||||
|  |                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <a class="mr-2" href="./">Teams</a><svg | ||||||
|  |                 stroke="currentColor" | ||||||
|  |                 fill="none" | ||||||
|  |                 stroke-width="2" | ||||||
|  |                 viewBox="0 0 24 24" | ||||||
|  |                 stroke-linecap="round" | ||||||
|  |                 stroke-linejoin="round" | ||||||
|  |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|  |                 height="1em" | ||||||
|  |                 width="1em" | ||||||
|  |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|  |                   x1="5" | ||||||
|  |                   y1="12" | ||||||
|  |                   x2="19" | ||||||
|  |                   y2="12" /> | ||||||
|  |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|  |             </li> | ||||||
|  |             <li class="flex items-center"> | ||||||
|  |               <span class="mr-2">Team-Details #{params.teamid}</span> | ||||||
|  |             </li> | ||||||
|  |           </ol> | ||||||
|  |         </nav> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label for="name" class="font-medium text-gray-700">Name</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder="Name" | ||||||
|  |         type="text" | ||||||
|  |         bind:value={teamdata.name} | ||||||
|  |         name="name" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label | ||||||
|  |         for="contact" | ||||||
|  |         class="font-medium text-gray-700">{$_('contact')}</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder={$_('contact')} | ||||||
|  |         type="text" | ||||||
|  |         bind:value={teamdata.contact} | ||||||
|  |         name="contact" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label for="org" class="font-medium text-gray-700">Parent Organization</label> | ||||||
|  |       <select | ||||||
|  |         name="org" | ||||||
|  |         bind:value={teamdata.parentGroup} | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"> | ||||||
|  |         {#each orgs as o} | ||||||
|  |           <option value={o.id}>{o.name}</option> | ||||||
|  |         {/each} | ||||||
|  |       </select> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | {:else} | ||||||
|  |   {#await promise} | ||||||
|  |     team detail is being loaded... | ||||||
|  |   {:catch error} | ||||||
|  |     <PromiseError /> | ||||||
|  |   {/await} | ||||||
|  | {/if} | ||||||
| @@ -1,10 +1,31 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import AddTeamModal from "./AddTeamModal.svelte"; | ||||||
|  |   export let modal_open = false; | ||||||
|  |   import TeamsOverview from "./TeamsOverview.svelte"; | ||||||
|  |   console.log(store.state.jwtinfo.userdetails.permissions); | ||||||
|  |   let current_teams=[]; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_('teams')} |     {$_('teams')} | ||||||
|  |     {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||||
|  |       <button | ||||||
|  |         on:click={() => { | ||||||
|  |           modal_open = true; | ||||||
|  |         }} | ||||||
|  |         type="button" | ||||||
|  |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |         Create Team | ||||||
|  |       </button> | ||||||
|  |     {/if} | ||||||
|   </span> |   </span> | ||||||
|   <p class="mb-8 text-lg text-gray-500">everything is more fun together 🏃♂️🏃♀️🏃♂️</p> |   <p class="mb-8 text-lg text-gray-500">everything is more fun together 🏃♂️🏃♀️🏃♂️</p> | ||||||
|  |   <TeamsOverview bind:current_teams /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||||
|  |   <AddTeamModal bind:current_teams bind:modal_open /> | ||||||
|  | {/if} | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								src/components/TeamsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/components/TeamsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import AddTeamModal from "./AddTeamModal.svelte"; | ||||||
|  |   import team_empty from "./team_empty.svg"; | ||||||
|  |   let modal_open = false; | ||||||
|  |   let current_teams = []; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="text-center items-center justify-center"> | ||||||
|  |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|  |     <img class="w-full h-44" src={team_empty} alt="" /> | ||||||
|  |     <span class="font-bold">There are no teams added yet.</span><br /> | ||||||
|  |     <span>Add your first team</span> | ||||||
|  |   </p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <AddTeamModal bind:modal_open bind:current_teams /> | ||||||
							
								
								
									
										177
									
								
								src/components/TeamsOverview.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								src/components/TeamsOverview.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | <script> | ||||||
|  |   import { t, _ } from "svelte-i18n"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import { RunnerTeamService } from "@odit/lfk-client-js"; | ||||||
|  |   const teams_promise = RunnerTeamService.runnerTeamControllerGetAll(); | ||||||
|  |   import "gridjs/dist/theme/mermaid.css"; | ||||||
|  |   import { users as usersstore } from "../store.js"; | ||||||
|  |   import store from "../store"; | ||||||
|  |   import TeamsEmptyState from "./TeamsEmptyState.svelte"; | ||||||
|  |   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; | ||||||
|  |   $: searchvalue = ""; | ||||||
|  |   $: active_deletes = []; | ||||||
|  |   export let current_teams = []; | ||||||
|  |   let modal_open = false; | ||||||
|  |   let delete_team = {}; | ||||||
|  |   usersstore.subscribe((val) => { | ||||||
|  |     current_teams = val; | ||||||
|  |   }); | ||||||
|  |   teams_promise.then((data) => { | ||||||
|  |     usersstore.set(data); | ||||||
|  |   }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <ConfirmTeamDeletion | ||||||
|  |   on:cancelDelete={(event) => { | ||||||
|  |     modal_open = false; | ||||||
|  |     active_deletes[event.detail.id] = false; | ||||||
|  |   }} | ||||||
|  |   bind:modal_open | ||||||
|  |   bind:delete_team /> | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:GET')} | ||||||
|  |   {#await teams_promise} | ||||||
|  |     <div | ||||||
|  |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|  |       role="alert"> | ||||||
|  |       <p class="font-bold">teams are being loaded...</p> | ||||||
|  |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|  |     </div> | ||||||
|  |   {:then} | ||||||
|  |     {#if current_teams.length === 0} | ||||||
|  |       <TeamsEmptyState /> | ||||||
|  |     {:else} | ||||||
|  |       <input | ||||||
|  |         type="search" | ||||||
|  |         bind:value={searchvalue} | ||||||
|  |         placeholder={$_('datatable.search')} | ||||||
|  |         aria-label={$_('datatable.search')} | ||||||
|  |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|  |       <div | ||||||
|  |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|  |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|  |           <thead class="bg-gray-50"> | ||||||
|  |             <tr> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 Name | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 {$_('organization')} | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 Contact | ||||||
|  |               </th> | ||||||
|  |               <th scope="col" class="relative px-6 py-3"> | ||||||
|  |                 <span class="sr-only">Action</span> | ||||||
|  |               </th> | ||||||
|  |             </tr> | ||||||
|  |           </thead> | ||||||
|  |           <tbody class="divide-y divide-gray-200"> | ||||||
|  |             {#each current_teams as t} | ||||||
|  |               {#if Object.values(t) | ||||||
|  |                 .toString() | ||||||
|  |                 .toLowerCase() | ||||||
|  |                 .includes(searchvalue)} | ||||||
|  |                 <tr data-rowid="team_{t.id}"> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {t.name} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {#if t.parentGroup} | ||||||
|  |                             {t.parentGroup.name} | ||||||
|  |                           {:else}no organization specified{/if} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {#if t.contact} | ||||||
|  |                             {JSON.stringify(t.contact)} | ||||||
|  |                           {:else}no contact specified{/if} | ||||||
|  |                         </div> | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                   </td> | ||||||
|  |                   {#if active_deletes[t.id] === true} | ||||||
|  |                     <td | ||||||
|  |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           active_deletes[t.id] = false; | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel | ||||||
|  |                         Delete</button> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           RunnerTeamService.runnerTeamControllerRemove(t.id, false) | ||||||
|  |                             .then((resp) => { | ||||||
|  |                               current_teams = current_teams.filter((obj) => obj.id !== t.id); | ||||||
|  |                               Toastify({ | ||||||
|  |                                 text: 'Organization deleted', | ||||||
|  |                                 duration: 500, | ||||||
|  |                                 backgroundColor: | ||||||
|  |                                   'linear-gradient(to right, #00b09b, #96c93d)', | ||||||
|  |                               }).showToast(); | ||||||
|  |                             }) | ||||||
|  |                             .catch((err) => { | ||||||
|  |                               modal_open = true; | ||||||
|  |                               delete_team = t; | ||||||
|  |                             }); | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Confirm | ||||||
|  |                         Delete</button> | ||||||
|  |                     </td> | ||||||
|  |                   {:else} | ||||||
|  |                     <td | ||||||
|  |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <a | ||||||
|  |                         href="./{t.id}" | ||||||
|  |                         class="text-indigo-600 hover:text-indigo-900">Edit</a> | ||||||
|  |                       {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} | ||||||
|  |                         <button | ||||||
|  |                           on:click={() => { | ||||||
|  |                             active_deletes[t.id] = true; | ||||||
|  |                           }} | ||||||
|  |                           tabindex="0" | ||||||
|  |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button> | ||||||
|  |                       {/if} | ||||||
|  |                     </td> | ||||||
|  |                   {/if} | ||||||
|  |                 </tr> | ||||||
|  |               {/if} | ||||||
|  |             {/each} | ||||||
|  |           </tbody> | ||||||
|  |         </table> | ||||||
|  |       </div> | ||||||
|  |     {/if} | ||||||
|  |   {:catch error} | ||||||
|  |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|  |       <span class="inline-block align-middle mr-8"> | ||||||
|  |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|  |         {error} | ||||||
|  |       </span> | ||||||
|  |     </div> | ||||||
|  |   {/await} | ||||||
|  | {/if} | ||||||
| @@ -6,7 +6,6 @@ | |||||||
|   const tracks_promise = TrackService.trackControllerGetAll(); |   const tracks_promise = TrackService.trackControllerGetAll(); | ||||||
|   import { getlang } from "./datatable_i18n"; |   import { getlang } from "./datatable_i18n"; | ||||||
|   import { Grid, html } from "gridjs"; |   import { Grid, html } from "gridjs"; | ||||||
|   import "gridjs/dist/theme/mermaid.css"; |  | ||||||
|   import { tracks as tracksstore } from "../store.js"; |   import { tracks as tracksstore } from "../store.js"; | ||||||
|   $: trackscache = []; |   $: trackscache = []; | ||||||
|   $: blocked = []; |   $: blocked = []; | ||||||
|   | |||||||
| @@ -1,27 +1,91 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import lodashIsEqual from "lodash.isequal"; |   import lodashIsEqual from "lodash.isequal"; | ||||||
|   import { UserService } from "@odit/lfk-client-js"; |   import store from "../store"; | ||||||
|   import "gridjs/dist/theme/mermaid.css"; |   import { | ||||||
|  |     UserService, | ||||||
|  |     UserGroupService, | ||||||
|  |     PermissionService, | ||||||
|  |   } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|   import PromiseError from "./PromiseError.svelte"; |   import PromiseError from "./PromiseError.svelte"; | ||||||
|   export let params; |   export let params; | ||||||
|   const user_promise = UserService.userControllerGetOne(params.userid); |   const user_promise = UserService.userControllerGetOne(params.userid); | ||||||
|   let data_loaded = false; |   let data_loaded = false; | ||||||
|   let original_data = undefined; |   $: delete_triggered = false; | ||||||
|   $: editable_userdata = undefined; |   $: original_data = {}; | ||||||
|  |   $: editable_userdata = {}; | ||||||
|  |   $: allpermissions = []; | ||||||
|  |   $: allgroups = []; | ||||||
|  |   $: allgroups_ids = []; | ||||||
|  |   $: usergroups_array_objects = []; | ||||||
|  |   $: usergroups_array = []; | ||||||
|  |   let usergroups_array_original = []; | ||||||
|   user_promise.then((data) => { |   user_promise.then((data) => { | ||||||
|     data_loaded = true; |     data_loaded = true; | ||||||
|     original_data = data; |     original_data = Object.assign(original_data, data); | ||||||
|     editable_userdata = data; |     editable_userdata = data; | ||||||
|  |     data.groups.forEach((g) => { | ||||||
|  |       usergroups_array=usergroups_array.concat([g.id]); | ||||||
|  |     }); | ||||||
|  |     usergroups_array_original = usergroups_array; | ||||||
|  |     allgroups.forEach((g) => { | ||||||
|  |       allgroups_ids.push(g.id); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
|   // $: changes_performed = lodashIsEqual(original_data, editable_userdata); |   UserGroupService.userGroupControllerGetAll().then((data) => { | ||||||
|   $: changes_performed = !lodashIsEqual({ test: 1 }, { test: 1 }); |     allgroups = data; | ||||||
|  |   }); | ||||||
|  |   const permissions_promise = PermissionService.permissionControllerGetAll(); | ||||||
|  |   permissions_promise.then((data) => { | ||||||
|  |     data.forEach((p) => { | ||||||
|  |       allpermissions=allpermissions.concat([p.target + ":" + p.action]) | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |   $: changes_performed = !lodashIsEqual(original_data, editable_userdata); | ||||||
|  |   $: groups_changed = JSON.stringify(usergroups_array)===JSON.stringify(usergroups_array_original); | ||||||
|  |   $: save_enabled = changes_performed||!groups_changed; | ||||||
|   function submit() { |   function submit() { | ||||||
|     if (data_loaded === true && changes_performed === true) { |     if ( | ||||||
|       console.log("ok, submitting..."); |       !lodashIsEqual(original_data.permissions, editable_userdata.permissions) | ||||||
|     } else { |     ) { | ||||||
|       console.log("no changes performed"); |       // TODO: add+delete permissions | ||||||
|     } |     } | ||||||
|  |     if (data_loaded === true && save_enabled) { | ||||||
|  |       let tmp=[]; | ||||||
|  |       usergroups_array.forEach(g => { | ||||||
|  |         const group=allgroups.find(obj=>obj.id===g); | ||||||
|  |         tmp.push(group); | ||||||
|  |       }); | ||||||
|  |       editable_userdata.groups=tmp; | ||||||
|  |       Toastify({ | ||||||
|  |         text: $_("updating-user"), | ||||||
|  |         duration: 2500, | ||||||
|  |       }).showToast(); | ||||||
|  |       UserService.userControllerPut(original_data.id, editable_userdata) | ||||||
|  |         .then((resp) => { | ||||||
|  |           Object.assign(original_data, editable_userdata); | ||||||
|  |           original_data = editable_userdata; | ||||||
|  |           Object.assign(original_data, editable_userdata); | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: $_("user-updated"), | ||||||
|  |             duration: 2500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |         }); | ||||||
|  |     } else { | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   function deleteUser() { | ||||||
|  |     UserService.userControllerRemove(original_data.id, true) | ||||||
|  |       .then((resp) => { | ||||||
|  |         location.replace("./"); | ||||||
|  |       }) | ||||||
|  |       .catch((err) => { | ||||||
|  |       }); | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| @@ -63,51 +127,54 @@ | |||||||
|                 <polyline points="12 5 19 12 12 19" /></svg> |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|             </li> |             </li> | ||||||
|             <li class="flex items-center"> |             <li class="flex items-center"> | ||||||
|               <span class="mr-2">{user.firstname} |               <span class="mr-2">{original_data.firstname} | ||||||
|                 {user.middlename || ''} |                 {original_data.middlename || ''} | ||||||
|                 {user.lastname}</span> |                 {original_data.lastname}</span> | ||||||
|             </li> |             </li> | ||||||
|           </ol> |           </ol> | ||||||
|         </nav> |         </nav> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|       {user.firstname} |       {original_data.firstname} | ||||||
|       {user.middlename || ''} |       {original_data.middlename || ''} | ||||||
|       {user.lastname} |       {original_data.lastname} | ||||||
|       <span data-id="user_actions_${user.id}"> |       <span data-id="user_actions_${editable_userdata.id}"> | ||||||
|         <button |         {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||||
|           class="hidden w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-400 text-base font-medium text-white sm:w-auto sm:text-sm" |           {#if delete_triggered} | ||||||
|           data-userid="${user.id}" |             <button | ||||||
|           onclick="user__delete_cancel()">{$_('cancel')}</button> |               on:click={deleteUser} | ||||||
|         <button |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button> | ||||||
|           class="hidden w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-500 text-base font-medium text-white sm:w-auto sm:text-sm" |             <button | ||||||
|           data-userid="${user.id}" |               on:click={() => { | ||||||
|           onclick="user__delete_confirm()">{$_('confirm-delete')}</button> |                 delete_triggered = !delete_triggered; | ||||||
|         <button |               }} | ||||||
|           type="button" |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> | ||||||
|           class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-user')}</button> |           {/if} | ||||||
|         <button |           {#if !delete_triggered} | ||||||
|           disabled={!changes_performed} |             <button | ||||||
|           class:opacity-50={!changes_performed} |               on:click={() => { | ||||||
|           type="button" |                 delete_triggered = true; | ||||||
|           on:click={submit} |               }} | ||||||
|           class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('save-changes')}</button> |               type="button" | ||||||
|  |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-user')}</button> | ||||||
|  |           {/if} | ||||||
|  |         {/if} | ||||||
|  |         {#if !delete_triggered} | ||||||
|  |           <button | ||||||
|  |             disabled={!save_enabled} | ||||||
|  |             class:opacity-50={!save_enabled} | ||||||
|  |             type="button" | ||||||
|  |             on:click={submit} | ||||||
|  |             class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('save-changes')}</button> | ||||||
|  |         {/if} | ||||||
|       </span> |       </span> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <!--  --> |  | ||||||
|     <div class="mt-2 flex items-center"> |     <div class="mt-2 flex items-center"> | ||||||
|       <img |       <img | ||||||
|         alt={$_('profile-picture')} |         alt={$_('profile-picture')} | ||||||
|         class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100" |         class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100" | ||||||
|         src={user.profilePic} /> |         src={editable_userdata.profilePic} /> | ||||||
|       <!-- <span |  | ||||||
|         class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100"><svg |  | ||||||
|           class="h-full w-full text-gray-300" |  | ||||||
|           fill="currentColor" |  | ||||||
|           viewBox="0 0 24 24"><path |  | ||||||
|             d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" /></svg></span> --> |  | ||||||
|       <button |       <button | ||||||
|         type="button" |         type="button" | ||||||
|         class="ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Change</button> |         class="ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Change</button> | ||||||
| @@ -165,6 +232,102 @@ | |||||||
|         name="lastname" |         name="lastname" | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|     </div> |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label | ||||||
|  |         for="email" | ||||||
|  |         class="font-medium text-gray-700">{$_('e-mail-adress')}</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder={$_('e-mail-adress')} | ||||||
|  |         type="email" | ||||||
|  |         bind:value={editable_userdata.email} | ||||||
|  |         name="email" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <label | ||||||
|  |         for="username" | ||||||
|  |         class="font-medium text-gray-700">{$_('username')}</label> | ||||||
|  |       <input | ||||||
|  |         autocomplete="off" | ||||||
|  |         placeholder={$_('username')} | ||||||
|  |         type="text" | ||||||
|  |         bind:value={editable_userdata.username} | ||||||
|  |         name="username" | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <span class="font-medium">{$_('groups')}</span> | ||||||
|  |       <!-- svelte-ignore a11y-no-onchange --> | ||||||
|  |       <select | ||||||
|  |         bind:value={usergroups_array} | ||||||
|  |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" | ||||||
|  |         multiple> | ||||||
|  |         {#each allgroups as g} | ||||||
|  |           {#if usergroups_array.includes(g.id)} | ||||||
|  |             <option selected value={g.id}>{g.name}</option> | ||||||
|  |           {:else} | ||||||
|  |             <option value={g.id}>{g.name}</option> | ||||||
|  |           {/if} | ||||||
|  |         {/each} | ||||||
|  |       </select> | ||||||
|  |     </div> | ||||||
|  |     <div class="text-sm w-full"> | ||||||
|  |       <span class="font-medium">Permissions</span> | ||||||
|  |       <div class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"> | ||||||
|  |         <!--  --> | ||||||
|  |         <div class="flex flex-wrap -mx-1 overflow-hidden"> | ||||||
|  |           <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2"> | ||||||
|  |             verfügbare | ||||||
|  |           </div> | ||||||
|  |           <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2">erteilte</div> | ||||||
|  |         </div> | ||||||
|  |         <!--  --> | ||||||
|  |         <div class="flex flex-wrap -mx-1 overflow-hidden"> | ||||||
|  |           {#if allpermissions.length > 0} | ||||||
|  |             <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2"> | ||||||
|  |               <div | ||||||
|  |                 class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"> | ||||||
|  |                 {#each allpermissions as p} | ||||||
|  |                   {#if !editable_userdata.permissions.includes(p)} | ||||||
|  |                     <p | ||||||
|  |                       class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"> | ||||||
|  |                       {p} | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           editable_userdata.permissions.push(p); | ||||||
|  |                           editable_userdata.permissions = editable_userdata.permissions; | ||||||
|  |                         }} | ||||||
|  |                         type="button" | ||||||
|  |                         class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-200 text-base font-medium text-black hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 sm:ml-3 sm:w-auto sm:text-sm">+</button> | ||||||
|  |                     </p> | ||||||
|  |                   {/if} | ||||||
|  |                 {/each} | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2"> | ||||||
|  |               <div | ||||||
|  |                 class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"> | ||||||
|  |                 {#each allpermissions as p} | ||||||
|  |                   {#if editable_userdata.permissions.includes(p)} | ||||||
|  |                     <p | ||||||
|  |                       class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"> | ||||||
|  |                       {p} | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           editable_userdata.permissions = editable_userdata.permissions.filter((obj) => obj !== p); | ||||||
|  |                         }} | ||||||
|  |                         type="button" | ||||||
|  |                         class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-300 text-base font-medium text-black hover:bg-red-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm">-</button> | ||||||
|  |                     </p> | ||||||
|  |                   {/if} | ||||||
|  |                 {/each} | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           {/if} | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|   </section> |   </section> | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> |   <PromiseError {error} /> | ||||||
|   | |||||||
| @@ -1,23 +1,31 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|  |   import store from "../store"; | ||||||
|   import AddUserModal from "./AddUserModal.svelte"; |   import AddUserModal from "./AddUserModal.svelte"; | ||||||
|   export let modal_open = false; |   export let modal_open = false; | ||||||
|   import UsersOverview from "./UsersOverview.svelte"; |   import UsersOverview from "./UsersOverview.svelte"; | ||||||
|  |   console.log(store.state.jwtinfo.userdetails.permissions); | ||||||
|  |   let current_users=[]; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_('users')} |     {$_('users')} | ||||||
|     <button |     {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||||
|       on:click={() => { |       <button | ||||||
|         modal_open = true; |         on:click={() => { | ||||||
|       }} |           modal_open = true; | ||||||
|       type="button" |         }} | ||||||
|       class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> |         type="button" | ||||||
|       {$_('create-user')} |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|     </button> |         {$_('create-user')} | ||||||
|  |       </button> | ||||||
|  |     {/if} | ||||||
|   </span> |   </span> | ||||||
|   <p class="mb-8 text-lg text-gray-500">{$_('manage-admin-users')}</p> |   <p class="mb-8 text-lg text-gray-500">{$_('manage-admin-users')}</p> | ||||||
|   <UsersOverview /> |   <UsersOverview bind:current_users /> | ||||||
| </section> | </section> | ||||||
| <AddUserModal bind:modal_open /> |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||||
|  |   <AddUserModal bind:current_users bind:modal_open /> | ||||||
|  | {/if} | ||||||
|   | |||||||
| @@ -1,147 +1,178 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import Toastify from "toastify-js"; |  | ||||||
|   import { UserService } from "@odit/lfk-client-js"; |   import { UserService } from "@odit/lfk-client-js"; | ||||||
|   const users_promise = UserService.userControllerGetAll(); |   const users_promise = UserService.userControllerGetAll(); | ||||||
|   import "gridjs/dist/theme/mermaid.css"; |  | ||||||
|   import { users as usersstore } from "../store.js"; |   import { users as usersstore } from "../store.js"; | ||||||
|  |   import store from "../store"; | ||||||
|   import UsersEmptyState from "./UsersEmptyState.svelte"; |   import UsersEmptyState from "./UsersEmptyState.svelte"; | ||||||
|   $: searchvalue = ""; |   $: searchvalue = ""; | ||||||
|   $: userscache = []; |   $: active_deletes = []; | ||||||
|  |   export let current_users=[]; | ||||||
|   $: advanced_search = false; |   $: advanced_search = false; | ||||||
|   usersstore.subscribe((val) => { |   usersstore.subscribe((val) => { | ||||||
|     userscache = val; |     current_users=val; | ||||||
|   }); |   }); | ||||||
|   users_promise.then((data) => { |   users_promise.then((data) => { | ||||||
|     console.log(data); |  | ||||||
|     usersstore.set(data); |     usersstore.set(data); | ||||||
|   }); |   }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await users_promise} | {#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')} | ||||||
|   <div |   {#await users_promise} | ||||||
|     class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |  | ||||||
|     role="alert"> |  | ||||||
|     <p class="font-bold">users are being loaded...</p> |  | ||||||
|     <p class="text-sm">{$_('this-might-take-a-moment')}</p> |  | ||||||
|   </div> |  | ||||||
| {:then users} |  | ||||||
|   {#if userscache.length === 0} |  | ||||||
|     <UsersEmptyState /> |  | ||||||
|   {:else} |  | ||||||
|     {#if advanced_search} |  | ||||||
|       advanced search |  | ||||||
|     {:else} |  | ||||||
|       <input |  | ||||||
|         type="search" |  | ||||||
|         bind:value={searchvalue} |  | ||||||
|         placeholder={$_('datatable.search')} |  | ||||||
|         aria-label={$_('datatable.search')} |  | ||||||
|         class="gridjs-input gridjs-search-input mb-4" /> |  | ||||||
|     {/if} |  | ||||||
|     <button |  | ||||||
|       on:click={() => { |  | ||||||
|         advanced_search = !advanced_search; |  | ||||||
|       }} |  | ||||||
|       type="button" |  | ||||||
|       class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-600 text-base font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm"> |  | ||||||
|       {#if advanced_search} |  | ||||||
|         toggle simple search |  | ||||||
|       {:else}toggle advanced search{/if} |  | ||||||
|     </button> |  | ||||||
|     <div |     <div | ||||||
|       class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|       <table class="divide-y divide-gray-200 w-full"> |       role="alert"> | ||||||
|         <thead class="bg-gray-50"> |       <p class="font-bold">users are being loaded...</p> | ||||||
|           <tr> |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|             <th |     </div> | ||||||
|               scope="col" |   {:then} | ||||||
|               class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |     {#if current_users.length === 0} | ||||||
|               Name |       <UsersEmptyState /> | ||||||
|             </th> |     {:else} | ||||||
|             <th |       {#if advanced_search} | ||||||
|               scope="col" |         advanced search | ||||||
|               class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |       {:else} | ||||||
|               Status |         <input | ||||||
|             </th> |           type="search" | ||||||
|             <th |           bind:value={searchvalue} | ||||||
|               scope="col" |           placeholder={$_('datatable.search')} | ||||||
|               class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |           aria-label={$_('datatable.search')} | ||||||
|               Groups |           class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|             </th> |       {/if} | ||||||
|             <th scope="col" class="relative px-6 py-3"> |       <button | ||||||
|               <span class="sr-only">Action</span> |         on:click={() => { | ||||||
|             </th> |           advanced_search = !advanced_search; | ||||||
|           </tr> |         }} | ||||||
|         </thead> |         type="button" | ||||||
|         <tbody class="divide-y divide-gray-200"> |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-600 text-base font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|           {#each users as u} |         {#if advanced_search} | ||||||
|             {#if Object.values(u) |           toggle simple search | ||||||
|               .toString() |         {:else}toggle advanced search{/if} | ||||||
|               .toLowerCase() |       </button> | ||||||
|               .includes(searchvalue)} |       <div | ||||||
|               <tr> |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|                 <td class="px-6 py-4 whitespace-nowrap"> |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|                   <div class="flex items-center"> |           <thead class="bg-gray-50"> | ||||||
|                     {#if u.profilePic} |             <tr> | ||||||
|                       <div class="flex-shrink-0 h-10 w-10"> |               <th | ||||||
|                         <img |                 scope="col" | ||||||
|                           class="h-10 w-10 rounded-full" |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|                           src={u.profilePic} |                 Name | ||||||
|                           alt="" /> |               </th> | ||||||
|                       </div> |               <th | ||||||
|                     {/if} |                 scope="col" | ||||||
|                     <div class="ml-4"> |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|                       <div |                 Status | ||||||
|                         class="text-sm font-medium text-gray-900 dark:text-gray-100"> |               </th> | ||||||
|                         {u.firstname} |               <th | ||||||
|                         {u.middlename || ''} |                 scope="col" | ||||||
|                         {u.lastname} |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|                       </div> |                 Groups | ||||||
|                       <div class="text-sm text-gray-500"> |               </th> | ||||||
|                         {u.email || u.username} |               <th scope="col" class="relative px-6 py-3"> | ||||||
|  |                 <span class="sr-only">Action</span> | ||||||
|  |               </th> | ||||||
|  |             </tr> | ||||||
|  |           </thead> | ||||||
|  |           <tbody class="divide-y divide-gray-200"> | ||||||
|  |             {#each current_users as u} | ||||||
|  |               {#if Object.values(u) | ||||||
|  |                 .toString() | ||||||
|  |                 .toLowerCase() | ||||||
|  |                 .includes(searchvalue)} | ||||||
|  |                 <tr data-rowid="user_{u.id}"> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  |                     <div class="flex items-center"> | ||||||
|  |                       {#if u.profilePic} | ||||||
|  |                         <div class="flex-shrink-0 h-10 w-10"> | ||||||
|  |                           <img | ||||||
|  |                             class="h-10 w-10 rounded-full" | ||||||
|  |                             src={u.profilePic} | ||||||
|  |                             alt="" /> | ||||||
|  |                         </div> | ||||||
|  |                       {/if} | ||||||
|  |                       <div class="ml-4"> | ||||||
|  |                         <div | ||||||
|  |                           class="text-sm font-medium text-gray-900 dark:text-gray-100"> | ||||||
|  |                           {u.firstname} | ||||||
|  |                           {u.middlename || ''} | ||||||
|  |                           {u.lastname} | ||||||
|  |                         </div> | ||||||
|  |                         <div class="text-sm text-gray-500"> | ||||||
|  |                           {u.email || u.username} | ||||||
|  |                         </div> | ||||||
|                       </div> |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
|                   </div> |                   </td> | ||||||
|                 </td> |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                 <td class="px-6 py-4 whitespace-nowrap"> |                     {#if u.enabled} | ||||||
|                   {#if u.enabled} |                       <span | ||||||
|                     <span |                         class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span> | ||||||
|                       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span> |                     {:else} | ||||||
|  |                       <span | ||||||
|  |                         class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Inactive</span> | ||||||
|  |                     {/if} | ||||||
|  |                   </td> | ||||||
|  |                   <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | ||||||
|  |                     {#each u.groups as g} | ||||||
|  |                       <a | ||||||
|  |                         href="../groups/{g.id}" | ||||||
|  |                         class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a> | ||||||
|  |                     {/each} | ||||||
|  |                   </td> | ||||||
|  |                   {#if active_deletes[u.id] === true} | ||||||
|  |                     <td | ||||||
|  |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           active_deletes[u.id] = false; | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel | ||||||
|  |                         Delete</button> | ||||||
|  |                       <button | ||||||
|  |                         on:click={() => { | ||||||
|  |                           UserService.userControllerRemove(u.id, true) | ||||||
|  |                             .then((resp) => { | ||||||
|  |                               current_users=current_users.filter(obj=>obj.id!==u.id); | ||||||
|  |                             }) | ||||||
|  |                             .catch((err) => { | ||||||
|  |                               // error deleting user | ||||||
|  |                             }); | ||||||
|  |                         }} | ||||||
|  |                         tabindex="0" | ||||||
|  |                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Confirm | ||||||
|  |                         Delete</button> | ||||||
|  |                     </td> | ||||||
|                   {:else} |                   {:else} | ||||||
|                     <span |                     <td | ||||||
|                       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Inactive</span> |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|  |                       <a | ||||||
|  |                         href="./{u.id}" | ||||||
|  |                         class="text-indigo-600 hover:text-indigo-900">Edit</a> | ||||||
|  |                       {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||||
|  |                         <button | ||||||
|  |                           on:click={() => { | ||||||
|  |                             active_deletes[u.id] = true; | ||||||
|  |                           }} | ||||||
|  |                           tabindex="0" | ||||||
|  |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button> | ||||||
|  |                       {/if} | ||||||
|  |                     </td> | ||||||
|                   {/if} |                   {/if} | ||||||
|                 </td> |                 </tr> | ||||||
|                 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> |               {/if} | ||||||
|                   {#each u.groups as g} |             {/each} | ||||||
|                     <a |           </tbody> | ||||||
|                       href="../groups/{g.id}" |         </table> | ||||||
|                       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a> |       </div> | ||||||
|                   {/each} |     {/if} | ||||||
|                 </td> |   {:catch error} | ||||||
|                 <td |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|                   class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |       <span class="inline-block align-middle mr-8"> | ||||||
|                   <a |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|                     href="./{u.id}" |         {error} | ||||||
|                     class="text-indigo-600 hover:text-indigo-900">Edit</a> |       </span> | ||||||
|                   <span |  | ||||||
|                     tabindex="0" |  | ||||||
|                     href="#" |  | ||||||
|                     class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</span> |  | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
|             {/if} |  | ||||||
|           {/each} |  | ||||||
|         </tbody> |  | ||||||
|       </table> |  | ||||||
|     </div> |     </div> | ||||||
|   {/if} |   {/await} | ||||||
| {:catch error} | {/if} | ||||||
|   <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> |  | ||||||
|     <span class="inline-block align-middle mr-8"> |  | ||||||
|       <b class="capitalize">{$_('general_promise_error')}</b> |  | ||||||
|       {error} |  | ||||||
|     </span> |  | ||||||
|   </div> |  | ||||||
| {/await} |  | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								src/components/org_empty.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/components/org_empty.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										1
									
								
								src/components/runners_empty.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/components/runners_empty.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 854.63 686"><path fill="#3f3d56" d="M0 600h821v9.053H0zM0 676.947h821V686H0z"/><path d="M750.178 608.328c-.49-.802-12.06-20.12-16.071-60.234-3.68-36.802-1.313-98.836 30.858-185.367 60.947-163.928-14.046-296.194-14.812-297.512l3.7-2.146c.194.334 19.545 34.057 30.977 87.755a382.846 382.846 0 01-15.856 213.394c-60.844 163.648-15.61 241.118-15.146 241.882z" fill="#3f3d56"/><circle cx="726.346" cy="27.795" r="27.795" fill="#3f3d56"/><circle cx="814.007" cy="130.422" r="27.795" fill="#3f3d56"/><circle cx="754.141" cy="198.841" r="27.795" fill="#dfe5ee"/><circle cx="826.835" cy="256.569" r="27.795" fill="#dfe5ee"/><circle cx="732.76" cy="346.368" r="27.795" fill="#3f3d56"/><path d="M766.97 609.35s-27.796-68.418 55.59-119.731zM732.786 608.11s-12.65-72.758-110.557-72.134z" fill="#3f3d56"/><circle cx="136.5" cy="387.5" r="41" fill="#a0616a"/><path d="M143.928 336.504c-7.84-1.925-16.272-2.247-23.868.49-7.824 2.817-14.263 8.708-19 15.542s-7.918 14.613-10.767 22.425a78.442 78.442 0 00-3.845 13.14 44.992 44.992 0 008.167 34.325c-1.2-3.166 1.822-6.617 5.138-7.303s6.693.474 9.963 1.353a61.559 61.559 0 0017.68 2.078c2.284-.065 4.679-.295 6.578-1.565 5.952-3.98 2.802-14.263 7.754-19.434 1.767-1.845 4.29-2.708 6.567-3.865 8.2-4.167 13.604-12.576 16.156-21.413 1.599-5.54 5.567-21.45 2.185-26.598-3.057-4.653-17.516-7.9-22.708-9.175z" fill="#2f2e41"/><path d="M248.066 342.291a24.396 24.396 0 00-18.677 1.041c-10.695 5.016-29.608 17.167-28.889 40.168 1 32 12 53 12 53l-2 65-10 118s-49 40-30 50 51-48 51-48l25-67 9-65s15-68 0-98c0 0 17.328-40.17-7.434-49.209zM367.5 445.5s-17 72 43 92 139 54 139 54l10 17 23-31-4-24-39-11s-73-56-105-60l4-37zM527.307 387.717L548.5 422.5s70 40 88 67 61 56 61 56l-19 45s-54-63-77-69-125-88-125-88z" fill="#a0616a"/><path d="M338.568 265.819c-7.805 1.226-15.617 2.454-23.33 4.174-17.917 3.995-35.147 10.616-51.966 17.974a608.405 608.405 0 00-68.447 35.267 132.255 132.255 0 00-16.97 11.523c-3.559 2.964-6.91 6.363-8.82 10.584a33.406 33.406 0 00-2.33 9.221c-1.55 11.12-1.477 22.595 1.535 33.41s9.124 20.955 18.119 27.674a29.88 29.88 0 007.84 4.348 45.675 45.675 0 0011.675 1.957c12.617 1.003 25.798 1.923 37.474-2.964 7.42-3.105 13.701-8.354 20.528-12.607 28.913-18.008 65.646-17.241 97.26-29.92 3.074-1.233 6.204-2.67 8.354-5.189a22.578 22.578 0 003.62-7.187l11.99-33.188c2.533-7.01 5.067-14.023 7.193-21.167 2.224-7.472 3.996-15.07 5.766-22.661 1.524-6.534 3.093-13.376 2.507-20.13-.864-9.962-3.166-10.367-12.316-8.925q-24.839 3.915-49.682 7.806z" fill="#dfe5ee"/><path d="M218.066 342.291a24.396 24.396 0 00-18.677 1.041c-10.695 5.016-29.608 17.167-28.889 40.168 1 32 12 53 12 53l-2 65-10 118s-49 40-30 50 51-48 51-48l25-67 9-65s15-68 0-98c0 0 17.328-40.17-7.434-49.209z" fill="#a0616a"/><path d="M391.66 257.544S480.5 249.5 476.5 304.5s-34 150-34 150l-77 4s-10-65 4-87z" fill="#2f2e41"/><path d="M453.5 275.5s22 14 34 42 48 83 48 83l-59 42-44-45zM559.5 587.5s-19 7-6 21a126.61 126.61 0 0120 29s-4 26 13 25 24-36 20-48-9-69-9-69-35 3-34 8 6 30-4 34zM678.5 567.5s-18 9-13 17 21 31 21 31-6 30 11 33 27-36 24-44-3-39-3-39 1-31-9-31-27 4-27 4 4 28-4 29z" fill="#2f2e41"/><path fill="#dfe5ee" d="M96 617.871h29v50.612H96z"/></svg> | ||||||
| After Width: | Height: | Size: 3.2 KiB | 
							
								
								
									
										1
									
								
								src/components/team_empty.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/components/team_empty.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 52 KiB | 
| @@ -26,6 +26,7 @@ | |||||||
|     "general-stats": "Allgemeine Statistiken", |     "general-stats": "Allgemeine Statistiken", | ||||||
|     "goback": "Zur Startseite", |     "goback": "Zur Startseite", | ||||||
|     "hallo": "hallo", |     "hallo": "hallo", | ||||||
|  |     "icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:", | ||||||
|     "invalid-mail-reset": "Das ist keine gültige E-Mail", |     "invalid-mail-reset": "Das ist keine gültige E-Mail", | ||||||
|     "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", |     "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", | ||||||
|     "log_in": "Anmelden", |     "log_in": "Anmelden", | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
|     "about": "About", |     "about": "About", | ||||||
|     "action": "Action", |     "action": "Action", | ||||||
|     "add-your-first-track": "Add your first track", |     "add-your-first-track": "Add your first track", | ||||||
|  |     "address": "Address", | ||||||
|     "application_name": "Lauf für Kaya! - Admin", |     "application_name": "Lauf für Kaya! - Admin", | ||||||
|     "author": "Author", |     "author": "Author", | ||||||
|     "browse": "Browse", |     "browse": "Browse", | ||||||
| @@ -13,10 +14,12 @@ | |||||||
|     "changelog": "Changelog", |     "changelog": "Changelog", | ||||||
|     "close": "Close", |     "close": "Close", | ||||||
|     "confirm-delete": "Confirm Delete", |     "confirm-delete": "Confirm Delete", | ||||||
|  |     "contact": "Contact", | ||||||
|     "count_organizations": "# Organizations", |     "count_organizations": "# Organizations", | ||||||
|     "count_teams": "# Teams", |     "count_teams": "# Teams", | ||||||
|     "create": "Create", |     "create": "Create", | ||||||
|     "create-a-new-track": "Create a new Track", |     "create-a-new-track": "Create a new Track", | ||||||
|  |     "create-organization": "Create Organization", | ||||||
|     "create-user": "Create User", |     "create-user": "Create User", | ||||||
|     "credits": "Credits", |     "credits": "Credits", | ||||||
|     "dashboard-greeting": "hello there", |     "dashboard-greeting": "hello there", | ||||||
| @@ -36,6 +39,8 @@ | |||||||
|         "no_matching_records_found": "No matching records found", |         "no_matching_records_found": "No matching records found", | ||||||
|         "an_error_happened_while_fetching_the_data": "An error happened while fetching the data" |         "an_error_happened_while_fetching_the_data": "An error happened while fetching the data" | ||||||
|     }, |     }, | ||||||
|  |     "delete-organization": "Delete Organization", | ||||||
|  |     "delete-team": "Delete Team", | ||||||
|     "delete-user": "Delete User", |     "delete-user": "Delete User", | ||||||
|     "dependency_name": "Name", |     "dependency_name": "Name", | ||||||
|     "dont-have-your-email-connected": "Don't have your email connected?", |     "dont-have-your-email-connected": "Don't have your email connected?", | ||||||
| @@ -71,7 +76,9 @@ | |||||||
|     "general-stats": "General Stats", |     "general-stats": "General Stats", | ||||||
|     "general_promise_error": "😢 Error", |     "general_promise_error": "😢 Error", | ||||||
|     "goback": "Go Home", |     "goback": "Go Home", | ||||||
|  |     "groups": "Groups", | ||||||
|     "hallo": "hello", |     "hallo": "hello", | ||||||
|  |     "icon-image-credits": "We also want to thank these projects for illustrations and icons:", | ||||||
|     "installed-version": "Installed version", |     "installed-version": "Installed version", | ||||||
|     "invalid-mail-reset": "the provided email is invalid", |     "invalid-mail-reset": "the provided email is invalid", | ||||||
|     "last-name": "Last name", |     "last-name": "Last name", | ||||||
| @@ -89,6 +96,8 @@ | |||||||
|     "minimum-lap-time-in-s": "minimum lap time in s", |     "minimum-lap-time-in-s": "minimum lap time in s", | ||||||
|     "no-license-text-could-be-found": "No license text could be found 😢", |     "no-license-text-could-be-found": "No license text could be found 😢", | ||||||
|     "no-tracks-added-yet": "there are no tracks added yet.", |     "no-tracks-added-yet": "there are no tracks added yet.", | ||||||
|  |     "organization": "Organization", | ||||||
|  |     "organizations": "Organizations", | ||||||
|     "orgs": "Orgs", |     "orgs": "Orgs", | ||||||
|     "oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!", |     "oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!", | ||||||
|     "password": "Password", |     "password": "Password", | ||||||
| @@ -105,6 +114,7 @@ | |||||||
|     "settings": "Settings", |     "settings": "Settings", | ||||||
|     "signout": "Sign out", |     "signout": "Sign out", | ||||||
|     "stats-are-being-loaded": "stats are being loaded...", |     "stats-are-being-loaded": "stats are being loaded...", | ||||||
|  |     "team-name": "Team name", | ||||||
|     "teams": "Teams", |     "teams": "Teams", | ||||||
|     "this-might-take-a-moment": "This might take a moment 👀", |     "this-might-take-a-moment": "This might take a moment 👀", | ||||||
|     "total-distance": "total distance", |     "total-distance": "total distance", | ||||||
| @@ -116,6 +126,9 @@ | |||||||
|     "track-length-in-m": "Track Length in m", |     "track-length-in-m": "Track Length in m", | ||||||
|     "track-name": "Track name", |     "track-name": "Track name", | ||||||
|     "tracks": "Tracks", |     "tracks": "Tracks", | ||||||
|  |     "updating-user": "updating user...", | ||||||
|  |     "user-updated": "User updated", | ||||||
|  |     "username": "Username", | ||||||
|     "users": "Users", |     "users": "Users", | ||||||
|     "valid-email-is-required": "valid email is required", |     "valid-email-is-required": "valid email is required", | ||||||
|     "welcome_wavinghand": "Welcome 👋", |     "welcome_wavinghand": "Welcome 👋", | ||||||
|   | |||||||
| @@ -27,6 +27,8 @@ const store = () => { | |||||||
| 			AuthService.authControllerRefresh({ token: state.auth.refresh_token }).then((auth) => { | 			AuthService.authControllerRefresh({ token: state.auth.refresh_token }).then((auth) => { | ||||||
| 				console.log('got new auth'); | 				console.log('got new auth'); | ||||||
| 				OpenAPI.TOKEN = auth.access_token; | 				OpenAPI.TOKEN = auth.access_token; | ||||||
|  | 				const jwtinfo = JSON.parse(atob(auth.access_token.split('.')[1])); | ||||||
|  | 				state.jwtinfo = jwtinfo; | ||||||
| 				localForage.setItem('logindata', auth); | 				localForage.setItem('logindata', auth); | ||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
| @@ -39,8 +41,8 @@ const store = () => { | |||||||
| 				// | 				// | ||||||
| 				state.refreshInterval = setInterval(() => { | 				state.refreshInterval = setInterval(() => { | ||||||
| 					this.refreshAuth(); | 					this.refreshAuth(); | ||||||
| 					// 4min | 					// 2min | ||||||
| 				}, 4 * 60000); | 				}, 2 * 60000); | ||||||
| 				// | 				// | ||||||
| 				return state; | 				return state; | ||||||
| 			}); | 			}); | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ module.exports = { | |||||||
| 	purge: { | 	purge: { | ||||||
| 		content: [ './src/**/*.svelte' ] | 		content: [ './src/**/*.svelte' ] | ||||||
| 	}, | 	}, | ||||||
| 	darkMode: 'media', | 	// darkMode: 'media', | ||||||
| 	variants: {}, | 	variants: {}, | ||||||
| 	plugins: [], | 	plugins: [], | ||||||
| 	theme: { | 	theme: { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user