Compare commits
13
Commits
0.1.6
..
87926e69db
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87926e69db | ||
|
|
f6db117a5e | ||
|
|
23c3cd605d | ||
|
|
77690702c0 | ||
|
|
e0093480d9 | ||
|
|
c7679b7a67 | ||
|
|
e6ac34bde8 | ||
|
|
8c4b595c30 | ||
|
|
be629e5c6b | ||
|
|
63569684a3 | ||
|
|
5937a0d7ce | ||
|
|
4512272c1c | ||
|
|
ce1f3842e0 |
No files matched your search
@@ -2,10 +2,23 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||
|
||||
#### [0.2.0](https://git.odit.services/lfk/frontend/compare/0.1.6...0.2.0)
|
||||
|
||||
- 🔒 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)
|
||||
- [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)
|
||||
|
||||
+1
-1
@@ -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";
|
||||
|
||||
+3
-4
@@ -1,17 +1,16 @@
|
||||
{
|
||||
"name": "@odit/lfk-frontend",
|
||||
"version": "0.1.6",
|
||||
"version": "0.2.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.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 public/locales"
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.1.6-RELEASE_INFO</span>
|
||||
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.2.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>
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"author":"ODIT.Services","repo":{"type":"git","url":"git+https://git.odit.services/lfk/lfk-client-js"},"description":"A lib to interact with https://git.odit.services/lfk/backend. Use this version for native JS applications.","name":"@odit/lfk-client-js","license":"CC-BY-NC-SA-4.0","version":"0.0.10","licensetext":"Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Creative\r\nCommons Corporation (\"Creative Commons\") is not a law firm and does not provide\r\nlegal services or legal advice. Distribution of Creative Commons public licenses\r\ndoes not create a lawyer-client or other relationship. Creative Commons makes\r\nits licenses and related information available on an \"as-is\" basis. Creative\r\nCommons gives no warranties regarding its licenses, any material licensed\r\nunder their terms and conditions, or any related information. Creative Commons\r\ndisclaims all liability for damages resulting from their use to the fullest\r\nextent possible.\r\n\r\nUsing Creative Commons Public Licenses\r\n\r\nCreative Commons public licenses provide a standard set of terms and conditions\r\nthat creators and other rights holders may use to share original works of\r\nauthorship and other material subject to copyright and certain other rights\r\nspecified in the public license below. The following considerations are for\r\ninformational purposes only, are not exhaustive, and do not form part of our\r\nlicenses.\r\n\r\nConsiderations for licensors: Our public licenses are intended for use by\r\nthose authorized to give the public permission to use material in ways otherwise\r\nrestricted by copyright and certain other rights. Our licenses are irrevocable.\r\nLicensors should read and understand the terms and conditions of the license\r\nthey choose before applying it. Licensors should also secure all rights necessary\r\nbefore applying our licenses so that the public can reuse the material as\r\nexpected. Licensors should clearly mark any material not subject to the license.\r\nThis includes other CC-licensed material, or material used under an exception\r\nor limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors\r\n\r\nConsiderations for the public: By using one of our public licenses, a licensor\r\ngrants the public permission to use the licensed material under specified\r\nterms and conditions. If the licensor's permission is not necessary for any\r\nreason–for example, because of any applicable exception or limitation to copyright–then\r\nthat use is not regulated by the license. Our licenses grant only permissions\r\nunder copyright and certain other rights that a licensor has authority to\r\ngrant. Use of the licensed material may still be restricted for other reasons,\r\nincluding because others have copyright or other rights in the material. A\r\nlicensor may make special requests, such as asking that all changes be marked\r\nor described. Although not required by our licenses, you are encouraged to\r\nrespect those requests where reasonable. More considerations for the public\r\n: wiki.creativecommons.org/Considerations_for_licensees\r\n\r\nCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public\r\nLicense\r\n\r\nBy exercising the Licensed Rights (defined below), You accept and agree to\r\nbe bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike\r\n4.0 International Public License (\"Public License\"). To the extent this Public\r\nLicense may be interpreted as a contract, You are granted the Licensed Rights\r\nin consideration of Your acceptance of these terms and conditions, and the\r\nLicensor grants You such rights in consideration of benefits the Licensor\r\nreceives from making the Licensed Material available under these terms and\r\nconditions.\r\n\r\nSection 1 – Definitions.\r\n\r\na. Adapted Material means material subject to Copyright and Similar Rights\r\nthat is derived from or based upon the Licensed Material and in which the\r\nLicensed Material is translated, altered, arranged, transformed, or otherwise\r\nmodified in a manner requiring permission under the Copyright and Similar\r\nRights held by the Licensor. For purposes of this Public License, where the\r\nLicensed Material is a musical work, performance, or sound recording, Adapted\r\nMaterial is always produced where the Licensed Material is synched in timed\r\nrelation with a moving image.\r\n\r\nb. Adapter's License means the license You apply to Your Copyright and Similar\r\nRights in Your contributions to Adapted Material in accordance with the terms\r\nand conditions of this Public License.\r\n\r\nc. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses,\r\napproved by Creative Commons as essentially the equivalent of this Public\r\nLicense.\r\n\r\nd. Copyright and Similar Rights means copyright and/or similar rights closely\r\nrelated to coLine truncated
|
||||
[{"author":"ODIT.Services","repo":{"type":"git","url":"git+https://git.odit.services/lfk/lfk-client-js"},"description":"A lib to interact with https://git.odit.services/lfk/backend. Use this version for native JS applications.","name":"@odit/lfk-client-js","license":"CC-BY-NC-SA-4.0","version":"0.0.11","licensetext":"Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Creative\r\nCommons Corporation (\"Creative Commons\") is not a law firm and does not provide\r\nlegal services or legal advice. Distribution of Creative Commons public licenses\r\ndoes not create a lawyer-client or other relationship. Creative Commons makes\r\nits licenses and related information available on an \"as-is\" basis. Creative\r\nCommons gives no warranties regarding its licenses, any material licensed\r\nunder their terms and conditions, or any related information. Creative Commons\r\ndisclaims all liability for damages resulting from their use to the fullest\r\nextent possible.\r\n\r\nUsing Creative Commons Public Licenses\r\n\r\nCreative Commons public licenses provide a standard set of terms and conditions\r\nthat creators and other rights holders may use to share original works of\r\nauthorship and other material subject to copyright and certain other rights\r\nspecified in the public license below. The following considerations are for\r\ninformational purposes only, are not exhaustive, and do not form part of our\r\nlicenses.\r\n\r\nConsiderations for licensors: Our public licenses are intended for use by\r\nthose authorized to give the public permission to use material in ways otherwise\r\nrestricted by copyright and certain other rights. Our licenses are irrevocable.\r\nLicensors should read and understand the terms and conditions of the license\r\nthey choose before applying it. Licensors should also secure all rights necessary\r\nbefore applying our licenses so that the public can reuse the material as\r\nexpected. Licensors should clearly mark any material not subject to the license.\r\nThis includes other CC-licensed material, or material used under an exception\r\nor limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors\r\n\r\nConsiderations for the public: By using one of our public licenses, a licensor\r\ngrants the public permission to use the licensed material under specified\r\nterms and conditions. If the licensor's permission is not necessary for any\r\nreason–for example, because of any applicable exception or limitation to copyright–then\r\nthat use is not regulated by the license. Our licenses grant only permissions\r\nunder copyright and certain other rights that a licensor has authority to\r\ngrant. Use of the licensed material may still be restricted for other reasons,\r\nincluding because others have copyright or other rights in the material. A\r\nlicensor may make special requests, such as asking that all changes be marked\r\nor described. Although not required by our licenses, you are encouraged to\r\nrespect those requests where reasonable. More considerations for the public\r\n: wiki.creativecommons.org/Considerations_for_licensees\r\n\r\nCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public\r\nLicense\r\n\r\nBy exercising the Licensed Rights (defined below), You accept and agree to\r\nbe bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike\r\n4.0 International Public License (\"Public License\"). To the extent this Public\r\nLicense may be interpreted as a contract, You are granted the Licensed Rights\r\nin consideration of Your acceptance of these terms and conditions, and the\r\nLicensor grants You such rights in consideration of benefits the Licensor\r\nreceives from making the Licensed Material available under these terms and\r\nconditions.\r\n\r\nSection 1 – Definitions.\r\n\r\na. Adapted Material means material subject to Copyright and Similar Rights\r\nthat is derived from or based upon the Licensed Material and in which the\r\nLicensed Material is translated, altered, arranged, transformed, or otherwise\r\nmodified in a manner requiring permission under the Copyright and Similar\r\nRights held by the Licensor. For purposes of this Public License, where the\r\nLicensed Material is a musical work, performance, or sound recording, Adapted\r\nMaterial is always produced where the Licensed Material is synched in timed\r\nrelation with a moving image.\r\n\r\nb. Adapter's License means the license You apply to Your Copyright and Similar\r\nRights in Your contributions to Adapted Material in accordance with the terms\r\nand conditions of this Public License.\r\n\r\nc. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses,\r\napproved by Creative Commons as essentially the equivalent of this Public\r\nLicense.\r\n\r\nd. Copyright and Similar Rights means copyright and/or similar rights closely\r\nrelated to coLine truncated
|
||||
+1
-1
@@ -49,7 +49,7 @@
|
||||
OpenAPI.BASE = config.baseurl;
|
||||
import { register as registerSW } from "./swmodule";
|
||||
store.init();
|
||||
// registerSW();
|
||||
registerSW();
|
||||
</script>
|
||||
|
||||
<Route>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "./outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
import { tracks as tracksstore } from "../store.js";
|
||||
import { tracks as usersstore } from "../store.js";
|
||||
import { UserService } from "@odit/lfk-client-js";
|
||||
import isEmail from "validator/es/lib/isEmail";
|
||||
import Toastify from "toastify-js";
|
||||
@@ -68,11 +68,11 @@
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
let storeval = [];
|
||||
tracksstore.subscribe((val) => {
|
||||
usersstore.subscribe((val) => {
|
||||
storeval = val;
|
||||
});
|
||||
storeval.push(result);
|
||||
tracksstore.set(storeval);
|
||||
usersstore.set(storeval);
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
const releaseinfo = document
|
||||
.getElementById("buildinfo")
|
||||
.textContent.replace("RELEASE_INFO-", "")
|
||||
.replace("-RELEASE_INFO", "");
|
||||
$: releaseinfo = "";
|
||||
setTimeout(() => {
|
||||
releaseinfo = document
|
||||
.getElementById("buildinfo")
|
||||
.textContent.replace("RELEASE_INFO-", "")
|
||||
.replace("-RELEASE_INFO", "");
|
||||
}, 1500);
|
||||
const year = new Date().getFullYear();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,28 +1,50 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import lodashIsEqual from "lodash.isequal";
|
||||
import store from "../store";
|
||||
import { UserService } from "@odit/lfk-client-js";
|
||||
import "gridjs/dist/theme/mermaid.css";
|
||||
import PromiseError from "./PromiseError.svelte";
|
||||
export let params;
|
||||
const user_promise = UserService.userControllerGetOne(params.userid);
|
||||
let data_loaded = false;
|
||||
let original_data = undefined;
|
||||
$: delete_triggered = false;
|
||||
$: original_data = {};
|
||||
$: editable_userdata = undefined;
|
||||
user_promise.then((data) => {
|
||||
data_loaded = true;
|
||||
original_data = data;
|
||||
original_data = Object.assign(original_data, data);
|
||||
editable_userdata = data;
|
||||
});
|
||||
// $: changes_performed = lodashIsEqual(original_data, editable_userdata);
|
||||
$: changes_performed = !lodashIsEqual({ test: 1 }, { test: 1 });
|
||||
$: changes_performed = !lodashIsEqual(original_data, editable_userdata);
|
||||
function submit() {
|
||||
if (data_loaded === true && changes_performed === true) {
|
||||
console.log("ok, submitting...");
|
||||
console.log(editable_userdata);
|
||||
UserService.userControllerPut(original_data.id, editable_userdata)
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
Object.assign(original_data, editable_userdata);
|
||||
original_data = editable_userdata;
|
||||
Object.assign(original_data, editable_userdata);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
console.log("no changes performed");
|
||||
}
|
||||
}
|
||||
function deleteUser() {
|
||||
UserService.userControllerRemove(original_data.id, true)
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
location.replace("./");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await user_promise}
|
||||
@@ -63,36 +85,47 @@
|
||||
<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}">
|
||||
<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>
|
||||
<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>
|
||||
<button
|
||||
type="button"
|
||||
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-user')}</button>
|
||||
<button
|
||||
disabled={!changes_performed}
|
||||
class:opacity-50={!changes_performed}
|
||||
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>
|
||||
{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
|
||||
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
|
||||
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}
|
||||
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>
|
||||
|
||||
@@ -101,7 +134,7 @@
|
||||
<img
|
||||
alt={$_('profile-picture')}
|
||||
class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100"
|
||||
src={user.profilePic} />
|
||||
src={editable_userdata.profilePic} />
|
||||
<!-- <span
|
||||
class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100"><svg
|
||||
class="h-full w-full text-gray-300"
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
<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);
|
||||
</script>
|
||||
|
||||
<section class="container p-5">
|
||||
<span class="mb-1 text-3xl font-extrabold leading-tight">
|
||||
{$_('users')}
|
||||
<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-user')}
|
||||
</button>
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
|
||||
<button
|
||||
on:click={() => {
|
||||
modal_open = true;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('create-user')}
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
<p class="mb-8 text-lg text-gray-500">{$_('manage-admin-users')}</p>
|
||||
<UsersOverview />
|
||||
</section>
|
||||
<AddUserModal bind:modal_open />
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
|
||||
<AddUserModal bind:modal_open />
|
||||
{/if}
|
||||
+160
-155
@@ -5,6 +5,7 @@
|
||||
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 = [];
|
||||
@@ -19,163 +20,167 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#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}
|
||||
<UsersEmptyState />
|
||||
{:else}
|
||||
{#if advanced_search}
|
||||
advanced search
|
||||
{:else}
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchvalue}
|
||||
placeholder={$_('datatable.search')}
|
||||
aria-label={$_('datatable.search')}
|
||||
class="gridjs-input gridjs-search-input mb-4" />
|
||||
{/if}
|
||||
<button
|
||||
on:click={() => {
|
||||
advanced_search = !advanced_search;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-600 text-base font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{#if advanced_search}
|
||||
toggle simple search
|
||||
{:else}toggle advanced search{/if}
|
||||
</button>
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')}
|
||||
{#await users_promise}
|
||||
<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">
|
||||
Status
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Groups
|
||||
</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 users as u}
|
||||
{#if Object.values(u)
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(searchvalue)}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
{#if u.profilePic}
|
||||
<div class="flex-shrink-0 h-10 w-10">
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
src={u.profilePic}
|
||||
alt="" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="ml-4">
|
||||
<div
|
||||
class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{u.firstname}
|
||||
{u.middlename || ''}
|
||||
{u.lastname}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500">
|
||||
{u.email || u.username}
|
||||
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
|
||||
role="alert">
|
||||
<p class="font-bold">users are being loaded...</p>
|
||||
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
|
||||
</div>
|
||||
{:then users}
|
||||
{#if userscache.length === 0}
|
||||
<UsersEmptyState />
|
||||
{:else}
|
||||
{#if advanced_search}
|
||||
advanced search
|
||||
{:else}
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchvalue}
|
||||
placeholder={$_('datatable.search')}
|
||||
aria-label={$_('datatable.search')}
|
||||
class="gridjs-input gridjs-search-input mb-4" />
|
||||
{/if}
|
||||
<button
|
||||
on:click={() => {
|
||||
advanced_search = !advanced_search;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-600 text-base font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{#if advanced_search}
|
||||
toggle simple search
|
||||
{:else}toggle advanced search{/if}
|
||||
</button>
|
||||
<div
|
||||
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">
|
||||
Status
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Groups
|
||||
</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 users as u}
|
||||
{#if Object.values(u)
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(searchvalue)}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
{#if u.profilePic}
|
||||
<div class="flex-shrink-0 h-10 w-10">
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
src={u.profilePic}
|
||||
alt="" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="ml-4">
|
||||
<div
|
||||
class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{u.firstname}
|
||||
{u.middlename || ''}
|
||||
{u.lastname}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500">
|
||||
{u.email || u.username}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{#if u.enabled}
|
||||
<span
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span>
|
||||
{:else}
|
||||
<span
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Inactive</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{#each u.groups as g}
|
||||
<a
|
||||
href="../groups/{g.id}"
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a>
|
||||
{/each}
|
||||
</td>
|
||||
{#if active_deletes[u.id] === true}
|
||||
<td
|
||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[u.id] = false;
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel
|
||||
Delete</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
UserService.userControllerRemove(u.id, true)
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
// user deleted
|
||||
users_promise.then((data) => {
|
||||
console.log(data);
|
||||
usersstore.set(data);
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{#if u.enabled}
|
||||
<span
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span>
|
||||
{:else}
|
||||
<span
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Inactive</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{#each u.groups as g}
|
||||
<a
|
||||
href="../groups/{g.id}"
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a>
|
||||
{/each}
|
||||
</td>
|
||||
{#if active_deletes[u.id] === true}
|
||||
<td
|
||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[u.id] = false;
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel
|
||||
Delete</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
UserService.userControllerRemove(u.id, true)
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
// user deleted
|
||||
users_promise.then((data) => {
|
||||
console.log(data);
|
||||
usersstore.set(data);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
// error deleting user
|
||||
});
|
||||
})
|
||||
.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>
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[u.id] = true;
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button>
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
}}
|
||||
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>
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')}
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[u.id] = true;
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</button>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
</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>
|
||||
{/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}
|
||||
{/await}
|
||||
{/if}
|
||||
+4
-2
@@ -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;
|
||||
});
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ module.exports = {
|
||||
purge: {
|
||||
content: [ './src/**/*.svelte' ]
|
||||
},
|
||||
darkMode: 'media',
|
||||
// darkMode: 'media',
|
||||
variants: {},
|
||||
plugins: [],
|
||||
theme: {
|
||||
|
||||
Reference in new issue
Block a user