Compare commits
	
		
			29 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2bbaa500f4 | |||
| 722a20e141 | |||
| 041c24a837 | |||
| 39a3baa00b | |||
| f7acbb1eaa | |||
| e6fbf7aa5b | |||
| 36a084eab6 | |||
| a9e319e0c0 | |||
| ea23b97231 | |||
| 7df76f9642 | |||
| f6db117a5e | |||
| 23c3cd605d | |||
| 77690702c0 | |||
| e0093480d9 | |||
| c7679b7a67 | |||
| e6ac34bde8 | |||
| 8c4b595c30 | |||
| be629e5c6b | |||
| 63569684a3 | |||
| 5937a0d7ce | |||
| 4512272c1c | |||
| ce1f3842e0 | |||
| ee01c3a059 | |||
| 81c1537bad | |||
| 98ecfab032 | |||
| b948b8c1a4 | |||
| f856c6ae37 | |||
| 2dd2580530 | |||
| f0c100aee4 | 
							
								
								
									
										41
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,9 +2,50 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||
|  | ||||
| #### [0.2.1](https://git.odit.services/lfk/frontend/compare/0.2.0...0.2.1) | ||||
|  | ||||
| - 🔒 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) | ||||
| - 💬 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) | ||||
|   | ||||
| @@ -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"; | ||||
|   | ||||
| @@ -1,17 +1,16 @@ | ||||
| { | ||||
| 	"name": "@odit/lfk-frontend", | ||||
| 	"version": "0.1.5", | ||||
| 	"version": "0.2.1", | ||||
| 	"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.11", | ||||
| 		"filepond": "4.25.1", | ||||
| 		"gridjs": "3.2.1", | ||||
| 		"localforage": "1.9.0", | ||||
| @@ -51,7 +50,7 @@ | ||||
| 			"publish": false | ||||
| 		}, | ||||
| 		"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> | ||||
|  | ||||
| <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.2.1-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> | ||||
|   | ||||
| @@ -49,7 +49,7 @@ | ||||
|   OpenAPI.BASE = config.baseurl; | ||||
|   import { register as registerSW } from "./swmodule"; | ||||
|   store.init(); | ||||
|   // registerSW(); | ||||
|   registerSW(); | ||||
| </script> | ||||
|  | ||||
| <Route> | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -1,9 +1,12 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   const releaseinfo = document | ||||
|   $: releaseinfo = ""; | ||||
|   setTimeout(() => { | ||||
|     releaseinfo = document | ||||
|       .getElementById("buildinfo") | ||||
|       .textContent.replace("RELEASE_INFO-", "") | ||||
|       .replace("-RELEASE_INFO", ""); | ||||
|   }, 1500); | ||||
|   const year = new Date().getFullYear(); | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -1,27 +1,92 @@ | ||||
| <script> | ||||
|   import { _ } from "svelte-i18n"; | ||||
|   import lodashIsEqual from "lodash.isequal"; | ||||
|   import { UserService } from "@odit/lfk-client-js"; | ||||
|   import store from "../store"; | ||||
|   import { | ||||
|     UserService, | ||||
|     UserGroupService, | ||||
|     PermissionService, | ||||
|   } from "@odit/lfk-client-js"; | ||||
|   import "gridjs/dist/theme/mermaid.css"; | ||||
|   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 +128,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 +233,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} | ||||
|   | ||||
| @@ -5,28 +5,32 @@ | ||||
|   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 = ""; | ||||
|   $: active_deletes = []; | ||||
|   export let current_users=[]; | ||||
|   $: userscache = []; | ||||
|   $: advanced_search = false; | ||||
|   usersstore.subscribe((val) => { | ||||
|     userscache = val; | ||||
|     current_users=val; | ||||
|   }); | ||||
|   users_promise.then((data) => { | ||||
|     console.log(data); | ||||
|     usersstore.set(data); | ||||
|   }); | ||||
| </script> | ||||
|  | ||||
| {#await users_promise} | ||||
| {#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" | ||||
|       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} | ||||
|   {:then} | ||||
|     {#if current_users.length === 0} | ||||
|       <UsersEmptyState /> | ||||
|     {:else} | ||||
|       {#if advanced_search} | ||||
| @@ -75,12 +79,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 +124,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} | ||||
| @@ -137,11 +171,12 @@ | ||||
|         </table> | ||||
|       </div> | ||||
|     {/if} | ||||
| {:catch error} | ||||
|   {: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} | ||||
|   {/await} | ||||
| {/if} | ||||
|   | ||||
| @@ -71,6 +71,7 @@ | ||||
|     "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", | ||||
| @@ -116,6 +117,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: { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user