@isoftdata/svelte-user-configuration 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Svelte UserConfiguration
2
+
3
+ ## Install
4
+
5
+ ```sh
6
+ npm i @isoftdata/svelte-user-configuration
7
+ ```
8
+
9
+ ## Props
10
+ | Name | Type | Description | Default Value |
11
+ |------|------|-------------|---------------|
12
+ | | | | |
13
+ | | | | |
14
+ | | | | |
15
+
16
+ ## Slots
17
+ * default - A brief description of the slot, if there is one
18
+
19
+ ## Events
20
+ * exampleEvent - A brief description of the event, if there are any
21
+
22
+ ## Example
23
+ ```svelte
24
+ <script lang="ts">
25
+ import UserConfiguration from '@isoftdata/svelte-user-configuration'
26
+ </script>
27
+
28
+ <UserConfiguration prop='foo' />
29
+ ```
@@ -0,0 +1,46 @@
1
+ <script>import { getContext, tick } from "svelte";
2
+ import { klona } from "klona";
3
+ import Modal from "@isoftdata/svelte-modal";
4
+ import TextArea from "@isoftdata/svelte-textarea";
5
+ let show = false;
6
+ let userAccount;
7
+ let lockNotes;
8
+ let textarea;
9
+ export let deactivateUser = void 0;
10
+ export async function open(userAccountCtx) {
11
+ userAccount = klona(userAccountCtx);
12
+ lockNotes = userAccount.lockNotes;
13
+ await tick();
14
+ show = true;
15
+ await tick();
16
+ textarea?.select();
17
+ }
18
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
19
+ </script>
20
+
21
+ <Modal
22
+ title={translate('common:deactivate', 'Deactivate {{userName}}', { userName: userAccount?.name })}
23
+ confirmButtonText={translate('common:deactivate', 'Deactivate')}
24
+ confirmButtonColor="danger"
25
+ cancelButtonText={translate('common:close', 'Close')}
26
+ confirmButtonType="submit"
27
+ confirmButtonFormId="deactivateUserModalForm"
28
+ on:close={() => (show = false)}
29
+ bind:show
30
+ >
31
+ <form
32
+ id="deactivateUserModalForm"
33
+ on:submit={e => {
34
+ e.preventDefault()
35
+ userAccount && deactivateUser ? deactivateUser({ id: userAccount.id, lockNotes }) : undefined
36
+ }}
37
+ >
38
+ <TextArea
39
+ bind:textarea
40
+ label={translate('configuration.user.accountInfo.lockNote', 'Lock Notes')}
41
+ labelClass="py-0 mb-2"
42
+ style="min-height:83px;"
43
+ bind:value={lockNotes}
44
+ />
45
+ </form>
46
+ </Modal>
@@ -0,0 +1,24 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { UserAccount } from './';
3
+ declare const __propDef: {
4
+ props: {
5
+ deactivateUser?: ((user: {
6
+ id: UserAccount["id"];
7
+ lockNotes: UserAccount["lockNotes"];
8
+ }) => void | Promise<void>) | undefined;
9
+ open?: (userAccountCtx: UserAccount) => Promise<void>;
10
+ };
11
+ events: {
12
+ [evt: string]: CustomEvent<any>;
13
+ };
14
+ slots: {};
15
+ exports?: {} | undefined;
16
+ bindings?: string | undefined;
17
+ };
18
+ export type DeactivateUserModalProps = typeof __propDef.props;
19
+ export type DeactivateUserModalEvents = typeof __propDef.events;
20
+ export type DeactivateUserModalSlots = typeof __propDef.slots;
21
+ export default class DeactivateUserModal extends SvelteComponent<DeactivateUserModalProps, DeactivateUserModalEvents, DeactivateUserModalSlots> {
22
+ get open(): (userAccountCtx: UserAccount) => Promise<void>;
23
+ }
24
+ export {};
@@ -0,0 +1,58 @@
1
+ <script>import { getContext } from "svelte";
2
+ import Modal from "@isoftdata/svelte-modal";
3
+ import Input from "@isoftdata/svelte-input";
4
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
5
+ export let sendPasswordRecoveryToken = void 0;
6
+ let resetDate = void 0;
7
+ let email = void 0;
8
+ let show = false;
9
+ export function open(passwordRecoveryEmail, lastResetDate) {
10
+ email = passwordRecoveryEmail;
11
+ resetDate = lastResetDate;
12
+ show = true;
13
+ }
14
+ </script>
15
+
16
+ <Modal
17
+ bind:show
18
+ title={translate('configuration.user.accountInfo.passwordRecovery.header', 'Password Recovery')}
19
+ confirmButtonText={translate('configuration.user.accountInfo.passwordManagementModal.requestResetToken', 'Request Reset Token')}
20
+ confirmButtonIcon="check"
21
+ confirmButtonDisabled={!email}
22
+ on:close={() => (show = false)}
23
+ confirmButtonType="submit"
24
+ confirmButtonFormId="passwordRecoveryForm"
25
+ >
26
+ <form
27
+ id="passwordRecoveryForm"
28
+ on:submit={async event => {
29
+ event.preventDefault()
30
+ try {
31
+ await sendPasswordRecoveryToken?.(email)
32
+ show = false
33
+ } catch (err) {
34
+ console.error(err)
35
+ }
36
+ }}
37
+ >
38
+ <div class="form-row">
39
+ <Input
40
+ label={translate('configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate', 'Last Password Set Date')}
41
+ value={resetDate?.toLocaleString() ?? ''}
42
+ labelParentClass="col-12 col-md-6 form-group mb-0"
43
+ readonly
44
+ />
45
+ <Input
46
+ label={translate('configuration.user.accountInfo.passwordRecoveryModal.passwordRecoveryEmail', 'Password Recovery Email')}
47
+ value={email ?? ''}
48
+ labelParentClass="col-12 col-md-6 form-group mb-0"
49
+ readonly
50
+ />
51
+ {#if !email}
52
+ <div class="alert alert-danger mt-3 mb-0">
53
+ {translate('configuration.user.accountInfo.passwordRecovery.noRecoveryEmail', 'No recovery email has been set for this user.')}
54
+ </div>
55
+ {/if}
56
+ </div>
57
+ </form>
58
+ </Modal>
@@ -0,0 +1,20 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ sendPasswordRecoveryToken?: ((email: string | undefined) => void | Promise<void>) | undefined;
5
+ open?: (passwordRecoveryEmail: string | undefined, lastResetDate: Date | undefined) => void;
6
+ };
7
+ events: {
8
+ [evt: string]: CustomEvent<any>;
9
+ };
10
+ slots: {};
11
+ exports?: {} | undefined;
12
+ bindings?: string | undefined;
13
+ };
14
+ export type PasswordRecoveryModalProps = typeof __propDef.props;
15
+ export type PasswordRecoveryModalEvents = typeof __propDef.events;
16
+ export type PasswordRecoveryModalSlots = typeof __propDef.slots;
17
+ export default class PasswordRecoveryModal extends SvelteComponent<PasswordRecoveryModalProps, PasswordRecoveryModalEvents, PasswordRecoveryModalSlots> {
18
+ get open(): (passwordRecoveryEmail: string | undefined, lastResetDate: Date | undefined) => void;
19
+ }
20
+ export {};
@@ -0,0 +1,78 @@
1
+ <script>import { tick, getContext } from "svelte";
2
+ import Input from "@isoftdata/svelte-input";
3
+ import Modal from "@isoftdata/svelte-modal";
4
+ import PasswordFields from "@isoftdata/svelte-password-fields";
5
+ import { klona } from "klona";
6
+ let show = false;
7
+ let newPassword = "";
8
+ let confirmPassword = "";
9
+ let passwordMismatch = false;
10
+ let lastResetDate = void 0;
11
+ let input = void 0;
12
+ let passwordRecoveryEmail = void 0;
13
+ let error = void 0;
14
+ export let confirmPasswordSet = void 0;
15
+ export async function open(userAccount) {
16
+ error = void 0;
17
+ newPassword = "";
18
+ confirmPassword = "";
19
+ lastResetDate = klona(userAccount?.lastPasswordResetDate);
20
+ passwordRecoveryEmail = userAccount?.recoveryEmail;
21
+ show = true;
22
+ await tick();
23
+ input?.focus();
24
+ }
25
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
26
+ </script>
27
+
28
+ <Modal
29
+ bind:show
30
+ modalSize="sm"
31
+ title={translate('configuration.user.accountInfo.setPasswordModal.header', 'Set Password')}
32
+ confirmButtonText={translate('configuration.user.accountInfo.passwordManagementModal.setPassword', 'Set Password')}
33
+ confirmButtonIcon="check"
34
+ confirmButtonDisabled={passwordMismatch || !newPassword || !confirmPassword}
35
+ on:close={() => (show = false)}
36
+ confirmButtonType="submit"
37
+ confirmButtonFormId="setPasswordForm"
38
+ >
39
+ <form
40
+ id="setPasswordForm"
41
+ on:submit={async e => {
42
+ e.preventDefault()
43
+ if (!passwordMismatch && confirmPasswordSet) {
44
+ try {
45
+ await confirmPasswordSet({ password: newPassword })
46
+ show = false
47
+ } catch (err) {
48
+ console.error(err)
49
+ if (err instanceof Error) {
50
+ error = err
51
+ }
52
+ }
53
+ }
54
+ }}
55
+ >
56
+ <Input
57
+ label={translate('configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate', 'Last Password Set Date')}
58
+ tabindex={-1}
59
+ value={lastResetDate ? lastResetDate.toLocaleString() : ''}
60
+ labelParentClass="form-group mb-0"
61
+ readonly
62
+ />
63
+ <PasswordFields
64
+ bind:password={newPassword}
65
+ bind:confirmPassword
66
+ bind:passwordMismatch
67
+ bind:passwordInput={input}
68
+ columnClass="col-12"
69
+ passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
70
+ confirmPasswordLabel={translate('configuration.user.accountInfo.passwordManagementModal.confirmNewPassword', 'Confirm New Password')}
71
+ />
72
+ {#if !passwordRecoveryEmail}
73
+ <div class="alert alert-danger mt-3 mb-0">
74
+ {translate('configuration.user.accountInfo.passwordRecovery.noRecoveryEmail', 'No recovery email has been set for this user.')}
75
+ </div>
76
+ {/if}
77
+ </form>
78
+ </Modal>
@@ -0,0 +1,23 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { UserAccount } from './';
3
+ declare const __propDef: {
4
+ props: {
5
+ confirmPasswordSet?: ((ctx: {
6
+ password: string;
7
+ }) => void | Promise<void>) | undefined;
8
+ open?: (userAccount?: UserAccount) => Promise<void>;
9
+ };
10
+ events: {
11
+ [evt: string]: CustomEvent<any>;
12
+ };
13
+ slots: {};
14
+ exports?: {} | undefined;
15
+ bindings?: string | undefined;
16
+ };
17
+ export type PasswordSetModalProps = typeof __propDef.props;
18
+ export type PasswordSetModalEvents = typeof __propDef.events;
19
+ export type PasswordSetModalSlots = typeof __propDef.slots;
20
+ export default class PasswordSetModal extends SvelteComponent<PasswordSetModalProps, PasswordSetModalEvents, PasswordSetModalSlots> {
21
+ get open(): (userAccount?: UserAccount) => Promise<void>;
22
+ }
23
+ export {};
@@ -0,0 +1,199 @@
1
+ <script>import { getContext } from "svelte";
2
+ import camelCase from "just-camel-case";
3
+ import Icon from "@isoftdata/svelte-icon";
4
+ import Button from "@isoftdata/svelte-button";
5
+ import Select from "@isoftdata/svelte-select";
6
+ import { getEventValue } from "@isoftdata/browser-event";
7
+ import { Table, Td } from "@isoftdata/svelte-table";
8
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
9
+ export let permissions;
10
+ export let siteLabel = "Site";
11
+ export let permissionValueChange = void 0;
12
+ export let icon = "user-lock";
13
+ export let cardHeaderTitle = translate("common:permissions", "Permissions");
14
+ let computedPermissions = [];
15
+ let selectedPermissionIds = /* @__PURE__ */ new Set();
16
+ let selectedPermissionValue = null;
17
+ const permissionColumns = getColumns(permissions);
18
+ const permissionValueList = {
19
+ NONE: { label: translate("common:permissionLevel.none", "None"), value: "NONE", color: "danger" },
20
+ SITE: { label: translate(`common:permissionLevel.${siteLabel.toLowerCase()}`, siteLabel), value: "SITE", color: "primary" },
21
+ GLOBAL: { label: translate("common:permissionLevel.global", "Global"), value: "GLOBAL", color: "success" }
22
+ };
23
+ function getColumns(permissions2) {
24
+ const hasGroupValue = permissions2.every((permission) => !!permission.groupValue);
25
+ let columns = [
26
+ { property: "value", name: hasGroupValue ? translate("common:user", "User") : translate("common:permission", "Permission"), width: "1rem" },
27
+ { property: "category", name: translate("common:category", "Category") },
28
+ { property: "displayName", name: translate("common:name", "Name") }
29
+ ];
30
+ if (hasGroupValue) {
31
+ columns.splice(
32
+ 1,
33
+ 0,
34
+ { property: "groupValue", name: translate("common:group", "Group"), align: "center", width: "1rem", minWidth: "25%" },
35
+ { property: "computedValue", name: translate("common:access", "Access"), align: "center", width: "1rem", minWidth: "25%" }
36
+ );
37
+ }
38
+ return columns;
39
+ }
40
+ function selectPermissions(permissionId) {
41
+ selectedPermissionIds.has(permissionId) ? selectedPermissionIds.delete(permissionId) : selectedPermissionIds.add(permissionId);
42
+ selectedPermissionIds = selectedPermissionIds;
43
+ }
44
+ function selectAndDeselectAllPermissions() {
45
+ if (selectedPermissionIds.size === computedPermissions.length) {
46
+ selectedPermissionIds.clear();
47
+ selectedPermissionValue = null;
48
+ } else {
49
+ selectedPermissionIds = new Set(permissions.map((permission) => permission.id));
50
+ }
51
+ selectedPermissionIds = selectedPermissionIds;
52
+ }
53
+ const getButtonColor = (optionValue, permissionValue) => optionValue === permissionValue ? permissionValueList[optionValue].color : "outline-secondary";
54
+ const isValidPermissionValue = (value) => Object.keys(permissionValueList).includes(value);
55
+ async function updatePermissionValues(event, permissionIds) {
56
+ const newValue = getEventValue(event);
57
+ if (isValidPermissionValue(newValue)) {
58
+ for (const permission of permissions) {
59
+ if (permissionIds.has(permission.id)) {
60
+ permission.value = newValue;
61
+ }
62
+ }
63
+ permissions = permissions;
64
+ await permissionValueChange?.({
65
+ value: newValue,
66
+ permissionIds: Array.from(permissionIds)
67
+ });
68
+ }
69
+ }
70
+ function getComputedPermissions(permissions2) {
71
+ return permissions2.map((permission) => {
72
+ const { value, groupValue } = permission;
73
+ let computedValue = value === "NONE" && groupValue || value === siteLabel.toUpperCase() && groupValue === "GLOBAL" ? groupValue : value;
74
+ return {
75
+ ...permission,
76
+ displayName: translate(`permissions:${camelCase(permission.codeName)}.displayName`, permission.displayName),
77
+ category: translate(`permissions:categories.${camelCase(permission.category)}`, permission.category),
78
+ computedValue
79
+ };
80
+ });
81
+ }
82
+ $: computedPermissions = getComputedPermissions(permissions);
83
+ </script>
84
+
85
+ <div
86
+ class="card"
87
+ {...$$restProps}
88
+ >
89
+ <div class="card-header">
90
+ <h5 class="mb-0">
91
+ <Icon
92
+ {icon}
93
+ class="mr-1"
94
+ />
95
+ {cardHeaderTitle}
96
+ </h5>
97
+ </div>
98
+ <div class="card-body">
99
+ <Table
100
+ class="mb-0"
101
+ parentClass="mh-60vh overflow-y-auto"
102
+ filterPlaceholder={translate('common:filterPermissions', 'Filter Permissions')}
103
+ filterColumnClass="col-6 col-lg-4 align-self-end"
104
+ rows={computedPermissions}
105
+ columns={permissionColumns}
106
+ responsive
107
+ filterEnabled
108
+ let:row={permission}
109
+ >
110
+ <tr
111
+ on:click={() => selectPermissions(permission.id)}
112
+ class:table-primary={selectedPermissionIds.has(permission.id)}
113
+ class="cursor-pointer"
114
+ >
115
+ <Td property="value">
116
+ <div
117
+ class="btn-group btn-group-toggle"
118
+ data-toggle="buttons"
119
+ >
120
+ {#each Object.values(permissionValueList) as permissionValue}
121
+ <label class="btn btn-sm btn-{getButtonColor(permissionValue.value, permission.value)} cursor-pointer">
122
+ <input
123
+ type="radio"
124
+ autocomplete="off"
125
+ name={permission.value}
126
+ value={permissionValue.value}
127
+ on:change={e => updatePermissionValues(e, new Set([permission.id]))}
128
+ />
129
+ {permissionValue.label}
130
+ </label>
131
+ {/each}
132
+ </div>
133
+ </Td>
134
+ {#if permission.groupValue && permission.computedValue}
135
+ <Td
136
+ property="groupValue"
137
+ class="px-4"
138
+ >
139
+ <span
140
+ style="width: 5em;"
141
+ class="badge badge-pill badge-{permissionValueList[permission.groupValue].color}">{permissionValueList[permission.groupValue].label}</span
142
+ >
143
+ </Td>
144
+ <Td
145
+ property="computedValue"
146
+ class="px-4"
147
+ >
148
+ <span
149
+ style="width: 5em;"
150
+ class="badge badge-pill badge-{permissionValueList[permission.computedValue].color}">{permissionValueList[permission.computedValue].label}</span
151
+ >
152
+ </Td>
153
+ {/if}
154
+ <Td property="category">{permission.category}</Td>
155
+ <Td property="displayName">{permission.displayName}</Td>
156
+ </tr>
157
+ </Table>
158
+ <slot></slot>
159
+ </div>
160
+ <div class="card-footer">
161
+ <div class="d-flex justify-content-between align-items-end">
162
+ <Select
163
+ label="{translate('common:setSelectedTo', 'Set Selected To')}:"
164
+ bind:value={selectedPermissionValue}
165
+ showEmptyOption={selectedPermissionValue === null}
166
+ emptyValue={null}
167
+ emptyText={translate('common:selectValue', 'Select a Value')}
168
+ labelParentClass="form-inline mr-2"
169
+ labelClass="mr-2 p-0"
170
+ disabled={selectedPermissionIds.size === 0}
171
+ on:change={e => {
172
+ updatePermissionValues(e, selectedPermissionIds)
173
+ selectedPermissionIds = new Set() //clear the Set and trigger reactivity
174
+ selectedPermissionValue = null
175
+ }}
176
+ >
177
+ {#each Object.values(permissionValueList) as permission}
178
+ <option value={permission.value}>{permission.label}</option>
179
+ {/each}
180
+ </Select>
181
+ <Button
182
+ class="mb-1"
183
+ outline
184
+ size="sm"
185
+ iconClass="check-double"
186
+ on:click={selectAndDeselectAllPermissions}
187
+ >
188
+ <span class:d-none={selectedPermissionIds.size !== computedPermissions.length}>{translate('common:deselectAll', 'Deselect All')}</span>
189
+ <span class:d-none={selectedPermissionIds.size === computedPermissions.length}>{translate('common:selectAll', 'Select All')}</span>
190
+ </Button>
191
+ </div>
192
+ </div>
193
+ </div>
194
+
195
+ <style>
196
+ .cursor-pointer {
197
+ cursor: pointer;
198
+ }
199
+ </style>
@@ -0,0 +1,37 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { IconName, SiteLabel, HTMLDivAttributes } from './';
3
+ declare const __propDef: {
4
+ props: HTMLDivAttributes & {
5
+ permissions: Array<{
6
+ id: number;
7
+ displayName: string;
8
+ category: string;
9
+ value: "NONE" | "SITE" | "GLOBAL";
10
+ /** Ractive version of this component didn't require `codeName`, but the translation key for permissions requires it, so we can't translate without it.*/
11
+ codeName: string;
12
+ /** Providing this value will cause the Group and Access columns to be rendered*/
13
+ groupValue?: "NONE" | "SITE" | "GLOBAL";
14
+ }>;
15
+ siteLabel?: SiteLabel;
16
+ permissionValueChange?: ((change: {
17
+ value: "NONE" | "SITE" | "GLOBAL";
18
+ permissionIds: Array<number>;
19
+ }) => void | Promise<void>) | undefined;
20
+ icon?: IconName;
21
+ cardHeaderTitle?: string;
22
+ };
23
+ events: {
24
+ [evt: string]: CustomEvent<any>;
25
+ };
26
+ slots: {
27
+ default: {};
28
+ };
29
+ exports?: {} | undefined;
30
+ bindings?: string | undefined;
31
+ };
32
+ export type PermissionListProps = typeof __propDef.props;
33
+ export type PermissionListEvents = typeof __propDef.events;
34
+ export type PermissionListSlots = typeof __propDef.slots;
35
+ export default class PermissionList extends SvelteComponent<PermissionListProps, PermissionListEvents, PermissionListSlots> {
36
+ }
37
+ export {};
@@ -0,0 +1,268 @@
1
+ <script>import { getContext } from "svelte";
2
+ import Icon from "@isoftdata/svelte-icon";
3
+ import Input from "@isoftdata/svelte-input";
4
+ import Button from "@isoftdata/svelte-button";
5
+ import TextArea from "@isoftdata/svelte-textarea";
6
+ import PasswordSetModal from "./PasswordSetModal.svelte";
7
+ import PasswordFields from "@isoftdata/svelte-password-fields";
8
+ import DeactivateUserModal from "./DeactivateUserModal.svelte";
9
+ import PasswordRecoveryModal from "./PasswordRecoveryModal.svelte";
10
+ export let userAccount;
11
+ export let icon = "user";
12
+ export let canToggleActive = true;
13
+ export let canEditAccountInfo = true;
14
+ export let isCreatingNewUser = false;
15
+ export let deactivateUser = void 0;
16
+ export let hasPermissionToChangePassword = false;
17
+ export let confirmPasswordSet = void 0;
18
+ export let accountInfoChanged = void 0;
19
+ export let error = void 0;
20
+ export let success = void 0;
21
+ export let sendPasswordRecoveryToken = void 0;
22
+ export let generateNewActivationPIN = () => Promise.resolve();
23
+ let isLoading = false;
24
+ let passwordSetModal;
25
+ let activationPINExpiration = "";
26
+ let deactivateUserModal;
27
+ let passwordRecoveryModal;
28
+ let activationPINInput;
29
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
30
+ async function getNewActivationPIN(sendEmail = false) {
31
+ let confirmationMessage = sendEmail ? translate("configuration.user.permissions.sendNewActivationPINMessage", "Are you sure you want to send a new activation PIN? The user will receive an email with the new activation PIN.") : translate("configuration.user.permissions.generateNewActivationPINMessage", "Are you sure you want to generate a new activation PIN?");
32
+ if (confirm(confirmationMessage)) {
33
+ try {
34
+ isLoading = true;
35
+ await generateNewActivationPIN(userAccount.name, !!userAccount.workEmail);
36
+ let successMessage = sendEmail ? translate("configuration.user.permissions.activationPINSent", "Email with new activation PIN has been sent successfully.") : translate("configuration.user.permissions.activationPINGenerated", "Activation PIN generated successfully.");
37
+ let successHeading = sendEmail ? translate("configuration.messageHeading.activationPINSent", "New Activation PIN Sent!") : translate("configuration.messageHeading.activationPINGenerated", "New Activation PIN Generated!");
38
+ await success?.({ heading: successHeading, message: successMessage });
39
+ isLoading = false;
40
+ await accountInfoChanged?.();
41
+ } catch (err) {
42
+ console.log(err);
43
+ if (err instanceof Error) {
44
+ await error?.({ heading: translate("configuration.messageHeading.failedToGenerateNewPIN", "Failed To Generate New PIN"), message: err.message });
45
+ }
46
+ }
47
+ }
48
+ }
49
+ async function copyTextToClipboard() {
50
+ if (activationPINInput) {
51
+ navigator.clipboard.writeText(activationPINInput.value);
52
+ await success?.({
53
+ heading: translate("configuration.messageHeading.activationPINCopied", "Activation PIN Copied!"),
54
+ message: translate("configuration.user.permissions.activationPINCopied", "Activation PIN copied to clipboard successfully.")
55
+ });
56
+ }
57
+ }
58
+ async function reactivateUserAccount() {
59
+ if (confirm(translate("configuration.user.permissions.reactivateUserConfirmation", "Are you sure you want to reactivate this user?"))) {
60
+ userAccount.status = "ACTIVE";
61
+ userAccount.lockNotes = null;
62
+ await accountInfoChanged?.();
63
+ }
64
+ }
65
+ async function deactivateUserAccount(lockNotes) {
66
+ userAccount.status = "DEACTIVATED";
67
+ userAccount.lockNotes = lockNotes;
68
+ await accountInfoChanged?.();
69
+ }
70
+ $: workEmail = userAccount.workEmail;
71
+ $: status = userAccount.status;
72
+ $: activationPIN = userAccount.activationPIN;
73
+ </script>
74
+
75
+ <div
76
+ class="card"
77
+ {...$$restProps}
78
+ >
79
+ <fieldset disabled={!canEditAccountInfo}>
80
+ <div class="card-header">
81
+ <div class="d-flex justify-content-between align-items-center">
82
+ <h5 class="mb-0">
83
+ <Icon
84
+ {icon}
85
+ class="mr-1"
86
+ />
87
+ {isCreatingNewUser ? translate('configuration.user.creatingNewAccountInfoHeader', 'New Account') : translate('configuration.user.accountInfoHeader', 'Account')}
88
+ </h5>
89
+ {#if status === 'ACTIVE'}
90
+ <Button
91
+ size="xs"
92
+ outline
93
+ color="danger"
94
+ iconClass="xmark"
95
+ on:click={() => deactivateUserModal.open(userAccount)}
96
+ disabled={!canEditAccountInfo || !canToggleActive}
97
+ >
98
+ <span>{translate('common:deactivate', 'Deactivate')}</span>
99
+ </Button>
100
+ {:else if status === 'DEACTIVATED' || status === 'LOCKED'}
101
+ <Button
102
+ size="sm"
103
+ outline
104
+ color="success"
105
+ iconClass="check"
106
+ on:click={() => reactivateUserAccount()}
107
+ disabled={!canEditAccountInfo || !canToggleActive}
108
+ >
109
+ <span>{translate('common:activate', 'Activate')}</span>
110
+ </Button>
111
+ {/if}
112
+ </div>
113
+ </div>
114
+ <div class="card-body">
115
+ <div class="form-row">
116
+ {#if !isCreatingNewUser}
117
+ {#if status === 'PENDING_ACTIVATION'}
118
+ <div class="col-12">
119
+ {#if activationPIN && workEmail}
120
+ <div class="alert alert-info mb-0">
121
+ {translate('configuration.user.accountInfo.activationPINSent', 'An activation PIN has been sent to {{email}}.', { email: workEmail })}
122
+ </div>
123
+ {:else}
124
+ <label for="activationPIN">{translate('configuration.user.activationPIN', 'Activation PIN')}</label>
125
+ <div class="input-group input-group-sm">
126
+ <input
127
+ bind:this={activationPINInput}
128
+ type="text"
129
+ class="form-control"
130
+ placeholder="###-###"
131
+ value={activationPIN}
132
+ readonly
133
+ />
134
+ <div class="input-group-append">
135
+ <!-- When this button is hit, the function will call an API endpoint that will write the new PIN into the db -->
136
+ <!-- Therefore, this button will ignore the save function, as we need the new PIN to display it here -->
137
+ <Button
138
+ size="sm"
139
+ outline
140
+ {isLoading}
141
+ iconClass="refresh"
142
+ on:click={() => getNewActivationPIN()}
143
+ title={translate('configuration.user.generateNewActivationPIN', 'Generate New PIN')}
144
+ />
145
+ <Button
146
+ size="sm"
147
+ outline
148
+ iconClass="copy"
149
+ on:click={() => copyTextToClipboard()}
150
+ disabled={!activationPIN}
151
+ title={translate('configuration.user.copyActivationPIN', 'Copy Activation PIN')}
152
+ />
153
+ </div>
154
+ </div>
155
+ {/if}
156
+ {#if activationPIN}
157
+ <small class="text-danger">{translate('configuratioin.user.activationPINExpireText', 'Activation PIN expires on')} {activationPINExpiration}</small>
158
+ {/if}
159
+ </div>
160
+ {:else}
161
+ <div class="col-12">
162
+ <Button
163
+ size="sm"
164
+ outline
165
+ iconClass="paper-plane"
166
+ on:click={() => passwordRecoveryModal.open(userAccount.recoveryEmail, userAccount.lastPasswordResetDate)}
167
+ >
168
+ {translate('configuration.user.sendResetToken', 'Send Reset Token')}...
169
+ </Button>
170
+ {#if hasPermissionToChangePassword}
171
+ <Button
172
+ size="sm"
173
+ outline
174
+ iconClass="key"
175
+ on:click={() => passwordSetModal.open(userAccount)}
176
+ >
177
+ {translate('configuration.user.setPassword', 'Set Password')}...
178
+ </Button>
179
+ {/if}
180
+ </div>
181
+ {/if}
182
+ {/if}
183
+ <div class="col-12">
184
+ <Input
185
+ id="usernameInput"
186
+ label={translate('configuration.user.accountInfo.username', 'Username')}
187
+ bind:value={userAccount.name}
188
+ maxlength={320}
189
+ required={isCreatingNewUser}
190
+ validation={{
191
+ validator: value => {
192
+ return value.length > 320 ? 'Username must be less than 320 characters.' : true
193
+ },
194
+ }}
195
+ />
196
+ </div>
197
+ <div class="col-6">
198
+ <Input
199
+ label={translate('configuration.user.accountInfo.firstName', 'First Name')}
200
+ bind:value={userAccount.firstName}
201
+ maxlength={100}
202
+ />
203
+ </div>
204
+ <div class="col-6">
205
+ <Input
206
+ label={translate('configuration.user.accountInfo.lastName', 'Last Name')}
207
+ bind:value={userAccount.lastName}
208
+ maxlength={100}
209
+ />
210
+ </div>
211
+ <div class="col-12">
212
+ <Input
213
+ label={translate('configuration.user.accountInfo.workEmail', 'Work Email')}
214
+ bind:value={userAccount.workEmail}
215
+ autocomplete="email"
216
+ type="email"
217
+ inputmode="email"
218
+ />
219
+ {#if workEmail && !isCreatingNewUser && status === 'PENDING_ACTIVATION'}
220
+ <Button
221
+ size="sm"
222
+ outline
223
+ iconClass="paper-plane"
224
+ on:click={() => getNewActivationPIN(true)}
225
+ >
226
+ {translate('configuration.user.sendNewActivationPIN', 'Send New Activation PIN')}
227
+ </Button>
228
+ {/if}
229
+ </div>
230
+ <div class="col-12">
231
+ {#if !isCreatingNewUser}
232
+ <TextArea
233
+ label={translate('configuration.user.accountInfo.lockNote', 'Lock Note')}
234
+ labelClass="py-0 mb-2"
235
+ style="min-height:83px;"
236
+ bind:value={userAccount.lockNotes}
237
+ readonly
238
+ />
239
+ {:else if hasPermissionToChangePassword}
240
+ <!-- TODO: When we migrate to Svelte 5, switch this and the other usage of PasswordFields to use a snippet-->
241
+ <PasswordFields
242
+ bind:password={userAccount.newPassword}
243
+ columnClass="col-12"
244
+ passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
245
+ confirmPasswordLabel={translate('configuration.user.accountInfo.passwordManagementModal.confirmNewPassword', 'Confirm New Password')}
246
+ />
247
+ {/if}
248
+ </div>
249
+ </div>
250
+ <slot></slot>
251
+ </div>
252
+ </fieldset>
253
+ </div>
254
+
255
+ <PasswordRecoveryModal
256
+ bind:this={passwordRecoveryModal}
257
+ {sendPasswordRecoveryToken}
258
+ />
259
+
260
+ <DeactivateUserModal
261
+ bind:this={deactivateUserModal}
262
+ {deactivateUser}
263
+ />
264
+
265
+ <PasswordSetModal
266
+ bind:this={passwordSetModal}
267
+ {confirmPasswordSet}
268
+ />
@@ -0,0 +1,39 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { UserAccount, ConfirmPasswordSetFn, DeactivateUserFn, HTMLDivAttributes, IconName } from './';
3
+ declare const __propDef: {
4
+ props: HTMLDivAttributes & {
5
+ userAccount: UserAccount;
6
+ canEditAccountInfo?: boolean;
7
+ canToggleActive?: boolean;
8
+ isCreatingNewUser?: boolean;
9
+ hasPermissionToChangePassword?: boolean;
10
+ generateNewActivationPIN?: (userName: string, hasWorkEmail: boolean) => Promise<void>;
11
+ confirmPasswordSet?: ConfirmPasswordSetFn;
12
+ deactivateUser?: DeactivateUserFn;
13
+ success?: ((info: {
14
+ heading: string;
15
+ message: string;
16
+ }) => void | Promise<void>) | undefined;
17
+ error?: ((info: {
18
+ heading: string;
19
+ message: string;
20
+ }) => void | Promise<void>) | undefined;
21
+ accountInfoChanged?: (() => void | Promise<void>) | undefined;
22
+ sendPasswordRecoveryToken?: ((email: string | undefined) => void | Promise<void>) | undefined;
23
+ icon?: IconName;
24
+ };
25
+ events: {
26
+ [evt: string]: CustomEvent<any>;
27
+ };
28
+ slots: {
29
+ default: {};
30
+ };
31
+ exports?: {} | undefined;
32
+ bindings?: string | undefined;
33
+ };
34
+ export type UserAccountInfoProps = typeof __propDef.props;
35
+ export type UserAccountInfoEvents = typeof __propDef.events;
36
+ export type UserAccountInfoSlots = typeof __propDef.slots;
37
+ export default class UserAccountInfo extends SvelteComponent<UserAccountInfoProps, UserAccountInfoEvents, UserAccountInfoSlots> {
38
+ }
39
+ export {};
@@ -0,0 +1,87 @@
1
+ <script>import UserSiteAccess from "../lib/UserSiteAccess.svelte";
2
+ import PermissionList from "../lib/PermissionList.svelte";
3
+ import UserAccountInfo from "../lib/UserAccountInfo.svelte";
4
+ import UserGroupMembership from "../lib/UserGroupMembership.svelte";
5
+ export let siteLabel = "Site";
6
+ export let userAccountInfoIcon = "user";
7
+ export let groupMembershipIcon = "users";
8
+ export let permissionListIcon = "user-lock";
9
+ export let userSiteAccessIcon = "industry-windows";
10
+ export let permissionListCardHeaderTitle = "Permissions";
11
+ export let userAccount;
12
+ export let canToggleActive = true;
13
+ export let isCreatingNewUser = false;
14
+ export let canEditAccountInfo = true;
15
+ export let hasPermissionToChangePassword = false;
16
+ export let error = void 0;
17
+ export let success = void 0;
18
+ export let deactivateUser = void 0;
19
+ export let confirmPasswordSet = void 0;
20
+ export let accountInfoChanged = void 0;
21
+ export let sendPasswordRecoveryToken = void 0;
22
+ export let generateNewActivationPIN = () => Promise.resolve();
23
+ export let userSites;
24
+ export let canEditSiteAccess = true;
25
+ export let siteAccessChange = void 0;
26
+ export let groupMembership;
27
+ export let canEditGroupMembership = true;
28
+ export let groupMembershipChange = void 0;
29
+ export let permissions;
30
+ export let permissionValueChange = void 0;
31
+ </script>
32
+
33
+ <div class="form-row">
34
+ <div class="col-12 col-lg-4 mb-2">
35
+ <UserAccountInfo
36
+ {userAccount}
37
+ {canToggleActive}
38
+ {canEditAccountInfo}
39
+ {isCreatingNewUser}
40
+ {hasPermissionToChangePassword}
41
+ {error}
42
+ {success}
43
+ {deactivateUser}
44
+ {accountInfoChanged}
45
+ {confirmPasswordSet}
46
+ {sendPasswordRecoveryToken}
47
+ {generateNewActivationPIN}
48
+ icon={userAccountInfoIcon}
49
+ style="height: 500px;"
50
+ />
51
+ </div>
52
+ <div class="col-12 col-lg-4 mb-2">
53
+ <UserSiteAccess
54
+ {siteLabel}
55
+ {userSites}
56
+ {canEditSiteAccess}
57
+ {siteAccessChange}
58
+ icon={userSiteAccessIcon}
59
+ style="height: 500px;"
60
+ >
61
+ <slot name="siteAccess"></slot>
62
+ </UserSiteAccess>
63
+ </div>
64
+ <div class="col-12 col-lg-4 mb-2">
65
+ <UserGroupMembership
66
+ {groupMembership}
67
+ {canEditGroupMembership}
68
+ {groupMembershipChange}
69
+ icon={groupMembershipIcon}
70
+ style="height: 500px;"
71
+ >
72
+ <slot name="userGroupMembership"></slot>
73
+ </UserGroupMembership>
74
+ </div>
75
+ </div>
76
+ <div class="form-row">
77
+ <div class="col-12">
78
+ <PermissionList
79
+ {permissions}
80
+ {permissionValueChange}
81
+ icon={permissionListIcon}
82
+ cardHeaderTitle={permissionListCardHeaderTitle}
83
+ >
84
+ <slot name="permissionList"></slot>
85
+ </PermissionList>
86
+ </div>
87
+ </div>
@@ -0,0 +1,48 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ErrorFn, IconName, UserSites, SuccessFn, SiteLabel, UserAccount, Permissions, GroupMembership, CanToggleActive, DeactivateUserFn, CanEditSiteAccess, IsCreatingNewUser, SiteAccessChangeFn, CanEditAccountInfo, ConfirmPasswordSetFn, AccountInfoChangedFn, CanEditGroupMembership, GroupMembershipChangeFn, PermissionValueChangeFn, GenerateNewActivationPINFn, SendPasswordRecoveryTokenFn, HasPermissionToChangePassword, PermissionListCardHeaderTitle } from '../lib/util';
3
+ declare const __propDef: {
4
+ props: {
5
+ siteLabel?: SiteLabel;
6
+ userAccountInfoIcon?: IconName;
7
+ groupMembershipIcon?: IconName;
8
+ permissionListIcon?: IconName;
9
+ userSiteAccessIcon?: IconName;
10
+ permissionListCardHeaderTitle?: PermissionListCardHeaderTitle;
11
+ userAccount: UserAccount;
12
+ canToggleActive?: CanToggleActive;
13
+ isCreatingNewUser?: IsCreatingNewUser;
14
+ canEditAccountInfo?: CanEditAccountInfo;
15
+ hasPermissionToChangePassword?: HasPermissionToChangePassword;
16
+ error?: ErrorFn;
17
+ success?: SuccessFn;
18
+ deactivateUser?: DeactivateUserFn;
19
+ confirmPasswordSet?: ConfirmPasswordSetFn;
20
+ accountInfoChanged?: AccountInfoChangedFn;
21
+ sendPasswordRecoveryToken?: SendPasswordRecoveryTokenFn;
22
+ generateNewActivationPIN?: GenerateNewActivationPINFn;
23
+ userSites: UserSites;
24
+ canEditSiteAccess?: CanEditSiteAccess;
25
+ siteAccessChange?: SiteAccessChangeFn;
26
+ groupMembership: GroupMembership;
27
+ canEditGroupMembership?: CanEditGroupMembership;
28
+ groupMembershipChange?: GroupMembershipChangeFn;
29
+ permissions: Permissions;
30
+ permissionValueChange?: PermissionValueChangeFn;
31
+ };
32
+ events: {
33
+ [evt: string]: CustomEvent<any>;
34
+ };
35
+ slots: {
36
+ siteAccess: {};
37
+ userGroupMembership: {};
38
+ permissionList: {};
39
+ };
40
+ exports?: {} | undefined;
41
+ bindings?: string | undefined;
42
+ };
43
+ export type UserConfigurationProps = typeof __propDef.props;
44
+ export type UserConfigurationEvents = typeof __propDef.events;
45
+ export type UserConfigurationSlots = typeof __propDef.slots;
46
+ export default class UserConfiguration extends SvelteComponent<UserConfigurationProps, UserConfigurationEvents, UserConfigurationSlots> {
47
+ }
48
+ export {};
@@ -0,0 +1,39 @@
1
+ <script>import { getContext } from "svelte";
2
+ import Icon from "@isoftdata/svelte-icon";
3
+ import Checkbox from "@isoftdata/svelte-checkbox";
4
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
5
+ export let groupMembership;
6
+ export let canEditGroupMembership = true;
7
+ export let groupMembershipChange = void 0;
8
+ export let icon = "users";
9
+ </script>
10
+
11
+ <div
12
+ class="card"
13
+ {...$$restProps}
14
+ >
15
+ <div class="card-header">
16
+ <h5 class="mb-0">
17
+ <Icon {icon} />
18
+ {translate('configuration.user.groupMembership', 'Group Membership')}
19
+ </h5>
20
+ </div>
21
+ <ul
22
+ class="list-group list-group-flush h-100"
23
+ style="overflow-y: auto;"
24
+ >
25
+ {#each groupMembership as { name, isMember }, i}
26
+ <li class="list-group-item">
27
+ <Checkbox
28
+ label={name}
29
+ bind:checked={isMember}
30
+ disabled={!canEditGroupMembership}
31
+ on:change={async () => {
32
+ await groupMembershipChange?.({ id: i, name, isMember })
33
+ }}
34
+ />
35
+ </li>
36
+ {/each}
37
+ </ul>
38
+ <slot></slot>
39
+ </div>
@@ -0,0 +1,32 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { IconName, HTMLDivAttributes } from './';
3
+ declare const __propDef: {
4
+ props: HTMLDivAttributes & {
5
+ groupMembership: Array<{
6
+ id: number;
7
+ name: string;
8
+ isMember: boolean;
9
+ }>;
10
+ canEditGroupMembership?: boolean;
11
+ groupMembershipChange?: ((groupMembership: {
12
+ id: number;
13
+ name: string;
14
+ isMember: boolean;
15
+ }) => void | Promise<void>) | undefined;
16
+ icon?: IconName;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {
22
+ default: {};
23
+ };
24
+ exports?: {} | undefined;
25
+ bindings?: string | undefined;
26
+ };
27
+ export type UserGroupMembershipProps = typeof __propDef.props;
28
+ export type UserGroupMembershipEvents = typeof __propDef.events;
29
+ export type UserGroupMembershipSlots = typeof __propDef.slots;
30
+ export default class UserGroupMembership extends SvelteComponent<UserGroupMembershipProps, UserGroupMembershipEvents, UserGroupMembershipSlots> {
31
+ }
32
+ export {};
@@ -0,0 +1,37 @@
1
+ <script>import { getContext } from "svelte";
2
+ import Checkbox from "@isoftdata/svelte-checkbox";
3
+ import Icon from "@isoftdata/svelte-icon";
4
+ const { t: translate } = getContext("i18next") || { t: (_key, fallback) => fallback };
5
+ export let userSites;
6
+ export let siteLabel = "Site";
7
+ export let canEditSiteAccess = true;
8
+ export let siteAccessChange = void 0;
9
+ export let icon = "industry-windows";
10
+ </script>
11
+
12
+ <div
13
+ class="card"
14
+ {...$$restProps}
15
+ >
16
+ <div class="card-header">
17
+ <h5 class="mb-0"><Icon {icon} /> {translate(`user.configuration.${siteLabel}Access`, `${siteLabel} Access`)}</h5>
18
+ </div>
19
+ <ul
20
+ class="list-group list-group-flush h-100"
21
+ style="overflow-y: auto"
22
+ >
23
+ {#each userSites as { code, name }, i}
24
+ <li class="list-group-item">
25
+ <Checkbox
26
+ label="{code} - {name}"
27
+ bind:checked={userSites[i].isAuthorized}
28
+ disabled={!canEditSiteAccess}
29
+ on:change={async () => {
30
+ await siteAccessChange?.(userSites[i])
31
+ }}
32
+ />
33
+ </li>
34
+ {/each}
35
+ </ul>
36
+ <slot></slot>
37
+ </div>
@@ -0,0 +1,33 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { IconName, HTMLDivAttributes, SiteLabel } from './';
3
+ declare const __propDef: {
4
+ props: HTMLDivAttributes & {
5
+ userSites: Array<{
6
+ code: string;
7
+ name: string;
8
+ isAuthorized: boolean;
9
+ }>;
10
+ siteLabel?: SiteLabel;
11
+ canEditSiteAccess?: boolean;
12
+ siteAccessChange?: ((siteAccess: {
13
+ code: string;
14
+ name: string;
15
+ isAuthorized: boolean;
16
+ }) => void | Promise<void>) | undefined;
17
+ icon?: IconName;
18
+ };
19
+ events: {
20
+ [evt: string]: CustomEvent<any>;
21
+ };
22
+ slots: {
23
+ default: {};
24
+ };
25
+ exports?: {} | undefined;
26
+ bindings?: string | undefined;
27
+ };
28
+ export type UserSiteAccessProps = typeof __propDef.props;
29
+ export type UserSiteAccessEvents = typeof __propDef.events;
30
+ export type UserSiteAccessSlots = typeof __propDef.slots;
31
+ export default class UserSiteAccess extends SvelteComponent<UserSiteAccessProps, UserSiteAccessEvents, UserSiteAccessSlots> {
32
+ }
33
+ export {};
@@ -0,0 +1,7 @@
1
+ export { default as default, default as UserConfiguration } from './UserConfiguration.svelte';
2
+ export { default as UserAccountInfo } from './UserAccountInfo.svelte';
3
+ export { default as UserGroupMembership } from './UserGroupMembership.svelte';
4
+ export { default as PermissionList } from './PermissionList.svelte';
5
+ export { default as UserSiteAccess } from './UserSiteAccess.svelte';
6
+ export * from './util';
7
+ export type * from './util';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { default as default, default as UserConfiguration } from './UserConfiguration.svelte';
2
+ export { default as UserAccountInfo } from './UserAccountInfo.svelte';
3
+ export { default as UserGroupMembership } from './UserGroupMembership.svelte';
4
+ export { default as PermissionList } from './PermissionList.svelte';
5
+ export { default as UserSiteAccess } from './UserSiteAccess.svelte';
6
+ export * from './util';
package/dist/util.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { ComponentProps } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import DeactivateUserModal from './DeactivateUserModal.svelte';
4
+ import PasswordSetModal from './PasswordSetModal.svelte';
5
+ import UserAccountInfo from './UserAccountInfo.svelte';
6
+ import UserSiteAccess from './UserSiteAccess.svelte';
7
+ import UserGroupMembership from './UserGroupMembership.svelte';
8
+ import type PermissionList from './PermissionList.svelte';
9
+ export interface UserAccount {
10
+ id: number;
11
+ name: string;
12
+ workEmail: string;
13
+ firstName: string;
14
+ lastName: string;
15
+ lockNotes: string | null;
16
+ recoveryEmail: string;
17
+ activationPIN: string;
18
+ status: 'ACTIVE' | 'DEACTIVATED' | 'LOCKED' | 'PENDING_ACTIVATION';
19
+ newPassword?: string;
20
+ lastPasswordResetDate?: Date;
21
+ lastAccessDate?: Date;
22
+ }
23
+ export type { IconName } from '@fortawesome/fontawesome-common-types';
24
+ export type HTMLDivAttributes = HTMLAttributes<HTMLDivElement>;
25
+ export type SiteLabel = string;
26
+ export type GenerateNewActivationPINFn = ComponentProps<UserAccountInfo>['generateNewActivationPIN'];
27
+ export type SuccessFn = ComponentProps<UserAccountInfo>['success'];
28
+ export type ErrorFn = ComponentProps<UserAccountInfo>['error'];
29
+ export type AccountInfoChangedFn = ComponentProps<UserAccountInfo>['accountInfoChanged'];
30
+ export type SendPasswordRecoveryTokenFn = ComponentProps<UserAccountInfo>['sendPasswordRecoveryToken'];
31
+ export type CanEditAccountInfo = ComponentProps<UserAccountInfo>['canEditAccountInfo'];
32
+ export type CanToggleActive = ComponentProps<UserAccountInfo>['canToggleActive'];
33
+ export type IsCreatingNewUser = ComponentProps<UserAccountInfo>['isCreatingNewUser'];
34
+ export type HasPermissionToChangePassword = ComponentProps<UserAccountInfo>['hasPermissionToChangePassword'];
35
+ export type ConfirmPasswordSetFn = ComponentProps<PasswordSetModal>['confirmPasswordSet'];
36
+ export type DeactivateUserFn = ComponentProps<DeactivateUserModal>['deactivateUser'];
37
+ export type UserSites = ComponentProps<UserSiteAccess>['userSites'];
38
+ export type CanEditSiteAccess = ComponentProps<UserSiteAccess>['canEditSiteAccess'];
39
+ export type SiteAccessChangeFn = ComponentProps<UserSiteAccess>['siteAccessChange'];
40
+ export type GroupMembership = ComponentProps<UserGroupMembership>['groupMembership'];
41
+ export type GroupMembershipChangeFn = ComponentProps<UserGroupMembership>['groupMembershipChange'];
42
+ export type CanEditGroupMembership = ComponentProps<UserGroupMembership>['canEditGroupMembership'];
43
+ export type Permissions = ComponentProps<PermissionList>['permissions'];
44
+ export type PermissionValueChangeFn = ComponentProps<PermissionList>['permissionValueChange'];
45
+ export type PermissionListCardHeaderTitle = ComponentProps<PermissionList>['cardHeaderTitle'];
package/dist/util.js ADDED
@@ -0,0 +1,5 @@
1
+ import DeactivateUserModal from './DeactivateUserModal.svelte';
2
+ import PasswordSetModal from './PasswordSetModal.svelte';
3
+ import UserAccountInfo from './UserAccountInfo.svelte';
4
+ import UserSiteAccess from './UserSiteAccess.svelte';
5
+ import UserGroupMembership from './UserGroupMembership.svelte';
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@isoftdata/svelte-user-configuration",
3
+ "version": "1.0.0",
4
+ "scripts": {
5
+ "dev": "vite dev",
6
+ "build": "vite build && npm run package",
7
+ "preview": "vite preview",
8
+ "package": "svelte-kit sync && svelte-package && publint",
9
+ "prepublishOnly": "npm run package",
10
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
+ "lint": "prettier --check . && eslint .",
13
+ "format": "prettier --write ."
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "svelte": "./dist/index.js"
19
+ }
20
+ },
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "files": [
25
+ "dist",
26
+ "!dist/**/*.test.*",
27
+ "!dist/**/*.spec.*"
28
+ ],
29
+ "peerDependencies": {
30
+ "svelte": "^4.0.0 || ^5.16.3"
31
+ },
32
+ "devDependencies": {
33
+ "@fortawesome/fontawesome-common-types": "^6.7.2",
34
+ "@isoftdata/prettier-config": "^1.0.3",
35
+ "@sveltejs/adapter-auto": "^3.0.0",
36
+ "@sveltejs/kit": "^2.0.0",
37
+ "@sveltejs/package": "^2.0.0",
38
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
39
+ "@types/eslint": "^9.6.0",
40
+ "eslint": "^9.0.0",
41
+ "eslint-config-prettier": "^9.1.0",
42
+ "eslint-plugin-svelte": "^2.36.0",
43
+ "globals": "^15.0.0",
44
+ "i18next": "^24.2.1",
45
+ "prettier": "^3.1.1",
46
+ "prettier-plugin-svelte": "^3.1.2",
47
+ "publint": "^0.2.0",
48
+ "svelte": "^4.2.7",
49
+ "svelte-check": "^4.0.0",
50
+ "type-fest": "^4.33.0",
51
+ "typescript": "^5.0.0",
52
+ "typescript-eslint": "^8.0.0",
53
+ "vite": "^5.0.11"
54
+ },
55
+ "svelte": "./dist/index.js",
56
+ "types": "./dist/index.d.ts",
57
+ "type": "module",
58
+ "prettier": "@isoftdata/prettier-config",
59
+ "dependencies": {
60
+ "@isoftdata/browser-event": "^2.3.2",
61
+ "@isoftdata/svelte-button": "^1.4.1",
62
+ "@isoftdata/svelte-checkbox": "^1.5.1",
63
+ "@isoftdata/svelte-input": "^1.6.0",
64
+ "@isoftdata/svelte-modal": "^1.3.1",
65
+ "@isoftdata/svelte-password-fields": "^1.3.0",
66
+ "@isoftdata/svelte-select": "^1.5.0",
67
+ "@isoftdata/svelte-table": "^1.16.0",
68
+ "@isoftdata/svelte-textarea": "^1.2.0",
69
+ "just-camel-case": "^6.2.0",
70
+ "klona": "^2.0.6"
71
+ }
72
+ }