Compare commits
	
		
			68 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7cd24cd51d | |||
| c81b34c1d0 | |||
| 7b1acc494d | |||
| 6ff90694e2 | |||
| 157c7c66b5 | |||
| 93249258c6 | |||
| 01c01a46fa | |||
| 0e2a10fe94 | |||
| 0b9f3de47c | |||
| bc239eead1 | |||
| 7a09869b0c | |||
| bdc0de6ada | |||
| 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 | |||
| 330755c63e | |||
| 9cf0174b41 | |||
| 16f572480a | |||
| b8a9e4f272 | |||
| c089bb3929 | |||
| 3caa1fc277 | |||
| 43b406592e | |||
| 1dd6674faa | |||
| 4674b52717 | |||
| cd5831251a | |||
| 45ec97066f | |||
| b08c0f145a | |||
| f0c100aee4 | |||
| 0e31ba212f | |||
| 692c906cd2 | |||
| 4f3837ac45 | 
							
								
								
									
										24
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -4,18 +4,6 @@ type: docker | ||||
| name: build:dev | ||||
|  | ||||
| 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 | ||||
|     depends_on: ["clone"] | ||||
|     image: node:alpine | ||||
| @@ -33,6 +21,18 @@ steps: | ||||
|       remote: git@git.odit.services:lfk/frontend.git | ||||
|       ssh_key: | ||||
|         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: | ||||
|   branch: | ||||
|   | ||||
							
								
								
									
										92
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,8 +2,99 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||
|  | ||||
| #### [0.3.0](https://git.odit.services/lfk/frontend/compare/0.2.1...0.3.0) | ||||
|  | ||||
| - 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) | ||||
| - 🏬 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) | ||||
|  | ||||
| > 10 January 2021 | ||||
|  | ||||
| - 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) | ||||
| - 📅 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) | ||||
| - ✨ added versionbuilder.js script [`1dd6674`](https://git.odit.services/lfk/frontend/commit/1dd6674faad686c0048a62b4cd25ab21b5c8b04f) | ||||
| - ⚡ add versionbuilder script to release hook [`16f5724`](https://git.odit.services/lfk/frontend/commit/16f572480ad55425890061f9dad65fe85f2f39ad) | ||||
| - 🔨 sample build of index.html with versionbuilder script [`3caa1fc`](https://git.odit.services/lfk/frontend/commit/3caa1fc277b99ee767c1e1fc4a28fd247d98e659) | ||||
|  | ||||
| #### [0.1.4](https://git.odit.services/lfk/frontend/compare/0.1.3...0.1.4) | ||||
|  | ||||
| > 10 January 2021 | ||||
|  | ||||
| - Merge commit '45ec97066f425ac2ac66914be649cbd5a1038e10' into dev [`#20`](https://git.odit.services/lfk/frontend/issues/20) | ||||
| - 🌎 add remaining translation keys for filepond [`45ec970`](https://git.odit.services/lfk/frontend/commit/45ec97066f425ac2ac66914be649cbd5a1038e10) | ||||
| - add basic i18n logic to filepond [`b08c0f1`](https://git.odit.services/lfk/frontend/commit/b08c0f145a13d295b2a51c7a6da76faceb80a90c) | ||||
| - 🚀RELEASE v0.1.4 [`4674b52`](https://git.odit.services/lfk/frontend/commit/4674b52717e388122e113553b8a136c649ce030c) | ||||
| - 🌎 About - i18n [`692c906`](https://git.odit.services/lfk/frontend/commit/692c906cd26bdb7f7d730b90734d23748e0ab451) | ||||
| - ✨ About - change license modal icon to "legal" [`0e31ba2`](https://git.odit.services/lfk/frontend/commit/0e31ba212f99d90b133bc242e5b4d163aa99b93b) | ||||
| - new license file version [CI SKIP] [`4f3837a`](https://git.odit.services/lfk/frontend/commit/4f3837ac45a5df9a7476fd68ec9c069dc6b128cd) | ||||
|  | ||||
| #### [0.1.3](https://git.odit.services/lfk/frontend/compare/0.1.2...0.1.3) | ||||
|  | ||||
| > 10 January 2021 | ||||
|  | ||||
| - 🌎 improved i18n for AddUserModal and UserDetail [`1c356a4`](https://git.odit.services/lfk/frontend/commit/1c356a41f54a954afaa69ed524f62c1676f7bbee) | ||||
| - 🧹 simplified UsersOverview table [`e1d5d54`](https://git.odit.services/lfk/frontend/commit/e1d5d54cfb1fb20e56f0e971e2cfd196e9a913ac) | ||||
| - 🌎 added i18n for UsersOverview [`3754f09`](https://git.odit.services/lfk/frontend/commit/3754f09b2f395a82ff8c3a9c655ab8a782e7eb71) | ||||
| @@ -11,6 +102,7 @@ All notable changes to this project will be documented in this file. Dates are d | ||||
| - AddUserModal - data validation [`264e0d7`](https://git.odit.services/lfk/frontend/commit/264e0d7ed98c5000da543af154d6e36a6b956e4a) | ||||
| - ✨ sample layout for advanced search [`5ec1dfa`](https://git.odit.services/lfk/frontend/commit/5ec1dfa8b0da4619f14e73794b9a9e22872aa330) | ||||
| - userdetail - dynamic buttons [`ded3198`](https://git.odit.services/lfk/frontend/commit/ded31980bfbf9f09afa2818bdcc8cc3e40748441) | ||||
| - 🚀RELEASE v0.1.3 [`ccb5125`](https://git.odit.services/lfk/frontend/commit/ccb5125a48486ef55709419eccd7d9e912a1e64c) | ||||
| - 🔍 UsersOverview table - basic fuzzy search [`b9e0be4`](https://git.odit.services/lfk/frontend/commit/b9e0be448398d087005e220d08e34461490be14e) | ||||
|  | ||||
| #### [0.1.2](https://git.odit.services/lfk/frontend/compare/0.1.2-1...0.1.2) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| FROM node:15.4.0-alpine3.12 | ||||
| FROM node:15.5.1-alpine3.12 | ||||
| WORKDIR /app | ||||
| RUN npm i -g pnpm | ||||
| COPY package.json ./ | ||||
| @@ -11,6 +11,7 @@ RUN pnpm run build | ||||
| # final image | ||||
| FROM alpine | ||||
| 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_/locales | ||||
| RUN rm -rf /app/build-manifest.json | ||||
|   | ||||
| @@ -9,7 +9,7 @@ http { | ||||
|         location / { | ||||
|             try_files $uri $uri/ /index.html; | ||||
|         } | ||||
|         location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { | ||||
|         location ~* \.(?:ico|css|gif|jpe?g|png)$ { | ||||
|             expires 1y; | ||||
|             add_header Pragma public; | ||||
|             add_header Cache-Control "public"; | ||||
|   | ||||
							
								
								
									
										13
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,19 +1,18 @@ | ||||
| { | ||||
| 	"name": "@odit/lfk-frontend", | ||||
| 	"version": "0.1.3", | ||||
| 	"version": "0.3.0", | ||||
| 	"scripts": { | ||||
| 		"i18n-order": "node order.js", | ||||
| 		"dev": "snowpack dev", | ||||
| 		"build": "snowpack build", | ||||
| 		"build:sw": "workbox generateSW workbox-config.js", | ||||
| 		"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" | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"@odit/lfk-client-js": "0.0.10", | ||||
| 		"@odit/lfk-client-js": "0.0.12", | ||||
| 		"filepond": "4.25.1", | ||||
| 		"gridjs": "3.2.1", | ||||
| 		"gridjs": "3.2.2", | ||||
| 		"localforage": "1.9.0", | ||||
| 		"lodash.isequal": "^4.5.0", | ||||
| 		"svelte-filepond": "0.0.1", | ||||
| @@ -26,13 +25,13 @@ | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"@odit/license-exporter": "0.0.9", | ||||
| 		"@snowpack/plugin-svelte": "3.4.1", | ||||
| 		"@snowpack/plugin-svelte": "3.5.1", | ||||
| 		"auto-changelog": "^2.2.1", | ||||
| 		"autoprefixer": "10.2.1", | ||||
| 		"postcss": "8.2.4", | ||||
| 		"postcss-load-config": "3.0.0", | ||||
| 		"release-it": "^14.2.2", | ||||
| 		"snowpack": "3.0.0-rc.2", | ||||
| 		"snowpack": "3.0.10", | ||||
| 		"svelte": "3.31.2", | ||||
| 		"svelte-preprocess": "4.6.1", | ||||
| 		"workbox-cli": "6.0.2" | ||||
| @@ -51,7 +50,7 @@ | ||||
| 			"publish": false | ||||
| 		}, | ||||
| 		"hooks": { | ||||
| 			"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit  && git add CHANGELOG.md" | ||||
| 			"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,6 +13,7 @@ | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|   <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.3.0-RELEASE_INFO</span> | ||||
|   <noscript>You need to enable JavaScript to run this app.</noscript> | ||||
|   <script src="/env.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_' | ||||
| 	}, | ||||
| 	plugins: [ '@snowpack/plugin-svelte' ], | ||||
| 	install: [ | ||||
| 		/* ... */ | ||||
| 	routes: [ | ||||
| 		/* Enable an SPA Fallback in development: */ | ||||
| 		{ match: 'routes', src: '.*', dest: '/index.html' } | ||||
| 	], | ||||
| 	installOptions: { | ||||
| 	packageOptions: { | ||||
| 		/* ... */ | ||||
| 		sourceMap: false | ||||
| 	}, | ||||
| @@ -18,13 +19,8 @@ module.exports = { | ||||
| 	buildOptions: { | ||||
| 		/* ... */ | ||||
| 	}, | ||||
| 	proxy: { | ||||
| 		/* ... */ | ||||
| 	}, | ||||
| 	alias: { | ||||
| 		/* ... */ | ||||
| 	}, | ||||
| 	experiments: { | ||||
| 	optimize: { bundle: true, minify: true } | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <script> | ||||
|   import "./TailwindStyles.svelte"; | ||||
|   import "toastify-js/src/toastify.css"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   import { Route, router } from "tinro"; | ||||
|   router.subscribe((routeInfo) => { | ||||
|     window.scrollTo(0, 0); | ||||
|   | ||||
| @@ -50,14 +50,14 @@ | ||||
|             <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="none" | ||||
|                 width="24" | ||||
|                 height="24" | ||||
|                 xmlns="http://www.w3.org/2000/svg" | ||||
|                 viewBox="0 0 640 512"><path | ||||
|                 fill="currentColor" | ||||
|                   d="M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z" /></svg> | ||||
|                 class="h-6 w-6 text-blue-600" | ||||
|                 xmlns="http://www.w3.org/2000/svg" | ||||
|                 viewBox="0 0 24 24" | ||||
|                 width="24" | ||||
|                 height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||
|                 <path | ||||
|                   d="M14 20v2H2v-2h12zM14.586.686l7.778 7.778L20.95 9.88l-1.06-.354L17.413 12l5.657 5.657-1.414 1.414L16 13.414l-2.404 2.404.283 1.132-1.415 1.414-7.778-7.778 1.415-1.414 1.13.282 6.294-6.293-.353-1.06L14.586.686z" /></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"> | ||||
| @@ -79,7 +79,7 @@ | ||||
|             }} | ||||
|             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"> | ||||
|             Close | ||||
|             {$_('close')} | ||||
|           </button> | ||||
|         </div> | ||||
|       </div> | ||||
| @@ -112,13 +112,12 @@ | ||||
|     <h2 class="text-4xl font-display font-semibold md:text-5xl"> | ||||
|       {$_('credits')} | ||||
|     </h2> | ||||
|     <div | ||||
|       class="max-w-3xl mx-auto text-xl leading-8 font-medium mt-8"> | ||||
|     <div class="max-w-3xl mx-auto text-xl leading-8 font-medium mt-8"> | ||||
|       <p class="text-center">{$_('oss_credit_description')}</p> | ||||
|     </div> | ||||
|     <div class="w-screen leading-8 pl-5 mt-5"> | ||||
|       {#await license_promise} | ||||
|         <p class="text-center w-full">Licenses are being loaded...</p> | ||||
|         <p class="text-center w-full">{$_('licenses-are-being-loaded')}</p> | ||||
|       {:then} | ||||
|         <table> | ||||
|           <thead> | ||||
| @@ -164,9 +163,7 @@ | ||||
|         </div> | ||||
|       {/await} | ||||
|     </div> | ||||
|     <h2 class="text-4xl font-display font-semibold md:text-5xl"> | ||||
|       Fragen | ||||
|     </h2> | ||||
|     <h2 class="text-4xl font-display font-semibold md:text-5xl">{$_('faq')}</h2> | ||||
|     <div class="mt-6 border-t-2 border-gray-100 pt-10"> | ||||
|       <dl class="md:grid md:grid-cols-2 md:gap-8"> | ||||
|         <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} | ||||
| @@ -2,20 +2,21 @@ | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import { clickOutside } from "./outsideclick"; | ||||
|   import { focusTrap } from "svelte-focus-trap"; | ||||
|   import { tracks as tracksstore } from "../store.js"; | ||||
|   import { UserService } from "@odit/lfk-client-js"; | ||||
|   import isEmail from "validator/es/lib/isEmail"; | ||||
|   import Toastify from "toastify-js"; | ||||
|   import "toastify-js/src/toastify.css"; | ||||
|   export let modal_open; | ||||
|   export let current_users; | ||||
|   let firstname_input; | ||||
|   let lastname_input; | ||||
|   let middlename_input; | ||||
|   let username_input; | ||||
|   let password_input; | ||||
|   let email_input; | ||||
|   function focus(el) { | ||||
|     el.focus(); | ||||
|   } | ||||
|   $: username_input_value = ""; | ||||
|   $: middlename_input_value = ""; | ||||
|   $: password_input_value = ""; | ||||
|   $: email_input_value = ""; | ||||
| @@ -49,17 +50,25 @@ | ||||
|         text: "User is being added...", | ||||
|         duration: -1, | ||||
|       }).showToast(); | ||||
|       UserService.userControllerPost({ | ||||
|       let postdata={ | ||||
|         firstname: firstname_input_value, | ||||
|         lastname: lastname_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) => { | ||||
|           firstname_input_value = ""; | ||||
|           lastname_input_value = ""; | ||||
|           middlename_input_value = ""; | ||||
|           email_input_value = ""; | ||||
|           username_input_value = ""; | ||||
|           modal_open = false; | ||||
|           // | ||||
|           Toastify({ | ||||
| @@ -67,12 +76,8 @@ | ||||
|             duration: 500, | ||||
|             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||
|           }).showToast(); | ||||
|           let storeval = []; | ||||
|           tracksstore.subscribe((val) => { | ||||
|             storeval = val; | ||||
|           }); | ||||
|           storeval.push(result); | ||||
|           tracksstore.set(storeval); | ||||
|           current_users.push(result); | ||||
|           current_users=current_users; | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           // | ||||
| @@ -213,6 +218,19 @@ | ||||
|                     </span> | ||||
|                   {/if} | ||||
|                 </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"> | ||||
|                   <label | ||||
|                     for="email" | ||||
|   | ||||
| @@ -24,19 +24,40 @@ | ||||
|       ) | ||||
|         check = true; | ||||
|     })(navigator.userAgent || navigator.vendor || window.opera); | ||||
|     const aspectratio=window.innerWidth/window.innerHeight; | ||||
|     if(aspectratio<=0.765){ | ||||
|       check=true; | ||||
|     } | ||||
|     return check; | ||||
|   } | ||||
|   $: mobile = ismobile(); | ||||
|   window.addEventListener('resize', function(){ | ||||
|     const aspectratio=window.innerWidth/window.innerHeight; | ||||
|     if(aspectratio<=0.765){ | ||||
|       navOpen=false; | ||||
|       mobile=true; | ||||
|     }else{ | ||||
|       navOpen=true; | ||||
|       mobile=false; | ||||
|  | ||||
|     } | ||||
|   }); | ||||
| //   $: if (mobile===true) { | ||||
| //     console.log("changed to mobile"); | ||||
| // } | ||||
| //   $: if (mobile===false) { | ||||
| //     console.log("changed to md"); | ||||
| // } | ||||
|   function logout() { | ||||
|     localForage.clear(); | ||||
|     location.replace("/"); | ||||
|   } | ||||
| </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 | ||||
|     class:hidden={!navOpen && mobile} | ||||
|     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="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"> | ||||
|       <img | ||||
|         src="/lfk-logo.png" | ||||
|   | ||||
| @@ -2,7 +2,6 @@ | ||||
|   import { _, json } from "svelte-i18n"; | ||||
|   import { getlang } from "./datatable_i18n"; | ||||
|   import { Grid } from "gridjs"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   // | ||||
|   let table; | ||||
|   const datatable = new Grid({ | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <script> | ||||
|   import "filepond/dist/filepond.css"; | ||||
|   import FilePond from "svelte-filepond"; | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   let pond; | ||||
|   // pond.getFiles() will return the active files | ||||
|   // the name to use for the internal file input | ||||
| @@ -11,12 +12,60 @@ | ||||
|   function handleAddFile(err, fileItem) { | ||||
|     // console.log("A file has been added", fileItem); | ||||
|   } | ||||
|   const labelInvalidField = $_("filepond__field-contains-invalid-files"); | ||||
|   const labelFileWaitingForSize = $_("filepond__waiting-for-size"); | ||||
|   const labelFileSizeNotAvailable = $_("filepond__size-not-available"); | ||||
|   const labelFileLoading = $_("filepond__loading"); | ||||
|   const labelFileLoadError = $_("filepond__error-during-load"); | ||||
|   const labelFileProcessing = $_("filepond__uploading"); | ||||
|   const labelFileProcessingComplete = $_("filepond__upload-complete"); | ||||
|   const labelFileProcessingAborted = $_("filepond__upload-cancelled"); | ||||
|   const labelFileProcessingError = $_("filepond__error-during-upload"); | ||||
|   const labelFileProcessingRevertError = $_("filepond__error-during-revert"); | ||||
|   const labelFileRemoveError = $_("filepond__error-during-remove"); | ||||
|   const labelTapToCancel = $_("filepond__tap-to-cancel"); | ||||
|   const labelTapToRetry = $_("filepond__tap-to-retry"); | ||||
|   const labelTapToUndo = $_("filepond__tap-to-undo"); | ||||
|   const labelButtonRemoveItem = $_("filepond__remove"); | ||||
|   const labelButtonAbortItemLoad = $_("filepond__abort"); | ||||
|   const labelButtonRetryItemLoad = $_("filepond__retry"); | ||||
|   const labelButtonAbortItemProcessing = $_("filepond__cancel"); | ||||
|   const labelButtonUndoItemProcessing = $_("filepond__undo"); | ||||
|   const labelButtonRetryItemProcessing = $_("filepond__retry"); | ||||
|   const labelButtonProcessItem = $_("filepond__upload"); | ||||
|   const labelIdle = | ||||
|     $_("drag-and-drop-your-files-or") + | ||||
|     ` <span class="filepond--label-action"> ` + | ||||
|     $_("browse") + | ||||
|     ` </span>`; | ||||
| </script> | ||||
|  | ||||
| <div class="app"> | ||||
|   <FilePond | ||||
|     bind:this={pond} | ||||
|     {name} | ||||
|     {labelFileWaitingForSize} | ||||
|     {labelFileSizeNotAvailable} | ||||
|     {labelFileLoading} | ||||
|     {labelFileLoadError} | ||||
|     {labelFileProcessing} | ||||
|     {labelFileProcessingComplete} | ||||
|     {labelFileProcessingAborted} | ||||
|     {labelFileProcessingError} | ||||
|     {labelFileProcessingRevertError} | ||||
|     {labelFileRemoveError} | ||||
|     {labelTapToCancel} | ||||
|     {labelTapToRetry} | ||||
|     {labelTapToUndo} | ||||
|     {labelButtonRemoveItem} | ||||
|     {labelButtonAbortItemLoad} | ||||
|     {labelButtonRetryItemLoad} | ||||
|     {labelButtonAbortItemProcessing} | ||||
|     {labelButtonUndoItemProcessing} | ||||
|     {labelButtonRetryItemProcessing} | ||||
|     {labelButtonProcessItem} | ||||
|     {labelIdle} | ||||
|     {labelInvalidField} | ||||
|     server="/api" | ||||
|     allowMultiple={false} | ||||
|     credits={false} | ||||
|   | ||||
| @@ -1,15 +1,35 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   $: releaseinfo = ""; | ||||
|   setTimeout(() => { | ||||
|     releaseinfo = document | ||||
|       .getElementById("buildinfo") | ||||
|       .textContent.replace("RELEASE_INFO-", "") | ||||
|       .replace("-RELEASE_INFO", ""); | ||||
|   }, 1500); | ||||
|   const year = new Date().getFullYear(); | ||||
| </script> | ||||
|  | ||||
| <footer class="container"> | ||||
|   <hr class="mt-2 mb-4 border-b-1 border-gray-300" /> | ||||
| <footer class="p-5 w-full"> | ||||
|   <p class="text-sm text-gray-500 mt-4"> | ||||
|     Lauf für Kaya! Läufersystem - Copyright © 2020 + proudly powered by | ||||
|     Lauf für Kaya! Läufersystem - Copyright © | ||||
|     {year} | ||||
|     + proudly powered by | ||||
|     <a | ||||
|       class="underline" | ||||
|       href="https://odit.services" | ||||
|       rel="noopener,noreferrer" | ||||
|       target="_blank">ODIT.Services</a> | ||||
|   </p> | ||||
|   <p class="text-sm text-gray-500 mt-4"> | ||||
|     <a | ||||
|       class="underline" | ||||
|       target="_blank" | ||||
|       rel="noopener, noreferrer" | ||||
|       href="https://git.odit.services/lfk/frontend/">LfK!Frontend</a>@<a | ||||
|       class="underline" | ||||
|       target="_blank" | ||||
|       rel="noopener, noreferrer" | ||||
|       href="https://git.odit.services/lfk/frontend/src/tag/{releaseinfo}">{releaseinfo}</a> | ||||
|   </p> | ||||
| </footer> | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   store.init(); | ||||
|   import { OpenAPI, AuthService } from "@odit/lfk-client-js"; | ||||
|   import Footer from "./Footer.svelte"; | ||||
|   import Toastify from "toastify-js"; | ||||
|   // ------ | ||||
|   let username = "demo"; | ||||
| @@ -140,3 +141,4 @@ | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| <Footer /> | ||||
|   | ||||
| @@ -1,14 +1,95 @@ | ||||
| <script> | ||||
|   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import Toastify from "toastify-js"; | ||||
|   import store from "../store"; | ||||
|   import PromiseError from "./PromiseError.svelte"; | ||||
|   $: delete_triggered = false; | ||||
|   $: save_enabled = !data_changed; | ||||
|   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); | ||||
|   }); | ||||
|   function deleteOrganisation() { | ||||
|     RunnerOrganisationService.runnerOrganisationControllerRemove( | ||||
|       original.id, | ||||
|       true | ||||
|     ) | ||||
|       .then((resp) => { | ||||
|         location.replace("./"); | ||||
|       }) | ||||
|       .catch((err) => {}); | ||||
|   } | ||||
|   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> | ||||
|  | ||||
| {#if data_loaded} | ||||
|   <section class="container p-5"> | ||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||
|     Orgs | ||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||
|       {original.name} | ||||
|       <span data-id="org_actions_${orgdata.id}"> | ||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||
|           {#if delete_triggered} | ||||
|             <button | ||||
|               on:click={deleteOrganisation} | ||||
|               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-organization')}</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> | ||||
|   <p class="mb-8 text-lg text-gray-500"> | ||||
|     configure the tracks & minimum lap times | ||||
|   </p> | ||||
|     </div> | ||||
|     <div class="flex flex-row mb-4"> | ||||
|       <div class="w-full"> | ||||
|         <nav class="w-full flex"> | ||||
| @@ -80,4 +161,45 @@ | ||||
|         </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} | ||||
|   | ||||
							
								
								
									
										157
									
								
								src/components/OrgOverview.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/components/OrgOverview.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import { RunnerOrganisationService } from "@odit/lfk-client-js"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   import store from "../store"; | ||||
|   import OrgsEmptyState from "./OrgsEmptyState.svelte"; | ||||
|   $: searchvalue = ""; | ||||
|   $: active_deletes = []; | ||||
|   export let current_organizations = []; | ||||
|  | ||||
|   const promise = RunnerOrganisationService.runnerOrganisationControllerGetAll().then( | ||||
|     (val) => { | ||||
|       current_organizations = val; | ||||
|     } | ||||
|   ); | ||||
| </script> | ||||
|  | ||||
| {#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, true) | ||||
|                             .then((resp) => { | ||||
|                               current_organizations = current_organizations.filter((obj) => obj.id !== o.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} | ||||
|                     <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> | ||||
|   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> | ||||
|  | ||||
| <section class="container p-5"> | ||||
|   <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> | ||||
|   <p class="mb-8 text-lg text-gray-500"> | ||||
|     add, delete, edit organizations | ||||
|   </p> | ||||
|   <nav><a class="underline" href="./1">Org 1</a></nav> | ||||
|   <p class="mb-8 text-lg text-gray-500">manage runner organizations</p> | ||||
|   <OrgOverview bind:current_organizations /> | ||||
| </section> | ||||
|  | ||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:CREATE')} | ||||
|   <AddOrgModal bind:current_organizations bind:modal_open /> | ||||
| {/if} | ||||
|   | ||||
							
								
								
									
										15
									
								
								src/components/OrgsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/components/OrgsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import AddOrgModal from "./AddOrgModal.svelte"; | ||||
|   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"> | ||||
|     <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 /> | ||||
| @@ -6,7 +6,6 @@ | ||||
|   const tracks_promise = TrackService.trackControllerGetAll(); | ||||
|   import { getlang } from "./datatable_i18n"; | ||||
|   import { Grid, html } from "gridjs"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   import { tracks as tracksstore } from "../store.js"; | ||||
|   $: trackscache = []; | ||||
|   $: blocked = []; | ||||
|   | ||||
| @@ -1,27 +1,91 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import lodashIsEqual from "lodash.isequal"; | ||||
|   import { UserService } from "@odit/lfk-client-js"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   import store from "../store"; | ||||
|   import { | ||||
|     UserService, | ||||
|     UserGroupService, | ||||
|     PermissionService, | ||||
|   } from "@odit/lfk-client-js"; | ||||
|   import Toastify from "toastify-js"; | ||||
|   import PromiseError from "./PromiseError.svelte"; | ||||
|   export let params; | ||||
|   const user_promise = UserService.userControllerGetOne(params.userid); | ||||
|   let data_loaded = false; | ||||
|   let original_data = undefined; | ||||
|   $: editable_userdata = undefined; | ||||
|   $: delete_triggered = false; | ||||
|   $: original_data = {}; | ||||
|   $: editable_userdata = {}; | ||||
|   $: allpermissions = []; | ||||
|   $: allgroups = []; | ||||
|   $: allgroups_ids = []; | ||||
|   $: usergroups_array_objects = []; | ||||
|   $: usergroups_array = []; | ||||
|   let usergroups_array_original = []; | ||||
|   user_promise.then((data) => { | ||||
|     data_loaded = true; | ||||
|     original_data = data; | ||||
|     original_data = Object.assign(original_data, data); | ||||
|     editable_userdata = data; | ||||
|     data.groups.forEach((g) => { | ||||
|       usergroups_array=usergroups_array.concat([g.id]); | ||||
|     }); | ||||
|   // $: changes_performed = lodashIsEqual(original_data, editable_userdata); | ||||
|   $: changes_performed = !lodashIsEqual({ test: 1 }, { test: 1 }); | ||||
|     usergroups_array_original = usergroups_array; | ||||
|     allgroups.forEach((g) => { | ||||
|       allgroups_ids.push(g.id); | ||||
|     }); | ||||
|   }); | ||||
|   UserGroupService.userGroupControllerGetAll().then((data) => { | ||||
|     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() { | ||||
|     if (data_loaded === true && changes_performed === true) { | ||||
|       console.log("ok, submitting..."); | ||||
|     } else { | ||||
|       console.log("no changes performed"); | ||||
|     if ( | ||||
|       !lodashIsEqual(original_data.permissions, editable_userdata.permissions) | ||||
|     ) { | ||||
|       // 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> | ||||
|  | ||||
| @@ -63,51 +127,54 @@ | ||||
|                 <polyline points="12 5 19 12 12 19" /></svg> | ||||
|             </li> | ||||
|             <li class="flex items-center"> | ||||
|               <span class="mr-2">{user.firstname} | ||||
|                 {user.middlename || ''} | ||||
|                 {user.lastname}</span> | ||||
|               <span class="mr-2">{original_data.firstname} | ||||
|                 {original_data.middlename || ''} | ||||
|                 {original_data.lastname}</span> | ||||
|             </li> | ||||
|           </ol> | ||||
|         </nav> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||
|       {user.firstname} | ||||
|       {user.middlename || ''} | ||||
|       {user.lastname} | ||||
|       <span data-id="user_actions_${user.id}"> | ||||
|       {original_data.firstname} | ||||
|       {original_data.middlename || ''} | ||||
|       {original_data.lastname} | ||||
|       <span data-id="user_actions_${editable_userdata.id}"> | ||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||
|           {#if delete_triggered} | ||||
|             <button | ||||
|           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" | ||||
|           data-userid="${user.id}" | ||||
|           onclick="user__delete_cancel()">{$_('cancel')}</button> | ||||
|               on:click={deleteUser} | ||||
|               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 | ||||
|           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" | ||||
|           data-userid="${user.id}" | ||||
|           onclick="user__delete_confirm()">{$_('confirm-delete')}</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-user')}</button> | ||||
|           {/if} | ||||
|         {/if} | ||||
|         {#if !delete_triggered} | ||||
|           <button | ||||
|           disabled={!changes_performed} | ||||
|           class:opacity-50={!changes_performed} | ||||
|             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> | ||||
|     </div> | ||||
|  | ||||
|     <!--  --> | ||||
|     <div class="mt-2 flex items-center"> | ||||
|       <img | ||||
|         alt={$_('profile-picture')} | ||||
|         class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100" | ||||
|         src={user.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> --> | ||||
|         src={editable_userdata.profilePic} /> | ||||
|       <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> | ||||
| @@ -165,6 +232,102 @@ | ||||
|         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" /> | ||||
|     </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> | ||||
| {:catch error} | ||||
|   <PromiseError {error} /> | ||||
|   | ||||
| @@ -1,13 +1,17 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import store from "../store"; | ||||
|   import AddUserModal from "./AddUserModal.svelte"; | ||||
|   export let modal_open = false; | ||||
|   import UsersOverview from "./UsersOverview.svelte"; | ||||
|   console.log(store.state.jwtinfo.userdetails.permissions); | ||||
|   let current_users=[]; | ||||
| </script> | ||||
|  | ||||
| <section class="container p-5"> | ||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||
|     {$_('users')} | ||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||
|       <button | ||||
|         on:click={() => { | ||||
|           modal_open = true; | ||||
| @@ -16,8 +20,12 @@ | ||||
|         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-user')} | ||||
|       </button> | ||||
|     {/if} | ||||
|   </span> | ||||
|   <p class="mb-8 text-lg text-gray-500">{$_('manage-admin-users')}</p> | ||||
|   <UsersOverview /> | ||||
|   <UsersOverview bind:current_users /> | ||||
| </section> | ||||
| <AddUserModal bind:modal_open /> | ||||
|  | ||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | ||||
|   <AddUserModal bind:current_users bind:modal_open /> | ||||
| {/if} | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import Toastify from "toastify-js"; | ||||
|   import { UserService } from "@odit/lfk-client-js"; | ||||
|   const users_promise = UserService.userControllerGetAll(); | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   import { users as usersstore } from "../store.js"; | ||||
|   import store from "../store"; | ||||
|   import UsersEmptyState from "./UsersEmptyState.svelte"; | ||||
|   $: searchvalue = ""; | ||||
|   $: userscache = []; | ||||
|   $: active_deletes = []; | ||||
|   export let current_users=[]; | ||||
|   $: advanced_search = false; | ||||
|   usersstore.subscribe((val) => { | ||||
|     userscache = val; | ||||
|     current_users=val; | ||||
|   }); | ||||
|   users_promise.then((data) => { | ||||
|     console.log(data); | ||||
|     usersstore.set(data); | ||||
|   }); | ||||
| </script> | ||||
|  | ||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')} | ||||
|   {#await users_promise} | ||||
|     <div | ||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||
| @@ -25,8 +26,8 @@ | ||||
|       <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} | ||||
|   {:then} | ||||
|     {#if current_users.length === 0} | ||||
|       <UsersEmptyState /> | ||||
|     {:else} | ||||
|       {#if advanced_search} | ||||
| @@ -75,12 +76,12 @@ | ||||
|             </tr> | ||||
|           </thead> | ||||
|           <tbody class="divide-y divide-gray-200"> | ||||
|           {#each users as u} | ||||
|             {#each current_users as u} | ||||
|               {#if Object.values(u) | ||||
|                 .toString() | ||||
|                 .toLowerCase() | ||||
|                 .includes(searchvalue)} | ||||
|               <tr> | ||||
|                 <tr data-rowid="user_{u.id}"> | ||||
|                   <td class="px-6 py-4 whitespace-nowrap"> | ||||
|                     <div class="flex items-center"> | ||||
|                       {#if u.profilePic} | ||||
| @@ -120,16 +121,46 @@ | ||||
|                         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} | ||||
|                     <td | ||||
|                       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> | ||||
|                   <span | ||||
|                       {#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} | ||||
|                         <button | ||||
|                           on:click={() => { | ||||
|                             active_deletes[u.id] = true; | ||||
|                           }} | ||||
|                           tabindex="0" | ||||
|                     href="#" | ||||
|                     class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</span> | ||||
|                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button> | ||||
|                       {/if} | ||||
|                     </td> | ||||
|                   {/if} | ||||
|                 </tr> | ||||
|               {/if} | ||||
|             {/each} | ||||
| @@ -145,3 +176,4 @@ | ||||
|       </span> | ||||
|     </div> | ||||
|   {/await} | ||||
| {/if} | ||||
|   | ||||
| @@ -4,17 +4,22 @@ | ||||
|     "about": "About", | ||||
|     "action": "Action", | ||||
|     "add-your-first-track": "Add your first track", | ||||
|     "address": "Address", | ||||
|     "application_name": "Lauf für Kaya! - Admin", | ||||
|     "author": "Author", | ||||
|     "browse": "Browse", | ||||
|     "by": "by", | ||||
|     "cancel": "Cancel", | ||||
|     "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", | ||||
|     "changelog": "Changelog", | ||||
|     "close": "Close", | ||||
|     "confirm-delete": "Confirm Delete", | ||||
|     "contact": "Contact", | ||||
|     "count_organizations": "# Organizations", | ||||
|     "count_teams": "# Teams", | ||||
|     "create": "Create", | ||||
|     "create-a-new-track": "Create a new Track", | ||||
|     "create-organization": "Create Organization", | ||||
|     "create-user": "Create User", | ||||
|     "credits": "Credits", | ||||
|     "dashboard-greeting": "hello there", | ||||
| @@ -34,20 +39,43 @@ | ||||
|         "no_matching_records_found": "No matching records found", | ||||
|         "an_error_happened_while_fetching_the_data": "An error happened while fetching the data" | ||||
|     }, | ||||
|     "delete-organization": "Delete Organization", | ||||
|     "delete-user": "Delete User", | ||||
|     "dependency_name": "Name", | ||||
|     "dont-have-your-email-connected": "Don't have your email connected?", | ||||
|     "dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌", | ||||
|     "drag-and-drop-your-files-or": "Drag & Drop your files or", | ||||
|     "e-mail-adress": "E-Mail Adress", | ||||
|     "email_address_or_username": "Email / username", | ||||
|     "error_on_login": "Error on login", | ||||
|     "faq": "FAQ", | ||||
|     "filepond__abort": "Abort", | ||||
|     "filepond__cancel": "Cancel", | ||||
|     "filepond__error-during-load": "Error during load", | ||||
|     "filepond__error-during-remove": "Error during remove", | ||||
|     "filepond__error-during-revert": "Error during revert", | ||||
|     "filepond__error-during-upload": "Error during upload", | ||||
|     "filepond__field-contains-invalid-files": "Field contains invalid files", | ||||
|     "filepond__loading": "Loading", | ||||
|     "filepond__remove": "Remove", | ||||
|     "filepond__retry": "Retry", | ||||
|     "filepond__size-not-available": "Size not available", | ||||
|     "filepond__tap-to-cancel": "tap to cancel", | ||||
|     "filepond__tap-to-retry": "tap to retry", | ||||
|     "filepond__tap-to-undo": "tap to undo", | ||||
|     "filepond__undo": "Undo", | ||||
|     "filepond__upload": "Upload", | ||||
|     "filepond__upload-cancelled": "Upload cancelled", | ||||
|     "filepond__upload-complete": "Upload complete", | ||||
|     "filepond__uploading": "Uploading", | ||||
|     "filepond__waiting-for-size": "Waiting for size", | ||||
|     "first-name": "First name", | ||||
|     "first-name-is-required": "First Name is required", | ||||
|     "forgot_password?": "Forgot your password?", | ||||
|     "general-stats": "General Stats", | ||||
|     "general_promise_error": "😢 Error", | ||||
|     "goback": "Go Home", | ||||
|     "groups": "Groups", | ||||
|     "hallo": "hello", | ||||
|     "installed-version": "Installed version", | ||||
|     "invalid-mail-reset": "the provided email is invalid", | ||||
| @@ -55,6 +83,7 @@ | ||||
|     "last-name-is-required": "Last Name is required", | ||||
|     "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", | ||||
|     "license": "License", | ||||
|     "licenses-are-being-loaded": "Licenses are being loaded...", | ||||
|     "log_in": "Log in", | ||||
|     "log_in_to_your_account": "Log in to your account", | ||||
|     "login_is_checked": "Login is being checked...", | ||||
| @@ -65,6 +94,7 @@ | ||||
|     "minimum-lap-time-in-s": "minimum lap time in s", | ||||
|     "no-license-text-could-be-found": "No license text could be found 😢", | ||||
|     "no-tracks-added-yet": "there are no tracks added yet.", | ||||
|     "organizations": "Organizations", | ||||
|     "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!", | ||||
|     "password": "Password", | ||||
| @@ -92,6 +122,9 @@ | ||||
|     "track-length-in-m": "Track Length in m", | ||||
|     "track-name": "Track name", | ||||
|     "tracks": "Tracks", | ||||
|     "updating-user": "updating user...", | ||||
|     "user-updated": "User updated", | ||||
|     "username": "Username", | ||||
|     "users": "Users", | ||||
|     "valid-email-is-required": "valid email is required", | ||||
|     "welcome_wavinghand": "Welcome 👋", | ||||
|   | ||||
| @@ -27,6 +27,8 @@ const store = () => { | ||||
| 			AuthService.authControllerRefresh({ token: state.auth.refresh_token }).then((auth) => { | ||||
| 				console.log('got new auth'); | ||||
| 				OpenAPI.TOKEN = auth.access_token; | ||||
| 				const jwtinfo = JSON.parse(atob(auth.access_token.split('.')[1])); | ||||
| 				state.jwtinfo = jwtinfo; | ||||
| 				localForage.setItem('logindata', auth); | ||||
| 			}); | ||||
| 		}, | ||||
| @@ -39,8 +41,8 @@ const store = () => { | ||||
| 				// | ||||
| 				state.refreshInterval = setInterval(() => { | ||||
| 					this.refreshAuth(); | ||||
| 					// 4min | ||||
| 				}, 4 * 60000); | ||||
| 					// 2min | ||||
| 				}, 2 * 60000); | ||||
| 				// | ||||
| 				return state; | ||||
| 			}); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ module.exports = { | ||||
| 	purge: { | ||||
| 		content: [ './src/**/*.svelte' ] | ||||
| 	}, | ||||
| 	darkMode: 'media', | ||||
| 	// darkMode: 'media', | ||||
| 	variants: {}, | ||||
| 	plugins: [], | ||||
| 	theme: { | ||||
|   | ||||
							
								
								
									
										5
									
								
								versionbuilder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								versionbuilder.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| const fs = require('fs'); | ||||
| const package = JSON.parse(fs.readFileSync(`./package.json`, { encoding: 'utf-8' })); | ||||
| const original = fs.readFileSync(`./public/index.html`, { encoding: 'utf-8' }); | ||||
| let out = original.replace(/RELEASE_INFO-(\S)+-RELEASE_INFO/gi, 'RELEASE_INFO-' + package.version + '-RELEASE_INFO'); | ||||
| fs.writeFileSync(`./public/index.html`, out); | ||||
		Reference in New Issue
	
	Block a user