@isoftdata/svelte-user-configuration 2.3.3 → 2.4.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 +162 -162
- package/dist/DeactivateUserModal.svelte +59 -59
- package/dist/PasswordRecoveryModal.svelte +83 -83
- package/dist/PasswordSetModal.svelte +127 -127
- package/dist/PermissionList.svelte +312 -312
- package/dist/UserAccountInfo.svelte +447 -445
- package/dist/UserAccountInfo.svelte.d.ts +1 -0
- package/dist/UserConfiguration.svelte +3 -0
- package/dist/UserConfiguration.svelte.d.ts +1 -0
- package/dist/UserGroupMembership.svelte +64 -64
- package/dist/UserSiteAccess.svelte +65 -65
- package/package.json +2 -2
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { i18n } from 'i18next'
|
|
3
|
-
import type { UserAccount, PasswordValidationRules } from './'
|
|
4
|
-
|
|
5
|
-
import { klona } from 'klona'
|
|
6
|
-
import { tick, getContext } from 'svelte'
|
|
7
|
-
import Input from '@isoftdata/svelte-input'
|
|
8
|
-
import Modal from '@isoftdata/svelte-modal'
|
|
9
|
-
import PasswordFields from '@isoftdata/svelte-password-fields'
|
|
10
|
-
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
11
|
-
|
|
12
|
-
let show: boolean = $state(false)
|
|
13
|
-
let currentPassword: string = $state('')
|
|
14
|
-
let newPassword: string = $state('')
|
|
15
|
-
let confirmPassword: string = $state('')
|
|
16
|
-
let lastResetDate: Date | null | undefined = $state(undefined)
|
|
17
|
-
let currentPasswordInput: HTMLInputElement | undefined = $state(undefined)
|
|
18
|
-
let newPasswordInput: HTMLInputElement | undefined = $state(undefined)
|
|
19
|
-
let passwordRecoveryEmail: string | null | undefined = $state(undefined)
|
|
20
|
-
let passwordIsValid: boolean = $state(false)
|
|
21
|
-
|
|
22
|
-
interface Props {
|
|
23
|
-
validationRules?: PasswordValidationRules | undefined
|
|
24
|
-
changePasswordMode?: boolean
|
|
25
|
-
confirmPasswordSet: (ctx: { currentPassword: string; newPassword: string }) => void | Promise<void>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let { validationRules = undefined, changePasswordMode = false, confirmPasswordSet }: Props = $props()
|
|
29
|
-
export async function open(userAccount?: UserAccount) {
|
|
30
|
-
currentPassword = ''
|
|
31
|
-
newPassword = ''
|
|
32
|
-
confirmPassword = ''
|
|
33
|
-
lastResetDate = klona(userAccount?.lastPasswordResetDate) // Don't mutate the given Date obj
|
|
34
|
-
passwordRecoveryEmail = userAccount?.recoveryEmail
|
|
35
|
-
show = true
|
|
36
|
-
await tick()
|
|
37
|
-
|
|
38
|
-
if (changePasswordMode) {
|
|
39
|
-
currentPasswordInput?.focus()
|
|
40
|
-
} else {
|
|
41
|
-
newPasswordInput?.focus()
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
46
|
-
|
|
47
|
-
// The passwordMismatch prop from the PasswordFields component only updates on:change,
|
|
48
|
-
// but we want the component consumer to be able to update their save button disabled state in real time
|
|
49
|
-
let passwordMismatch: boolean = $derived(!(newPassword && confirmPassword && newPassword === confirmPassword))
|
|
50
|
-
let disablePasswordChange: boolean = $derived(
|
|
51
|
-
(changePasswordMode && !currentPassword) ||
|
|
52
|
-
passwordMismatch ||
|
|
53
|
-
!newPassword ||
|
|
54
|
-
!confirmPassword ||
|
|
55
|
-
!passwordIsValid,
|
|
56
|
-
)
|
|
57
|
-
</script>
|
|
58
|
-
|
|
59
|
-
<Modal
|
|
60
|
-
bind:show
|
|
61
|
-
title={changePasswordMode
|
|
62
|
-
? translate('configuration.user.changePassword', 'Change Password')
|
|
63
|
-
: translate('configuration.user.setPassword', 'Set Password')}
|
|
64
|
-
confirmButtonText={changePasswordMode
|
|
65
|
-
? translate('configuration.user.changePassword', 'Change Password')
|
|
66
|
-
: translate('configuration.user.setPassword', 'Set Password')}
|
|
67
|
-
confirmButtonIcon="check"
|
|
68
|
-
confirmButtonDisabled={disablePasswordChange}
|
|
69
|
-
close={() => (show = false)}
|
|
70
|
-
confirmButtonType="submit"
|
|
71
|
-
confirmButtonFormId="setPasswordForm"
|
|
72
|
-
>
|
|
73
|
-
<form
|
|
74
|
-
id="setPasswordForm"
|
|
75
|
-
onsubmit={async e => {
|
|
76
|
-
e.preventDefault()
|
|
77
|
-
if (!disablePasswordChange) {
|
|
78
|
-
await confirmPasswordSet({ currentPassword, newPassword })
|
|
79
|
-
show = false
|
|
80
|
-
}
|
|
81
|
-
}}
|
|
82
|
-
>
|
|
83
|
-
<Input
|
|
84
|
-
label={translate(
|
|
85
|
-
'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
|
|
86
|
-
'Last Password Set Date',
|
|
87
|
-
)}
|
|
88
|
-
tabindex={-1}
|
|
89
|
-
value={lastResetDate ? lastResetDate.toLocaleString() : ''}
|
|
90
|
-
labelParentClass="form-group mb-0"
|
|
91
|
-
readonly
|
|
92
|
-
/>
|
|
93
|
-
{#if changePasswordMode}
|
|
94
|
-
<Input
|
|
95
|
-
bind:input={currentPasswordInput}
|
|
96
|
-
label={translate('configuration.user.accountInfo.passwordManagementModal.currentPassword', 'Current Password')}
|
|
97
|
-
type="password"
|
|
98
|
-
bind:value={currentPassword}
|
|
99
|
-
autocomplete="current-password"
|
|
100
|
-
required
|
|
101
|
-
class={!currentPassword ? 'is-invalid' : ''}
|
|
102
|
-
/>
|
|
103
|
-
<hr />
|
|
104
|
-
{/if}
|
|
105
|
-
<PasswordFields
|
|
106
|
-
bind:password={newPassword}
|
|
107
|
-
bind:confirmPassword
|
|
108
|
-
bind:passwordInput={newPasswordInput}
|
|
109
|
-
bind:passwordIsValid
|
|
110
|
-
columnClass="col-12"
|
|
111
|
-
{validationRules}
|
|
112
|
-
passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
|
|
113
|
-
confirmPasswordLabel={translate(
|
|
114
|
-
'configuration.user.accountInfo.passwordManagementModal.confirmNewPassword',
|
|
115
|
-
'Confirm New Password',
|
|
116
|
-
)}
|
|
117
|
-
/>
|
|
118
|
-
{#if !passwordRecoveryEmail}
|
|
119
|
-
<div class="alert alert-danger mt-3 mb-0">
|
|
120
|
-
{translate(
|
|
121
|
-
'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
|
|
122
|
-
'No recovery email has been set for this user.',
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
{/if}
|
|
126
|
-
</form>
|
|
127
|
-
</Modal>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { i18n } from 'i18next'
|
|
3
|
+
import type { UserAccount, PasswordValidationRules } from './'
|
|
4
|
+
|
|
5
|
+
import { klona } from 'klona'
|
|
6
|
+
import { tick, getContext } from 'svelte'
|
|
7
|
+
import Input from '@isoftdata/svelte-input'
|
|
8
|
+
import Modal from '@isoftdata/svelte-modal'
|
|
9
|
+
import PasswordFields from '@isoftdata/svelte-password-fields'
|
|
10
|
+
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
11
|
+
|
|
12
|
+
let show: boolean = $state(false)
|
|
13
|
+
let currentPassword: string = $state('')
|
|
14
|
+
let newPassword: string = $state('')
|
|
15
|
+
let confirmPassword: string = $state('')
|
|
16
|
+
let lastResetDate: Date | null | undefined = $state(undefined)
|
|
17
|
+
let currentPasswordInput: HTMLInputElement | undefined = $state(undefined)
|
|
18
|
+
let newPasswordInput: HTMLInputElement | undefined = $state(undefined)
|
|
19
|
+
let passwordRecoveryEmail: string | null | undefined = $state(undefined)
|
|
20
|
+
let passwordIsValid: boolean = $state(false)
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
validationRules?: PasswordValidationRules | undefined
|
|
24
|
+
changePasswordMode?: boolean
|
|
25
|
+
confirmPasswordSet: (ctx: { currentPassword: string; newPassword: string }) => void | Promise<void>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let { validationRules = undefined, changePasswordMode = false, confirmPasswordSet }: Props = $props()
|
|
29
|
+
export async function open(userAccount?: UserAccount) {
|
|
30
|
+
currentPassword = ''
|
|
31
|
+
newPassword = ''
|
|
32
|
+
confirmPassword = ''
|
|
33
|
+
lastResetDate = klona(userAccount?.lastPasswordResetDate) // Don't mutate the given Date obj
|
|
34
|
+
passwordRecoveryEmail = userAccount?.recoveryEmail
|
|
35
|
+
show = true
|
|
36
|
+
await tick()
|
|
37
|
+
|
|
38
|
+
if (changePasswordMode) {
|
|
39
|
+
currentPasswordInput?.focus()
|
|
40
|
+
} else {
|
|
41
|
+
newPasswordInput?.focus()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
46
|
+
|
|
47
|
+
// The passwordMismatch prop from the PasswordFields component only updates on:change,
|
|
48
|
+
// but we want the component consumer to be able to update their save button disabled state in real time
|
|
49
|
+
let passwordMismatch: boolean = $derived(!(newPassword && confirmPassword && newPassword === confirmPassword))
|
|
50
|
+
let disablePasswordChange: boolean = $derived(
|
|
51
|
+
(changePasswordMode && !currentPassword) ||
|
|
52
|
+
passwordMismatch ||
|
|
53
|
+
!newPassword ||
|
|
54
|
+
!confirmPassword ||
|
|
55
|
+
!passwordIsValid,
|
|
56
|
+
)
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<Modal
|
|
60
|
+
bind:show
|
|
61
|
+
title={changePasswordMode
|
|
62
|
+
? translate('configuration.user.changePassword', 'Change Password')
|
|
63
|
+
: translate('configuration.user.setPassword', 'Set Password')}
|
|
64
|
+
confirmButtonText={changePasswordMode
|
|
65
|
+
? translate('configuration.user.changePassword', 'Change Password')
|
|
66
|
+
: translate('configuration.user.setPassword', 'Set Password')}
|
|
67
|
+
confirmButtonIcon="check"
|
|
68
|
+
confirmButtonDisabled={disablePasswordChange}
|
|
69
|
+
close={() => (show = false)}
|
|
70
|
+
confirmButtonType="submit"
|
|
71
|
+
confirmButtonFormId="setPasswordForm"
|
|
72
|
+
>
|
|
73
|
+
<form
|
|
74
|
+
id="setPasswordForm"
|
|
75
|
+
onsubmit={async e => {
|
|
76
|
+
e.preventDefault()
|
|
77
|
+
if (!disablePasswordChange) {
|
|
78
|
+
await confirmPasswordSet({ currentPassword, newPassword })
|
|
79
|
+
show = false
|
|
80
|
+
}
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<Input
|
|
84
|
+
label={translate(
|
|
85
|
+
'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
|
|
86
|
+
'Last Password Set Date',
|
|
87
|
+
)}
|
|
88
|
+
tabindex={-1}
|
|
89
|
+
value={lastResetDate ? lastResetDate.toLocaleString() : ''}
|
|
90
|
+
labelParentClass="form-group mb-0"
|
|
91
|
+
readonly
|
|
92
|
+
/>
|
|
93
|
+
{#if changePasswordMode}
|
|
94
|
+
<Input
|
|
95
|
+
bind:input={currentPasswordInput}
|
|
96
|
+
label={translate('configuration.user.accountInfo.passwordManagementModal.currentPassword', 'Current Password')}
|
|
97
|
+
type="password"
|
|
98
|
+
bind:value={currentPassword}
|
|
99
|
+
autocomplete="current-password"
|
|
100
|
+
required
|
|
101
|
+
class={!currentPassword ? 'is-invalid' : ''}
|
|
102
|
+
/>
|
|
103
|
+
<hr />
|
|
104
|
+
{/if}
|
|
105
|
+
<PasswordFields
|
|
106
|
+
bind:password={newPassword}
|
|
107
|
+
bind:confirmPassword
|
|
108
|
+
bind:passwordInput={newPasswordInput}
|
|
109
|
+
bind:passwordIsValid
|
|
110
|
+
columnClass="col-12"
|
|
111
|
+
{validationRules}
|
|
112
|
+
passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
|
|
113
|
+
confirmPasswordLabel={translate(
|
|
114
|
+
'configuration.user.accountInfo.passwordManagementModal.confirmNewPassword',
|
|
115
|
+
'Confirm New Password',
|
|
116
|
+
)}
|
|
117
|
+
/>
|
|
118
|
+
{#if !passwordRecoveryEmail}
|
|
119
|
+
<div class="alert alert-danger mt-3 mb-0">
|
|
120
|
+
{translate(
|
|
121
|
+
'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
|
|
122
|
+
'No recovery email has been set for this user.',
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
{/if}
|
|
126
|
+
</form>
|
|
127
|
+
</Modal>
|