feature/12-user-management #39
@ -48,7 +48,7 @@
|
||||
OpenAPI.BASE = config.baseurl;
|
||||
import { register as registerSW } from "./swmodule";
|
||||
import TeamDetail from "./components/TeamDetail.svelte";
|
||||
import RunnerDetail from "./components/RunnerDetail.svelte";
|
||||
import UserPermissions from "./components/UserPermissions.svelte";
|
||||
store.init();
|
||||
registerSW();
|
||||
</script>
|
||||
@ -72,8 +72,13 @@
|
||||
<Route path="/">
|
||||
<Users />
|
||||
</Route>
|
||||
<Route path="/:userid" let:params>
|
||||
<UserDetail {params} />
|
||||
<Route path="/:userid/*" let:params>
|
||||
<Route path="/">
|
||||
<UserDetail {params} />
|
||||
</Route>
|
||||
<Route path="/permissions/">
|
||||
<UserPermissions {params} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/tracks/*">
|
||||
@ -82,13 +87,8 @@
|
||||
</Route>
|
||||
<Route path="/:trackid" let:params />
|
||||
</Route>
|
||||
<Route path="/runners/*">
|
||||
<Route path="/">
|
||||
<Runners />
|
||||
</Route>
|
||||
<Route path="/:runnerid" let:params>
|
||||
<RunnerDetail {params} />
|
||||
</Route>
|
||||
<Route path="/runners">
|
||||
<Runners />
|
||||
</Route>
|
||||
<Route path="/teams/*">
|
||||
<Route path="/">
|
||||
|
@ -28,7 +28,10 @@
|
||||
$: isLastnameValid = lastname_input_value.trim().length !== 0;
|
||||
$: isFirstnameValid = firstname_input_value.trim().length !== 0;
|
||||
$: createbtnenabled =
|
||||
isFirstnameValid && isLastnameValid && isEmailValid && isPasswordValid;
|
||||
isFirstnameValid &&
|
||||
isLastnameValid &&
|
||||
isPasswordValid &&
|
||||
!(!isEmailValid && username_input_value.trim().length === 0);
|
||||
(function () {
|
||||
document.onkeydown = function (e) {
|
||||
e = e || window.event;
|
||||
@ -50,19 +53,14 @@
|
||||
text: "User is being added...",
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
let postdata={
|
||||
UserService.userControllerPost({
|
||||
firstname: firstname_input_value,
|
||||
lastname: lastname_input_value,
|
||||
middlename: middlename_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)
|
||||
password: password_input_value,
|
||||
email: email_input_value,
|
||||
username: username_input_value,
|
||||
})
|
||||
.then((result) => {
|
||||
firstname_input_value = "";
|
||||
lastname_input_value = "";
|
||||
@ -77,7 +75,7 @@
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
current_users.push(result);
|
||||
current_users=current_users;
|
||||
current_users = current_users;
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
@ -238,18 +236,21 @@
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder={$_('e-mail-adress')}
|
||||
class:border-red-500={!isEmailValid}
|
||||
class:focus:border-red-500={!isEmailValid}
|
||||
class:focus:ring-red-500={!isEmailValid}
|
||||
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" />
|
||||
{#if !isEmailValid}
|
||||
<!-- {#if !isEmailValid}
|
||||
<span
|
||||
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
|
||||
{$_('valid-email-is-required')}
|
||||
valid email or username is required
|
||||
</span>
|
||||
{/if} -->
|
||||
{#if !isEmailValid && username_input_value.trim().length === 0}
|
||||
<span
|
||||
class="mt-8 flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
|
||||
valid email or username is required
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -2,31 +2,63 @@
|
||||
import { _ } from "svelte-i18n";
|
||||
import lodashIsEqual from "lodash.isequal";
|
||||
import store from "../store";
|
||||
import {
|
||||
UserService,
|
||||
UserGroupService,
|
||||
PermissionService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import { UserService, UserGroupService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import PromiseError from "./PromiseError.svelte";
|
||||
export let params;
|
||||
const user_promise = UserService.userControllerGetOne(params.userid);
|
||||
let data_loaded = false;
|
||||
let 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 = {};
|
||||
$: allpermissions = [];
|
||||
$: allgroups = [];
|
||||
$: allgroups_ids = [];
|
||||
$: usergroups_array_objects = [];
|
||||
$: usergroups_array = [];
|
||||
let usergroups_array_original = [];
|
||||
$: 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 = usergroups_array.concat([g.id]);
|
||||
});
|
||||
usergroups_array_original = usergroups_array;
|
||||
allgroups.forEach((g) => {
|
||||
@ -36,37 +68,28 @@
|
||||
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;
|
||||
$: groups_changed =
|
||||
JSON.stringify(usergroups_array) ===
|
||||
JSON.stringify(usergroups_array_original);
|
||||
$: save_enabled = changes_performed || !groups_changed;
|
||||
function submit() {
|
||||
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;
|
||||
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, editable_userdata);
|
||||
original_data = editable_userdata;
|
||||
Object.assign(original_data, editable_userdata);
|
||||
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"),
|
||||
@ -74,9 +97,7 @@
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
})
|
||||
.catch((err) => {
|
||||
});
|
||||
} else {
|
||||
.catch((err) => {});
|
||||
}
|
||||
}
|
||||
function deleteUser() {
|
||||
@ -84,8 +105,7 @@
|
||||
.then((resp) => {
|
||||
location.replace("./");
|
||||
})
|
||||
.catch((err) => {
|
||||
});
|
||||
.catch((err) => {});
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -135,7 +155,7 @@
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8 text-3xl font-extrabold leading-tight">
|
||||
<div class="mb-8 text-3xl font-extrabold">
|
||||
{original_data.firstname}
|
||||
{original_data.middlename || ''}
|
||||
{original_data.lastname}
|
||||
@ -170,31 +190,30 @@
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 flex items-center">
|
||||
<div class="mt-3 text-sm w-full">
|
||||
<p class="ml-1 font-medium text-gray-700">Profile Picture</p>
|
||||
<img
|
||||
alt={$_('profile-picture')}
|
||||
class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100"
|
||||
class="h-20 w-20 rounded-full overflow-hidden bg-gray-100"
|
||||
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>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="mt-3 text-sm w-full">
|
||||
<input
|
||||
id="enabled"
|
||||
on:change={() => {
|
||||
editable_userdata.enabled = !editable_userdata.enabled;
|
||||
// TODO: this reactive set does not work?
|
||||
}}
|
||||
name="enabled"
|
||||
type="checkbox"
|
||||
checked={editable_userdata.enabled}
|
||||
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
|
||||
<label
|
||||
for="enabled"
|
||||
class="ml-1 font-medium text-gray-700">Active?</label>
|
||||
<p class="text-gray-500">set the user active/ inactive</p>
|
||||
<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
|
||||
@ -206,7 +225,7 @@
|
||||
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 rounded-md p-2" />
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
|
||||
</div>
|
||||
<div class="text-sm w-full">
|
||||
<label
|
||||
@ -218,7 +237,7 @@
|
||||
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 rounded-md p-2" />
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
|
||||
</div>
|
||||
<div class="text-sm w-full">
|
||||
<label
|
||||
@ -230,7 +249,7 @@
|
||||
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 rounded-md p-2" />
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
|
||||
</div>
|
||||
<div class="text-sm w-full">
|
||||
<label
|
||||
@ -242,7 +261,7 @@
|
||||
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 rounded-md p-2" />
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
|
||||
</div>
|
||||
<div class="text-sm w-full">
|
||||
<label
|
||||
@ -254,14 +273,14 @@
|
||||
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 rounded-md p-2" />
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
|
||||
</div>
|
||||
<div 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 rounded-md p-2"
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"
|
||||
multiple>
|
||||
{#each allgroups as g}
|
||||
{#if usergroups_array.includes(g.id)}
|
||||
@ -272,61 +291,29 @@
|
||||
{/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 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple 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 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple 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 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}
|
||||
|
241
src/components/UserPermissions.svelte
Normal file
241
src/components/UserPermissions.svelte
Normal file
@ -0,0 +1,241 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import {
|
||||
UserService,
|
||||
PermissionService,
|
||||
CreatePermission,
|
||||
} from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import PromiseError from "./PromiseError.svelte";
|
||||
export let params;
|
||||
let [
|
||||
grantedPermissions_initial,
|
||||
grantedPermissions,
|
||||
inheritedPermissions,
|
||||
to_add,
|
||||
to_delete,
|
||||
allpermissions,
|
||||
promises,
|
||||
] = [[], [], [], [], [], [], []];
|
||||
$: original_data = {};
|
||||
$: save_enabled =
|
||||
JSON.stringify(grantedPermissions) ===
|
||||
JSON.stringify(grantedPermissions_initial);
|
||||
const user_promise = UserService.userControllerGetOne(params.userid);
|
||||
user_promise.then((data) => {
|
||||
original_data = Object.assign(original_data, data);
|
||||
});
|
||||
function submit() {
|
||||
Toastify({
|
||||
text: "updating permissions...",
|
||||
duration: 2500,
|
||||
}).showToast();
|
||||
to_delete.forEach((d) => {
|
||||
promises = promises.concat([
|
||||
PermissionService.permissionControllerRemove(d, true),
|
||||
]);
|
||||
});
|
||||
to_add.forEach((a) => {
|
||||
promises = promises.concat([
|
||||
PermissionService.permissionControllerPost(a),
|
||||
]);
|
||||
});
|
||||
Promise.all(promises).then((values) => {
|
||||
promises = [];
|
||||
to_delete.forEach((d) => {
|
||||
to_delete = to_delete.filter((o) => o !== d);
|
||||
});
|
||||
to_add.forEach((a) => {
|
||||
to_add = to_add.filter(
|
||||
(o) => o.target + ":" + o.action !== a.target + ":" + a.action
|
||||
);
|
||||
});
|
||||
Toastify({
|
||||
text: "Permissions updated!",
|
||||
duration: 2500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
});
|
||||
}
|
||||
Object.values(CreatePermission.target).forEach((t) => {
|
||||
Object.values(CreatePermission.action).forEach((a) => {
|
||||
allpermissions = allpermissions.concat([{ target: t, action: a }]);
|
||||
});
|
||||
});
|
||||
UserService.userControllerGetPermissions(params.userid).then((val) => {
|
||||
val.inherited.forEach((p) => {
|
||||
inheritedPermissions = inheritedPermissions.concat([p]);
|
||||
});
|
||||
val.directlyGranted.forEach((p) => {
|
||||
grantedPermissions = grantedPermissions.concat([p]);
|
||||
});
|
||||
grantedPermissions_initial = grantedPermissions;
|
||||
});
|
||||
</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 640 512"><path
|
||||
fill="currentColor"
|
||||
d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<a class="mr-2" href="./">{$_('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"><a href="../">{original_data.firstname}
|
||||
{original_data.middlename || ''}
|
||||
{original_data.lastname}</a></span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="h-3 w-3 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">Permissions</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8 text-3xl font-extrabold">
|
||||
Permissions:
|
||||
{original_data.firstname}
|
||||
{original_data.middlename || ''}
|
||||
{original_data.lastname}
|
||||
<span>
|
||||
{#if promises.length === 0}
|
||||
<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>
|
||||
{: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>
|
||||
{/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">verfügbare</div>
|
||||
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">erteilte</div>
|
||||
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/3">geerbte</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/3">
|
||||
<div
|
||||
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
|
||||
{#each allpermissions as p}
|
||||
{#if !grantedPermissions.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.target + ':' + p.action}
|
||||
<button
|
||||
on:click={() => {
|
||||
grantedPermissions = grantedPermissions.concat([p]);
|
||||
if (to_delete.some((o) => o === p.id)) {
|
||||
to_delete = to_delete.filter((o) => o !== p.id);
|
||||
} else {
|
||||
to_add = to_add.concat([
|
||||
{
|
||||
action: p.action,
|
||||
target: p.target,
|
||||
principal: original_data.id,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}}
|
||||
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/3">
|
||||
<div
|
||||
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}
|
||||
<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);
|
||||
} 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>
|
||||
</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">
|
||||
{#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}
|
||||
</p>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
{:catch error}
|
||||
<PromiseError {error} />
|
||||
{/await}
|
@ -1,11 +1,13 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import AddUserModal from "./AddUserModal.svelte";
|
||||
import users_empty from "./users_empty.svg";
|
||||
let modal_open = false;
|
||||
</script>
|
||||
|
||||
<div class="text-center items-center justify-center">
|
||||
<p class="mb-16 text-lg text-gray-500">
|
||||
<img class="w-full h-44" src={users_empty} alt="" />
|
||||
<span class="font-bold">There are no users added yet.</span><br />
|
||||
<span>Add your first user</span>
|
||||
</p>
|
||||
|
@ -29,17 +29,17 @@
|
||||
{#if current_users.length === 0}
|
||||
<UsersEmptyState />
|
||||
{:else}
|
||||
{#if advanced_search}
|
||||
<!-- {#if advanced_search}
|
||||
advanced search
|
||||
{:else}
|
||||
{:else} -->
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchvalue}
|
||||
placeholder={$_('datatable.search')}
|
||||
aria-label={$_('datatable.search')}
|
||||
class="gridjs-input gridjs-search-input mb-4" />
|
||||
{/if}
|
||||
<button
|
||||
<!-- {/if} -->
|
||||
<!-- <button
|
||||
on:click={() => {
|
||||
advanced_search = !advanced_search;
|
||||
}}
|
||||
@ -48,7 +48,7 @@
|
||||
{#if advanced_search}
|
||||
toggle simple search
|
||||
{:else}toggle advanced search{/if}
|
||||
</button>
|
||||
</button> -->
|
||||
<div
|
||||
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
|
||||
<table class="divide-y divide-gray-200 w-full">
|
||||
|
1
src/components/users_empty.svg
Normal file
1
src/components/users_empty.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.6 KiB |
@ -60,6 +60,7 @@
|
||||
"dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌",
|
||||
"drag-and-drop-your-files-or": "Drag & Drop your files or",
|
||||
"e-mail-adress": "E-Mail Adress",
|
||||
"edit-permissions": "edit permissions",
|
||||
"email_address_or_username": "Email / username",
|
||||
"error_on_login": "Error on login",
|
||||
"faq": "FAQ",
|
||||
@ -119,6 +120,7 @@
|
||||
"oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!",
|
||||
"password": "Password",
|
||||
"password-is-required": "Password is required",
|
||||
"permissions": "Permissions",
|
||||
"phone": "Phone",
|
||||
"please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file",
|
||||
"please-provide-the-required-information-to-add-a-new-runner": "Please provide the required information to add a new runner.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user