formatting, full migration to svelte-french-toast

This commit is contained in:
2023-04-26 22:47:42 +02:00
parent 38a665024e
commit 46d076af9d
137 changed files with 11984 additions and 9212 deletions

View File

@@ -1,13 +1,13 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { UserService } from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail";
import Toastify from "toastify-js";
import PasswordStrength, {
password_strong_enough,
} from "../auth/PasswordStrength.svelte";
import toast from "svelte-french-toast";
export let modal_open;
export let current_users;
let firstname_input;
@@ -52,10 +52,7 @@
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
const toast = Toastify({
text: $_("user-is-being-added"),
duration: -1,
}).showToast();
toast.loading($_("user-is-being-added"));
UserService.userControllerPost({
firstname: firstname_input_value,
lastname: lastname_input_value,
@@ -72,18 +69,14 @@
username_input_value = "";
modal_open = false;
//
Toastify({
text: $_("user-added"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
toast.dismiss();
toast.success($_("user-added"));
current_users.push(result);
current_users = current_users;
})
.catch((err) => {})
.finally(() => {
processed_last_submit = true;
toast.hideToast();
});
}
}
@@ -92,58 +85,70 @@
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
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">
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" />
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span>
aria-hidden="true">&#8203;</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">
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">
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path
viewBox="0 0 24 24"
><path
fill="currentColor"
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z" /></svg>
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z"
/></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-user')}
{$_("create-a-new-user")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_('please-provide-the-required-information-to-add-a-new-user')}
{$_(
"please-provide-the-required-information-to-add-a-new-user"
)}
</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">{$_('first-name')}</label>
class="block text-sm font-medium text-gray-700"
>{$_("first-name")}</label
>
<input
use:focus
autocomplete="off"
placeholder={$_('first-name')}
placeholder={$_("first-name")}
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
@@ -151,34 +156,41 @@
bind:this={firstname_input}
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" />
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 !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('first-name-is-required')}
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("first-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="trackname"
class="block text-sm font-medium text-gray-700">{$_('middle-name')}</label>
class="block text-sm font-medium text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_('middle-name')}
placeholder={$_("middle-name")}
bind:value={middlename_input_value}
bind:this={middlename_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" />
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="lastname"
class="block text-sm font-medium text-gray-700">Last Name</label>
class="block text-sm font-medium text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder="Last Name"
placeholder={$_("last-name")}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
@@ -186,21 +198,25 @@
bind:this={lastname_input}
type="text"
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 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
/>
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('last-name-is-required')}
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("last-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="password"
class="block text-sm font-medium text-gray-700">{$_('password')}</label>
class="block text-sm font-medium text-gray-700"
>{$_("password")}</label
>
<input
autocomplete="off"
placeholder={$_('password')}
placeholder={$_("password")}
class:border-red-500={!isPasswordValid}
class:focus:border-red-500={!isPasswordValid}
class:focus:ring-red-500={!isPasswordValid}
@@ -208,38 +224,48 @@
bind:this={password_input}
type="password"
name="password"
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" />
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"
/>
<PasswordStrength
bind:password_change={password_input_value} />
bind:password_change={password_input_value}
/>
</div>
<div class="col-span-6">
<label
for="trackname"
class="block text-sm font-medium text-gray-700">{$_('username')}</label>
class="block text-sm font-medium text-gray-700"
>{$_("username")}</label
>
<input
autocomplete="off"
placeholder={$_('username')}
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" />
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"
class="block text-sm font-medium text-gray-700">{$_('e-mail-adress')}</label>
class="block text-sm font-medium text-gray-700"
>{$_("e-mail-adress")}</label
>
<input
autocomplete="off"
placeholder={$_('e-mail-adress')}
placeholder={$_("e-mail-adress")}
bind:value={email_input_value}
bind:this={email_input}
type="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 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
/>
{#if !isEmailValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">{$_('valid-email-is-required')}</span>
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>{$_("valid-email-is-required")}</span
>
{/if}
</div>
</div>
@@ -252,16 +278,18 @@
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')}
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')}
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>

View File

@@ -1,319 +1,341 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import isEmail from "validator/es/lib/isEmail";
import { UserService, UserGroupService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import PromiseError from "../base/PromiseError.svelte";
export let params;
const user_promise = UserService.userControllerGetOne(params.userid);
let data_loaded = false;
let usergroups_array_original = [];
const colors = [
"#f3558e",
"#17b978",
"#3498db",
"#3f3b3b",
"#775ada",
"#7ed6df_#000000",
"#000000",
"#21e6c1_#000000",
"#c0392b",
"#d35400",
"#7f8c8d",
"#6ab04c",
"#4834d4",
"#ff1f5a",
"#eac100",
];
let matched_colors = [];
$: delete_triggered = false;
$: original_data = {};
$: editable_userdata = {};
$: allgroups = [];
$: allgroups_ids = [];
$: usergroups_array = [];
$: search_permission = "";
user_promise.then((data) => {
let current_target = "";
let colorindex = -1;
// alphabetically sort permissions for color compatibility for target
data.permissions = data.permissions.sort();
data.permissions.forEach((p) => {
const target = p.split(":")[0];
if (current_target !== p.split(":")[0]) {
colorindex++;
current_target = p.split(":")[0];
}
let background = colors[colorindex];
let foreground = "#fff";
if (background.includes("_")) {
foreground = background.split("_")[1];
background = background.split("_")[0];
}
matched_colors[target] = [background, foreground];
});
//
data_loaded = true;
original_data = Object.assign(original_data, data);
editable_userdata = data;
data.groups.forEach((g) => {
usergroups_array = usergroups_array.concat([g.id]);
});
usergroups_array_original = usergroups_array;
allgroups.forEach((g) => {
allgroups_ids.push(g.id);
});
});
UserGroupService.userGroupControllerGetAll().then((data) => {
allgroups = data;
});
$: changes_performed = !(JSON.stringify(original_data) == JSON.stringify(editable_userdata));
$: groups_changed =
JSON.stringify(usergroups_array) ===
JSON.stringify(usergroups_array_original);
$: save_enabled =
(changes_performed || !groups_changed) && isEmail(editable_userdata.email);
function submit() {
if (data_loaded === true && save_enabled) {
editable_userdata.groups = usergroups_array;
Toastify({
text: $_("updating-user"),
duration: 2500,
}).showToast();
UserService.userControllerPut(original_data.id, editable_userdata)
.then((resp) => {
Object.assign(original_data, resp);
Object.assign(editable_userdata, resp);
original_data.permissions = resp.permissions;
usergroups_array = [];
resp.groups.forEach((g) => {
usergroups_array = usergroups_array.concat([g.id]);
});
usergroups_array_original = usergroups_array;
//
Toastify({
text: $_("user-updated"),
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {});
}
}
function deleteUser() {
UserService.userControllerRemove(original_data.id, true)
.then((resp) => {
location.replace("./");
})
.catch((err) => {});
}
</script>
{#await user_promise}
<!-- -->
{:then user}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<svg
class="flex-shrink-0 w-5 h-5 mr-2"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path
fill="currentColor"
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z" /></svg>
</li>
<li class="flex items-center">
<a class="mr-2" href="./">{$_('users')}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold">
{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={!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-3 text-sm w-full">
<label
for="enabled"
class="ml-1 font-medium text-gray-700">{$_('active')}?</label>
<br />
<p class="text-gray-500">
<input
id="enabled"
on:change={() => {
editable_userdata.enabled = !editable_userdata.enabled;
}}
name="enabled"
type="checkbox"
checked={editable_userdata.enabled}
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
{$_('set-the-user-active-inactive')}
</p>
</div>
<div class="text-sm w-full">
<label
for="firstname"
class="font-medium text-gray-700">{$_('first-name')}</label>
<input
autocomplete="off"
placeholder={$_('first-name')}
type="text"
bind:value={editable_userdata.firstname}
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 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="middlename"
class="font-medium text-gray-700">{$_('middle-name')}</label>
<input
autocomplete="off"
placeholder={$_('middle-name')}
type="text"
bind:value={editable_userdata.middlename}
name="middlename"
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="lastname"
class="font-medium text-gray-700">{$_('last-name')}</label>
<input
autocomplete="off"
placeholder={$_('last-name')}
type="text"
bind:value={editable_userdata.lastname}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</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>
{#if !isEmail(editable_userdata.email)}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">{$_('valid-email-is-required')}</span>
{/if}
<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 mt-8">
<p class="font-medium mb-4">
{$_('permissions')}
<a
class="px-4 py-2 bg-gray-500 rounded-md text-white"
href="/users/{params.userid}/permissions/">{$_('edit-permissions')}</a>
</p>
<div class="w-full sm:my-px sm:px-px sm:w-1/2">
<input
autocomplete="off"
placeholder="{$_('search-for-permission')}"
type="text"
bind:value={search_permission}
class="mt-4 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>
{#each original_data.permissions as p}
{#if p.toLowerCase().includes(search_permission.toLowerCase())}
<span
style="background:{matched_colors[p.split(':')[0]][0]};color:{matched_colors[p.split(':')[0]][1]};"
class="mt-1 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-indigo-100 rounded">{p}</span>
<!-- -->
{/if}
{/each}
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import isEmail from "validator/es/lib/isEmail";
import { UserService, UserGroupService } from "@odit/lfk-client-js";
import PromiseError from "../base/PromiseError.svelte";
import toast from "svelte-french-toast";
export let params;
const user_promise = UserService.userControllerGetOne(params.userid);
let data_loaded = false;
let usergroups_array_original = [];
const colors = [
"#f3558e",
"#17b978",
"#3498db",
"#3f3b3b",
"#775ada",
"#7ed6df_#000000",
"#000000",
"#21e6c1_#000000",
"#c0392b",
"#d35400",
"#7f8c8d",
"#6ab04c",
"#4834d4",
"#ff1f5a",
"#eac100",
];
let matched_colors = [];
$: delete_triggered = false;
$: original_data = {};
$: editable_userdata = {};
$: allgroups = [];
$: allgroups_ids = [];
$: usergroups_array = [];
$: search_permission = "";
user_promise.then((data) => {
let current_target = "";
let colorindex = -1;
// alphabetically sort permissions for color compatibility for target
data.permissions = data.permissions.sort();
data.permissions.forEach((p) => {
const target = p.split(":")[0];
if (current_target !== p.split(":")[0]) {
colorindex++;
current_target = p.split(":")[0];
}
let background = colors[colorindex];
let foreground = "#fff";
if (background.includes("_")) {
foreground = background.split("_")[1];
background = background.split("_")[0];
}
matched_colors[target] = [background, foreground];
});
//
data_loaded = true;
original_data = Object.assign(original_data, data);
editable_userdata = data;
data.groups.forEach((g) => {
usergroups_array = usergroups_array.concat([g.id]);
});
usergroups_array_original = usergroups_array;
allgroups.forEach((g) => {
allgroups_ids.push(g.id);
});
});
UserGroupService.userGroupControllerGetAll().then((data) => {
allgroups = data;
});
$: changes_performed = !(
JSON.stringify(original_data) == JSON.stringify(editable_userdata)
);
$: groups_changed =
JSON.stringify(usergroups_array) ===
JSON.stringify(usergroups_array_original);
$: save_enabled =
(changes_performed || !groups_changed) && isEmail(editable_userdata.email);
function submit() {
if (data_loaded === true && save_enabled) {
editable_userdata.groups = usergroups_array;
toast.loading($_("updating-user"));
UserService.userControllerPut(original_data.id, editable_userdata)
.then((resp) => {
Object.assign(original_data, resp);
Object.assign(editable_userdata, resp);
original_data.permissions = resp.permissions;
usergroups_array = [];
resp.groups.forEach((g) => {
usergroups_array = usergroups_array.concat([g.id]);
});
usergroups_array_original = usergroups_array;
//
toast.dismiss();
toast($_("user-updated"));
})
.catch((err) => {});
}
}
function deleteUser() {
UserService.userControllerRemove(original_data.id, true)
.then((resp) => {
location.replace("./");
})
.catch((err) => {});
}
</script>
{#await user_promise}
<!-- -->
{:then user}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<svg
class="flex-shrink-0 w-5 h-5 mr-2"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path
fill="currentColor"
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z"
/></svg
>
</li>
<li class="flex items-center">
<a class="mr-2" href="./">{$_("users")}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
><line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" /></svg
>
</li>
<li class="flex items-center">
<span class="mr-2"
>{original_data.firstname}
{original_data.middlename || ""}
{original_data.lastname}</span
>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold">
{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={!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-3 text-sm w-full">
<label for="enabled" class="ml-1 font-medium text-gray-700"
>{$_("active")}?</label
>
<br />
<p class="text-gray-500">
<input
id="enabled"
on:change={() => {
editable_userdata.enabled = !editable_userdata.enabled;
}}
name="enabled"
type="checkbox"
checked={editable_userdata.enabled}
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
{$_("set-the-user-active-inactive")}
</p>
</div>
<div class="text-sm w-full">
<label for="firstname" class="font-medium text-gray-700"
>{$_("first-name")}</label
>
<input
autocomplete="off"
placeholder={$_("first-name")}
type="text"
bind:value={editable_userdata.firstname}
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 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"
/>
</div>
<div class="text-sm w-full">
<label for="middlename" class="font-medium text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_("middle-name")}
type="text"
bind:value={editable_userdata.middlename}
name="middlename"
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="lastname" class="font-medium text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder={$_("last-name")}
type="text"
bind:value={editable_userdata.lastname}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"
/>
</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>
{#if !isEmail(editable_userdata.email)}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>{$_("valid-email-is-required")}</span
>
{/if}
<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 mt-8">
<p class="font-medium mb-4">
{$_("permissions")}
<a
class="px-4 py-2 bg-gray-500 rounded-md text-white"
href="/users/{params.userid}/permissions/">{$_("edit-permissions")}</a
>
</p>
<div class="w-full sm:my-px sm:px-px sm:w-1/2">
<input
autocomplete="off"
placeholder={$_("search-for-permission")}
type="text"
bind:value={search_permission}
class="mt-4 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>
{#each original_data.permissions as p}
{#if p.toLowerCase().includes(search_permission.toLowerCase())}
<span
style="background:{matched_colors[
p.split(':')[0]
][0]};color:{matched_colors[p.split(':')[0]][1]};"
class="mt-1 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-indigo-100 rounded"
>{p}</span
>
<!-- -->
{/if}
{/each}
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}

View File

@@ -5,8 +5,8 @@
PermissionService,
CreatePermission,
} from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import PromiseError from "../base/PromiseError.svelte";
import toast from "svelte-french-toast";
export let params;
let [
grantedPermissions_initial,
@@ -26,10 +26,7 @@
original_data = Object.assign(original_data, data);
});
function submit() {
Toastify({
text: $_('updating-permissions'),
duration: 2500,
}).showToast();
toast.loading($_("updating-permissions"));
to_delete.forEach((d) => {
promises = promises.concat([
PermissionService.permissionControllerRemove(d, true),
@@ -51,11 +48,8 @@
);
});
grantedPermissions_initial = grantedPermissions;
Toastify({
text: $_("permissions-updated"),
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
toast.dismiss();
toast.success($_("permissions-updated"));
});
}
Object.values(CreatePermission.target).forEach((t) => {
@@ -89,12 +83,15 @@
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path
viewBox="0 0 24 24"
><path
fill="currentColor"
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z" /></svg>
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z"
/></svg
>
</li>
<li class="flex items-center">
<a class="mr-2" href="../../">{$_('users')}</a><svg
<a class="mr-2" href="../../">{$_("users")}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
@@ -104,17 +101,19 @@
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
xmlns="http://www.w3.org/2000/svg"
><line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" /></svg
>
</li>
<li class="flex items-center">
<span class="mr-2"><a href="../">{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}</a></span>
<span class="mr-2"
><a href="../"
>{original_data.firstname}
{original_data.middlename || ""}
{original_data.lastname}</a
></span
>
</li>
<li class="flex items-center">
<svg
@@ -127,24 +126,22 @@
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
xmlns="http://www.w3.org/2000/svg"
><line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" /></svg
>
</li>
<li class="flex items-center">
<span class="mr-2">{$_('permissions')}</span>
<span class="mr-2">{$_("permissions")}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold">
{$_('permissions')}:
{$_("permissions")}:
{original_data.firstname}
{original_data.middlename || ''}
{original_data.middlename || ""}
{original_data.lastname}
<span>
{#if promises.length === 0}
@@ -153,24 +150,28 @@
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>
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
>
{:else}
<button
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-yellow-600 text-base font-medium text-white hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('applying-changes')}</button>
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-yellow-600 text-base font-medium text-white hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 sm:ml-3 sm:w-auto sm:text-sm"
>{$_("applying-changes")}</button
>
{/if}
</span>
</div>
<!-- -->
<div class="flex flex-wrap -mx-1 overflow-hidden">
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
{$_('verfuegbare')}
{$_("available-permissions")}
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
{$_('erteilte')}
{$_("directly-granted")}
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
{$_('geerbte')}
{$_("inherited-permissions")}
</div>
</div>
<!-- -->
@@ -178,12 +179,14 @@
{#if allpermissions.length > 0}
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
<div
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"
>
{#each allpermissions as p}
{#if !(grantedPermissions.filter((o)=>p.target == o.target && p.action == o.action).length > 0)}
{#if !(grantedPermissions.filter((o) => p.target == o.target && p.action == o.action).length > 0)}
<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.target + ':' + p.action}
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.target + ":" + p.action}
<button
on:click={() => {
grantedPermissions = grantedPermissions.concat([p]);
@@ -200,7 +203,9 @@
}
}}
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>
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}
@@ -208,33 +213,52 @@
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
<div
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"
>
{#each grantedPermissions as 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.target + ':' + p.action}
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.target + ":" + p.action}
<button
on:click={() => {
grantedPermissions = grantedPermissions.filter((o) => o.target + ':' + o.action !== p.target + ':' + p.action);
if (to_add.some((o) => o.target + ':' + o.action === p.target + ':' + p.action)) {
to_add = to_add.filter((o) => o.target + ':' + o.action !== p.target + ':' + p.action);
grantedPermissions = grantedPermissions.filter(
(o) =>
o.target + ":" + o.action !== p.target + ":" + p.action
);
if (
to_add.some(
(o) =>
o.target + ":" + o.action ===
p.target + ":" + p.action
)
) {
to_add = to_add.filter(
(o) =>
o.target + ":" + o.action !==
p.target + ":" + p.action
);
} else {
to_delete = to_delete.concat([p.id]);
}
}}
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>
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>
{/each}
</div>
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">
<div
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center"
>
{#each inheritedPermissions as 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.target + ':' + p.action}
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.target + ":" + p.action}
</p>
{/each}
</div>

View File

@@ -4,27 +4,28 @@
import AddUserModal from "./AddUserModal.svelte";
export let modal_open = false;
import UsersOverview from "./UsersOverview.svelte";
let current_users=[];
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')}
{$_("users")}
{#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')}
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>
<p class="mb-8 text-lg text-gray-500">{$_("manage-admin-users")}</p>
<UsersOverview bind:current_users />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
{#if store.state.jwtinfo.userdetails.permissions.includes("USER:CREATE")}
<AddUserModal bind:current_users bind:modal_open />
{/if}

View File

@@ -8,8 +8,8 @@
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="w-full h-44" src={users_empty} alt="" />
<span class="font-bold">{$_('there-are-no-users-added-yet')}</span><br />
<span>{$_('add-your-first-user')}</span>
<span class="font-bold">{$_("there-are-no-users-added-yet")}</span><br />
<span>{$_("add-your-first-user")}</span>
</p>
</div>

View File

@@ -16,13 +16,14 @@
});
</script>
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')}
{#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">
role="alert"
>
<p class="font-bold">users are being loaded...</p>
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div>
{:then}
{#if current_users.length === 0}
@@ -34,9 +35,10 @@
<input
type="search"
bind:value={searchvalue}
placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')}
class="mb-4" />
placeholder={$_("datatable.search")}
aria-label={$_("datatable.search")}
class="mb-4"
/>
<!-- {/if} -->
<!-- <button
on:click={() => {
@@ -49,27 +51,31 @@
{:else}toggle advanced search{/if}
</button> -->
<div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
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')}
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')}
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')}
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>
<span class="sr-only">{$_("action")}</span>
</th>
</tr>
</thead>
@@ -85,7 +91,7 @@
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{u.firstname}
{u.middlename || ''}
{u.middlename || ""}
{u.lastname}
</div>
<div class="text-sm text-gray-500">
@@ -97,52 +103,70 @@
<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>
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>
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>
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">
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>
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);
current_users = current_users.filter(
(obj) => obj.id !== u.id
);
})
.catch((err) => {});
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
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">
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">{$_('details')}</a>
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')}
class="text-indigo-600 hover:text-indigo-900"
>{$_("details")}</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>
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
>
{/if}
</td>
{/if}
@@ -156,7 +180,7 @@
{: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>
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div>