@isoftdata/svelte-user-configuration 2.3.2 → 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 -304
- package/dist/PermissionList.svelte.d.ts +1 -0
- package/dist/UserAccountInfo.svelte +447 -445
- package/dist/UserAccountInfo.svelte.d.ts +1 -0
- package/dist/UserConfiguration.svelte +6 -0
- package/dist/UserConfiguration.svelte.d.ts +2 -0
- package/dist/UserGroupMembership.svelte +64 -64
- package/dist/UserSiteAccess.svelte +65 -65
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
# Svelte UserConfiguration
|
|
2
|
-
|
|
3
|
-
This Svelte component provides a user configuration interface, including user account details, site access, group membership, and permissions.
|
|
4
|
-
|
|
5
|
-

|
|
6
|
-

|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
pnpm i @isoftdata/svelte-user-configuration
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Breaking changes
|
|
14
|
-
|
|
15
|
-
### 2.0.0
|
|
16
|
-
- Require Svelte 5
|
|
17
|
-
- Slots -> Snippets
|
|
18
|
-
- Events -> Callbacks
|
|
19
|
-
|
|
20
|
-
## Props
|
|
21
|
-
|
|
22
|
-
### User Account Properties
|
|
23
|
-
|
|
24
|
-
| Prop | Type | Required | Default | Description |
|
|
25
|
-
|------|------|----------|---------|-------------|
|
|
26
|
-
| `userAccount` | `UserAccount` | ✅ | - | The user account information. |
|
|
27
|
-
| `canToggleActive` | boolean | ❌ | `true` | Whether the user can be activated/deactivated. |
|
|
28
|
-
| `canEditAccountInfo` | boolean | ❌ | `true` | Whether account details can be edited. |
|
|
29
|
-
| `doSendPasswordRecoveryToken` | boolean | ❌ | `false` | Whether to allow sending password recovery tokens. |
|
|
30
|
-
| `hasPermissionToChangePassword` | boolean | ❌ | `false` | Whether the user has permission to change passwords. |
|
|
31
|
-
| `myAccountMode` | boolean | ❌ | `false` | When `true`, admin controls will be hidden/disabled. This is designed to be used when using the user account info component standalone so the current session user can edit their own account info, including first & last name, password recovery email, & password. |
|
|
32
|
-
| `passwordValidationRules` | `validationRules` of the [PasswordFields](<https://github.com/ISoft-Data-Systems/svelte-component-password-fields>) component | ❌ | `undefined` | Passwords rules to be enforced during password change. |
|
|
33
|
-
|
|
34
|
-
> The `passwordValidationRules` prop will be used during password setting when `hasPermissionToChangePassword` or `myAccountMode` are `true` .
|
|
35
|
-
|
|
36
|
-
### Site Access Properties
|
|
37
|
-
|
|
38
|
-
| Prop | Type | Required | Default | Description |
|
|
39
|
-
|------|------|----------|---------|-------------|
|
|
40
|
-
| `userSites` | `UserSites` | ✅ | - | List of sites the user has access to. |
|
|
41
|
-
| `canEditSiteAccess` | boolean | ❌ | `true` | Whether site access can be edited. |
|
|
42
|
-
|
|
43
|
-
### Group Membership Properties
|
|
44
|
-
|
|
45
|
-
| Prop | Type | Required | Default | Description |
|
|
46
|
-
|------|------|----------|---------|-------------|
|
|
47
|
-
| `groupMembership` | `GroupMembership` | ✅ | - | The user's group membership information. |
|
|
48
|
-
| `canEditGroupMembership` | boolean | ❌ | `true` | Whether group memberships can be edited. |
|
|
49
|
-
|
|
50
|
-
### Permission List Properties
|
|
51
|
-
|
|
52
|
-
| Prop | Type | Required | Default | Description |
|
|
53
|
-
|------|------|----------|---------|-------------|
|
|
54
|
-
| `permissions` | `Permissions` | ✅ | - | The list of permissions for the user. |
|
|
55
|
-
| `permissionValueMap` | `PermissionValueMap` | ✅ | `new SvelteMap()` | A mapping of permissions to their values. **Note this *must* be a `SvelteMap`** or reactivity will not work. |
|
|
56
|
-
| `groupPermissionValueMap` | `GroupPermissionValueMap` | ❌ | `undefined` | A mapping of group-based permissions. |
|
|
57
|
-
|
|
58
|
-
### Other Properties
|
|
59
|
-
|
|
60
|
-
| Prop | Type | Required | Default | Description |
|
|
61
|
-
|------|------|----------|---------|-------------|
|
|
62
|
-
| `siteLabel` | `SiteLabel` | ❌ | `"Site"` | Label for the site. |
|
|
63
|
-
| `showSiteAccess` | boolean | ❌ | `true` | Whether the site access section is shown. |
|
|
64
|
-
| `userAccountInfoIcon` | `IconName` | ❌ | `"user"` | Icon for the user account section. |
|
|
65
|
-
| `groupMembershipIcon` | `IconName` | ❌ | `"users"` | Icon for the group membership section. |
|
|
66
|
-
| `permissionListIcon` | `IconName` | ❌ | `"user-lock"` | Icon for the permission list section. |
|
|
67
|
-
| `userSiteAccessIcon` | `IconName` | ❌ | `"industry-windows"` | Icon for the site access section. |
|
|
68
|
-
| `permissionListCardHeaderTitle` | `PermissionListCardHeaderTitle` | ❌ | `"Permissions"` | Title for the permission list card header. |
|
|
69
|
-
| `usernameInput` | `HTMLInputElement \| undefined` | ❌ | `undefined` | Reference to the username input element. |
|
|
70
|
-
|
|
71
|
-
### Callbacks
|
|
72
|
-
|
|
73
|
-
| Prop | Type | Description |
|
|
74
|
-
|------|------|-------------|
|
|
75
|
-
| `error` | `ErrorFn` | Callback for handling errors. |
|
|
76
|
-
| `success` | `SuccessFn` | Callback for handling success messages. |
|
|
77
|
-
| `deactivateUser` | `DeactivateUserFn` | Function to deactivate a user. |
|
|
78
|
-
| `confirmPasswordSet` | `ConfirmPasswordSetFn` | Function called when a password is set. |
|
|
79
|
-
| `accountInfoChanged` | `AccountInfoChangedFn` | Function called when account info changes. |
|
|
80
|
-
| `sendPasswordRecoveryToken` | `SendPasswordRecoveryTokenFn` | Function to send password recovery token. |
|
|
81
|
-
| `generateNewActivationPIN` | `GenerateNewActivationPINFn` | Function to generate a new activation PIN. |
|
|
82
|
-
| `permissionValueChange` | `PermissionValueChangeFn` | Function called when permissions change. |
|
|
83
|
-
| `siteAccessChange` | `SiteAccessChangeFn` | Function called when site access is changed. |
|
|
84
|
-
| `groupMembershipChange` | `GroupMembershipChangeFn` | Function called when group membership changes. |
|
|
85
|
-
|
|
86
|
-
## Snippets
|
|
87
|
-
This component provides snippets for injecting additional content.
|
|
88
|
-
|
|
89
|
-
| Snippet Name | Description |
|
|
90
|
-
|-----------|-------------|
|
|
91
|
-
| `userAccountInfo` | Slot at the end of the `userAccountInfo` component's card body |
|
|
92
|
-
| `siteAccess` | Slot at the end of the `siteAccess` component's card body |
|
|
93
|
-
| `userGroupMembership` | Slot at the end of the `userGroupMembership` component's card body |
|
|
94
|
-
| `permissionList` | Slot at the end of the `permissionList` component's card body |
|
|
95
|
-
|
|
96
|
-
## Usage Example in Svelte 5 w/ Runes
|
|
97
|
-
|
|
98
|
-
```svelte
|
|
99
|
-
<script lang="ts">
|
|
100
|
-
import { UserConfiguration, getGroupHighestPermissionValueMap } from '@isoftdata/svelte-user-configuration'
|
|
101
|
-
|
|
102
|
-
interface Props {
|
|
103
|
-
plants: PlantsForDropdown$result['plants']['data']
|
|
104
|
-
groups: Array<Group>
|
|
105
|
-
permissions: UserConfigurationData$result['permissions']['data']
|
|
106
|
-
userAccount: UserAccount
|
|
107
|
-
permissionValueMap?: PermissionValueMap
|
|
108
|
-
groupPermissionMap?: GroupPermissionMap
|
|
109
|
-
authorizedSitesSet?: any
|
|
110
|
-
groupMembershipSet?: any
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let {
|
|
114
|
-
plants,
|
|
115
|
-
groups,
|
|
116
|
-
permissions,
|
|
117
|
-
userAccount = $bindable(),
|
|
118
|
-
permissionValueMap = $bindable(new SvelteMap()),
|
|
119
|
-
groupPermissionMap = new SvelteMap(),
|
|
120
|
-
authorizedSitesSet = $bindable(new SvelteSet<number>()),
|
|
121
|
-
groupMembershipSet = $bindable(new SvelteSet<number>()),
|
|
122
|
-
}: Props = $props()
|
|
123
|
-
|
|
124
|
-
let userSites = $derived(
|
|
125
|
-
plants.map(({ id, code, name }) => {
|
|
126
|
-
return { id, code, name, isAuthorized: authorizedSitesSet.has(id) }
|
|
127
|
-
}),
|
|
128
|
-
)
|
|
129
|
-
let groupMembership = $derived(
|
|
130
|
-
groups.map(({ id, name }) => {
|
|
131
|
-
return { id, name, isMember: groupMembershipSet.has(id) }
|
|
132
|
-
}),
|
|
133
|
-
)
|
|
134
|
-
let groupPermissionValueMap = $derived(getGroupHighestPermissionValueMap(groupMembershipSet, groupPermissionMap))
|
|
135
|
-
</script>
|
|
136
|
-
|
|
137
|
-
<UserConfiguration
|
|
138
|
-
siteLabel="Plant"
|
|
139
|
-
bind:userAccount
|
|
140
|
-
bind:usernameInput
|
|
141
|
-
bind:doSendPasswordRecoveryToken={sendPasswordRecoveryToken}
|
|
142
|
-
{userSites}
|
|
143
|
-
{groupMembership}
|
|
144
|
-
{permissions}
|
|
145
|
-
{permissionValueMap}
|
|
146
|
-
{groupPermissionValueMap}
|
|
147
|
-
siteAccessChange={async site => {
|
|
148
|
-
site.isAuthorized ? authorizedSitesSet.add(site.id) : authorizedSitesSet.delete(site.id)
|
|
149
|
-
authorizedSitesSet = new Set(authorizedSitesSet)
|
|
150
|
-
}}
|
|
151
|
-
groupMembershipChange={async ({ id, isMember }) => {
|
|
152
|
-
isMember ? groupMembershipSet.add(id) : groupMembershipSet.delete(id)
|
|
153
|
-
groupMembershipSet = new Set(groupMembershipSet)
|
|
154
|
-
}}
|
|
155
|
-
permissionValueChange={async ({ permissionIds, value }) => {
|
|
156
|
-
for (const id of permissionIds) {
|
|
157
|
-
permissionValueMap.set(id, value)
|
|
158
|
-
}
|
|
159
|
-
permissionValueMap = new SvelteMap(permissionValueMap)
|
|
160
|
-
}}
|
|
161
|
-
/>
|
|
162
|
-
```
|
|
1
|
+
# Svelte UserConfiguration
|
|
2
|
+
|
|
3
|
+
This Svelte component provides a user configuration interface, including user account details, site access, group membership, and permissions.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm i @isoftdata/svelte-user-configuration
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Breaking changes
|
|
14
|
+
|
|
15
|
+
### 2.0.0
|
|
16
|
+
- Require Svelte 5
|
|
17
|
+
- Slots -> Snippets
|
|
18
|
+
- Events -> Callbacks
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
### User Account Properties
|
|
23
|
+
|
|
24
|
+
| Prop | Type | Required | Default | Description |
|
|
25
|
+
|------|------|----------|---------|-------------|
|
|
26
|
+
| `userAccount` | `UserAccount` | ✅ | - | The user account information. |
|
|
27
|
+
| `canToggleActive` | boolean | ❌ | `true` | Whether the user can be activated/deactivated. |
|
|
28
|
+
| `canEditAccountInfo` | boolean | ❌ | `true` | Whether account details can be edited. |
|
|
29
|
+
| `doSendPasswordRecoveryToken` | boolean | ❌ | `false` | Whether to allow sending password recovery tokens. |
|
|
30
|
+
| `hasPermissionToChangePassword` | boolean | ❌ | `false` | Whether the user has permission to change passwords. |
|
|
31
|
+
| `myAccountMode` | boolean | ❌ | `false` | When `true`, admin controls will be hidden/disabled. This is designed to be used when using the user account info component standalone so the current session user can edit their own account info, including first & last name, password recovery email, & password. |
|
|
32
|
+
| `passwordValidationRules` | `validationRules` of the [PasswordFields](<https://github.com/ISoft-Data-Systems/svelte-component-password-fields>) component | ❌ | `undefined` | Passwords rules to be enforced during password change. |
|
|
33
|
+
|
|
34
|
+
> The `passwordValidationRules` prop will be used during password setting when `hasPermissionToChangePassword` or `myAccountMode` are `true` .
|
|
35
|
+
|
|
36
|
+
### Site Access Properties
|
|
37
|
+
|
|
38
|
+
| Prop | Type | Required | Default | Description |
|
|
39
|
+
|------|------|----------|---------|-------------|
|
|
40
|
+
| `userSites` | `UserSites` | ✅ | - | List of sites the user has access to. |
|
|
41
|
+
| `canEditSiteAccess` | boolean | ❌ | `true` | Whether site access can be edited. |
|
|
42
|
+
|
|
43
|
+
### Group Membership Properties
|
|
44
|
+
|
|
45
|
+
| Prop | Type | Required | Default | Description |
|
|
46
|
+
|------|------|----------|---------|-------------|
|
|
47
|
+
| `groupMembership` | `GroupMembership` | ✅ | - | The user's group membership information. |
|
|
48
|
+
| `canEditGroupMembership` | boolean | ❌ | `true` | Whether group memberships can be edited. |
|
|
49
|
+
|
|
50
|
+
### Permission List Properties
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Required | Default | Description |
|
|
53
|
+
|------|------|----------|---------|-------------|
|
|
54
|
+
| `permissions` | `Permissions` | ✅ | - | The list of permissions for the user. |
|
|
55
|
+
| `permissionValueMap` | `PermissionValueMap` | ✅ | `new SvelteMap()` | A mapping of permissions to their values. **Note this *must* be a `SvelteMap`** or reactivity will not work. |
|
|
56
|
+
| `groupPermissionValueMap` | `GroupPermissionValueMap` | ❌ | `undefined` | A mapping of group-based permissions. |
|
|
57
|
+
|
|
58
|
+
### Other Properties
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Required | Default | Description |
|
|
61
|
+
|------|------|----------|---------|-------------|
|
|
62
|
+
| `siteLabel` | `SiteLabel` | ❌ | `"Site"` | Label for the site. |
|
|
63
|
+
| `showSiteAccess` | boolean | ❌ | `true` | Whether the site access section is shown. |
|
|
64
|
+
| `userAccountInfoIcon` | `IconName` | ❌ | `"user"` | Icon for the user account section. |
|
|
65
|
+
| `groupMembershipIcon` | `IconName` | ❌ | `"users"` | Icon for the group membership section. |
|
|
66
|
+
| `permissionListIcon` | `IconName` | ❌ | `"user-lock"` | Icon for the permission list section. |
|
|
67
|
+
| `userSiteAccessIcon` | `IconName` | ❌ | `"industry-windows"` | Icon for the site access section. |
|
|
68
|
+
| `permissionListCardHeaderTitle` | `PermissionListCardHeaderTitle` | ❌ | `"Permissions"` | Title for the permission list card header. |
|
|
69
|
+
| `usernameInput` | `HTMLInputElement \| undefined` | ❌ | `undefined` | Reference to the username input element. |
|
|
70
|
+
|
|
71
|
+
### Callbacks
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Description |
|
|
74
|
+
|------|------|-------------|
|
|
75
|
+
| `error` | `ErrorFn` | Callback for handling errors. |
|
|
76
|
+
| `success` | `SuccessFn` | Callback for handling success messages. |
|
|
77
|
+
| `deactivateUser` | `DeactivateUserFn` | Function to deactivate a user. |
|
|
78
|
+
| `confirmPasswordSet` | `ConfirmPasswordSetFn` | Function called when a password is set. |
|
|
79
|
+
| `accountInfoChanged` | `AccountInfoChangedFn` | Function called when account info changes. |
|
|
80
|
+
| `sendPasswordRecoveryToken` | `SendPasswordRecoveryTokenFn` | Function to send password recovery token. |
|
|
81
|
+
| `generateNewActivationPIN` | `GenerateNewActivationPINFn` | Function to generate a new activation PIN. |
|
|
82
|
+
| `permissionValueChange` | `PermissionValueChangeFn` | Function called when permissions change. |
|
|
83
|
+
| `siteAccessChange` | `SiteAccessChangeFn` | Function called when site access is changed. |
|
|
84
|
+
| `groupMembershipChange` | `GroupMembershipChangeFn` | Function called when group membership changes. |
|
|
85
|
+
|
|
86
|
+
## Snippets
|
|
87
|
+
This component provides snippets for injecting additional content.
|
|
88
|
+
|
|
89
|
+
| Snippet Name | Description |
|
|
90
|
+
|-----------|-------------|
|
|
91
|
+
| `userAccountInfo` | Slot at the end of the `userAccountInfo` component's card body |
|
|
92
|
+
| `siteAccess` | Slot at the end of the `siteAccess` component's card body |
|
|
93
|
+
| `userGroupMembership` | Slot at the end of the `userGroupMembership` component's card body |
|
|
94
|
+
| `permissionList` | Slot at the end of the `permissionList` component's card body |
|
|
95
|
+
|
|
96
|
+
## Usage Example in Svelte 5 w/ Runes
|
|
97
|
+
|
|
98
|
+
```svelte
|
|
99
|
+
<script lang="ts">
|
|
100
|
+
import { UserConfiguration, getGroupHighestPermissionValueMap } from '@isoftdata/svelte-user-configuration'
|
|
101
|
+
|
|
102
|
+
interface Props {
|
|
103
|
+
plants: PlantsForDropdown$result['plants']['data']
|
|
104
|
+
groups: Array<Group>
|
|
105
|
+
permissions: UserConfigurationData$result['permissions']['data']
|
|
106
|
+
userAccount: UserAccount
|
|
107
|
+
permissionValueMap?: PermissionValueMap
|
|
108
|
+
groupPermissionMap?: GroupPermissionMap
|
|
109
|
+
authorizedSitesSet?: any
|
|
110
|
+
groupMembershipSet?: any
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let {
|
|
114
|
+
plants,
|
|
115
|
+
groups,
|
|
116
|
+
permissions,
|
|
117
|
+
userAccount = $bindable(),
|
|
118
|
+
permissionValueMap = $bindable(new SvelteMap()),
|
|
119
|
+
groupPermissionMap = new SvelteMap(),
|
|
120
|
+
authorizedSitesSet = $bindable(new SvelteSet<number>()),
|
|
121
|
+
groupMembershipSet = $bindable(new SvelteSet<number>()),
|
|
122
|
+
}: Props = $props()
|
|
123
|
+
|
|
124
|
+
let userSites = $derived(
|
|
125
|
+
plants.map(({ id, code, name }) => {
|
|
126
|
+
return { id, code, name, isAuthorized: authorizedSitesSet.has(id) }
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
let groupMembership = $derived(
|
|
130
|
+
groups.map(({ id, name }) => {
|
|
131
|
+
return { id, name, isMember: groupMembershipSet.has(id) }
|
|
132
|
+
}),
|
|
133
|
+
)
|
|
134
|
+
let groupPermissionValueMap = $derived(getGroupHighestPermissionValueMap(groupMembershipSet, groupPermissionMap))
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<UserConfiguration
|
|
138
|
+
siteLabel="Plant"
|
|
139
|
+
bind:userAccount
|
|
140
|
+
bind:usernameInput
|
|
141
|
+
bind:doSendPasswordRecoveryToken={sendPasswordRecoveryToken}
|
|
142
|
+
{userSites}
|
|
143
|
+
{groupMembership}
|
|
144
|
+
{permissions}
|
|
145
|
+
{permissionValueMap}
|
|
146
|
+
{groupPermissionValueMap}
|
|
147
|
+
siteAccessChange={async site => {
|
|
148
|
+
site.isAuthorized ? authorizedSitesSet.add(site.id) : authorizedSitesSet.delete(site.id)
|
|
149
|
+
authorizedSitesSet = new Set(authorizedSitesSet)
|
|
150
|
+
}}
|
|
151
|
+
groupMembershipChange={async ({ id, isMember }) => {
|
|
152
|
+
isMember ? groupMembershipSet.add(id) : groupMembershipSet.delete(id)
|
|
153
|
+
groupMembershipSet = new Set(groupMembershipSet)
|
|
154
|
+
}}
|
|
155
|
+
permissionValueChange={async ({ permissionIds, value }) => {
|
|
156
|
+
for (const id of permissionIds) {
|
|
157
|
+
permissionValueMap.set(id, value)
|
|
158
|
+
}
|
|
159
|
+
permissionValueMap = new SvelteMap(permissionValueMap)
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { UserAccount } from './'
|
|
3
|
-
import type { i18n } from 'i18next'
|
|
4
|
-
|
|
5
|
-
import { getContext, tick } from 'svelte'
|
|
6
|
-
import { klona } from 'klona'
|
|
7
|
-
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
8
|
-
|
|
9
|
-
import Modal from '@isoftdata/svelte-modal'
|
|
10
|
-
import TextArea from '@isoftdata/svelte-textarea'
|
|
11
|
-
|
|
12
|
-
let show: boolean = $state(false)
|
|
13
|
-
let userAccount: UserAccount | undefined = $state()
|
|
14
|
-
let lockNotes: UserAccount['lockNotes'] = $state(null)
|
|
15
|
-
let textarea: HTMLTextAreaElement | undefined = $state()
|
|
16
|
-
|
|
17
|
-
interface Props {
|
|
18
|
-
deactivateUser?: ((user: { id: UserAccount['id']; lockNotes: UserAccount['lockNotes'] }) => void | Promise<void>) | undefined;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
let { deactivateUser = undefined }: Props = $props();
|
|
22
|
-
export async function open(userAccountCtx: UserAccount) {
|
|
23
|
-
userAccount = klona(userAccountCtx)
|
|
24
|
-
lockNotes = userAccount.lockNotes
|
|
25
|
-
show = true
|
|
26
|
-
await tick()
|
|
27
|
-
textarea?.select()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<Modal
|
|
34
|
-
title={translate('common:deactivate', 'Deactivate {{- userName}}', { userName: userAccount?.name ?? '' })}
|
|
35
|
-
confirmButtonText={translate('common:deactivate', 'Deactivate')}
|
|
36
|
-
confirmButtonColor="danger"
|
|
37
|
-
cancelButtonText={translate('common:close', 'Close')}
|
|
38
|
-
confirmButtonType="submit"
|
|
39
|
-
confirmButtonFormId="deactivateUserModalForm"
|
|
40
|
-
close={() => (show = false)}
|
|
41
|
-
bind:show
|
|
42
|
-
>
|
|
43
|
-
<form
|
|
44
|
-
id="deactivateUserModalForm"
|
|
45
|
-
onsubmit={async e => {
|
|
46
|
-
e.preventDefault()
|
|
47
|
-
userAccount ? await deactivateUser?.({ id: userAccount.id, lockNotes }) : undefined
|
|
48
|
-
show = false
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
<TextArea
|
|
52
|
-
bind:textarea
|
|
53
|
-
label={translate('configuration.user.accountInfo.lockNote', 'Lock Notes')}
|
|
54
|
-
labelClass="py-0 mb-2"
|
|
55
|
-
style="min-height:83px;"
|
|
56
|
-
bind:value={lockNotes}
|
|
57
|
-
/>
|
|
58
|
-
</form>
|
|
59
|
-
</Modal>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { UserAccount } from './'
|
|
3
|
+
import type { i18n } from 'i18next'
|
|
4
|
+
|
|
5
|
+
import { getContext, tick } from 'svelte'
|
|
6
|
+
import { klona } from 'klona'
|
|
7
|
+
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
8
|
+
|
|
9
|
+
import Modal from '@isoftdata/svelte-modal'
|
|
10
|
+
import TextArea from '@isoftdata/svelte-textarea'
|
|
11
|
+
|
|
12
|
+
let show: boolean = $state(false)
|
|
13
|
+
let userAccount: UserAccount | undefined = $state()
|
|
14
|
+
let lockNotes: UserAccount['lockNotes'] = $state(null)
|
|
15
|
+
let textarea: HTMLTextAreaElement | undefined = $state()
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
deactivateUser?: ((user: { id: UserAccount['id']; lockNotes: UserAccount['lockNotes'] }) => void | Promise<void>) | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let { deactivateUser = undefined }: Props = $props();
|
|
22
|
+
export async function open(userAccountCtx: UserAccount) {
|
|
23
|
+
userAccount = klona(userAccountCtx)
|
|
24
|
+
lockNotes = userAccount.lockNotes
|
|
25
|
+
show = true
|
|
26
|
+
await tick()
|
|
27
|
+
textarea?.select()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<Modal
|
|
34
|
+
title={translate('common:deactivate', 'Deactivate {{- userName}}', { userName: userAccount?.name ?? '' })}
|
|
35
|
+
confirmButtonText={translate('common:deactivate', 'Deactivate')}
|
|
36
|
+
confirmButtonColor="danger"
|
|
37
|
+
cancelButtonText={translate('common:close', 'Close')}
|
|
38
|
+
confirmButtonType="submit"
|
|
39
|
+
confirmButtonFormId="deactivateUserModalForm"
|
|
40
|
+
close={() => (show = false)}
|
|
41
|
+
bind:show
|
|
42
|
+
>
|
|
43
|
+
<form
|
|
44
|
+
id="deactivateUserModalForm"
|
|
45
|
+
onsubmit={async e => {
|
|
46
|
+
e.preventDefault()
|
|
47
|
+
userAccount ? await deactivateUser?.({ id: userAccount.id, lockNotes }) : undefined
|
|
48
|
+
show = false
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
<TextArea
|
|
52
|
+
bind:textarea
|
|
53
|
+
label={translate('configuration.user.accountInfo.lockNote', 'Lock Notes')}
|
|
54
|
+
labelClass="py-0 mb-2"
|
|
55
|
+
style="min-height:83px;"
|
|
56
|
+
bind:value={lockNotes}
|
|
57
|
+
/>
|
|
58
|
+
</form>
|
|
59
|
+
</Modal>
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { i18n } from 'i18next'
|
|
3
|
-
|
|
4
|
-
import { getContext } from 'svelte'
|
|
5
|
-
import Modal from '@isoftdata/svelte-modal'
|
|
6
|
-
import Input from '@isoftdata/svelte-input'
|
|
7
|
-
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
8
|
-
|
|
9
|
-
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
10
|
-
|
|
11
|
-
interface Props {
|
|
12
|
-
sendPasswordRecoveryToken?: ((email: string | null) => void | Promise<void>) | undefined
|
|
13
|
-
doSendPasswordRecoveryToken: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let { sendPasswordRecoveryToken = undefined, doSendPasswordRecoveryToken = $bindable() }: Props = $props()
|
|
17
|
-
let resetDate: Date | null | undefined = $state(undefined)
|
|
18
|
-
let email: string | null = $state(null)
|
|
19
|
-
let show: boolean = $state(false)
|
|
20
|
-
|
|
21
|
-
export function open(passwordRecoveryEmail: typeof email, lastResetDate: Date | null | undefined) {
|
|
22
|
-
email = passwordRecoveryEmail
|
|
23
|
-
resetDate = lastResetDate
|
|
24
|
-
show = true
|
|
25
|
-
}
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<Modal
|
|
29
|
-
bind:show
|
|
30
|
-
title={translate('configuration.user.accountInfo.passwordRecovery.header', 'Password Recovery')}
|
|
31
|
-
confirmButtonText={translate(
|
|
32
|
-
'configuration.user.accountInfo.passwordManagementModal.requestResetToken',
|
|
33
|
-
'Request Reset Token',
|
|
34
|
-
)}
|
|
35
|
-
confirmButtonIcon="check"
|
|
36
|
-
confirmButtonDisabled={!email}
|
|
37
|
-
close={() => (show = false)}
|
|
38
|
-
confirmButtonType="submit"
|
|
39
|
-
confirmButtonFormId="passwordRecoveryForm"
|
|
40
|
-
>
|
|
41
|
-
<form
|
|
42
|
-
id="passwordRecoveryForm"
|
|
43
|
-
onsubmit={async event => {
|
|
44
|
-
event.preventDefault()
|
|
45
|
-
try {
|
|
46
|
-
doSendPasswordRecoveryToken = true
|
|
47
|
-
await sendPasswordRecoveryToken?.(email)
|
|
48
|
-
show = false
|
|
49
|
-
} catch (err) {
|
|
50
|
-
console.error(err)
|
|
51
|
-
}
|
|
52
|
-
}}
|
|
53
|
-
>
|
|
54
|
-
<div class="row">
|
|
55
|
-
<Input
|
|
56
|
-
label={translate(
|
|
57
|
-
'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
|
|
58
|
-
'Last Password Set Date',
|
|
59
|
-
)}
|
|
60
|
-
value={resetDate?.toLocaleString() ?? ''}
|
|
61
|
-
labelParentClass="col-12 col-md-6 form-group mb-0"
|
|
62
|
-
readonly
|
|
63
|
-
/>
|
|
64
|
-
<Input
|
|
65
|
-
label={translate(
|
|
66
|
-
'configuration.user.accountInfo.passwordRecoveryModal.passwordRecoveryEmail',
|
|
67
|
-
'Password Recovery Email',
|
|
68
|
-
)}
|
|
69
|
-
value={email ?? ''}
|
|
70
|
-
labelParentClass="col-12 col-md-6 form-group mb-0"
|
|
71
|
-
readonly
|
|
72
|
-
/>
|
|
73
|
-
{#if !email}
|
|
74
|
-
<div class="alert alert-danger mt-3 mb-0">
|
|
75
|
-
{translate(
|
|
76
|
-
'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
|
|
77
|
-
'No recovery email has been set for this user.',
|
|
78
|
-
)}
|
|
79
|
-
</div>
|
|
80
|
-
{/if}
|
|
81
|
-
</div>
|
|
82
|
-
</form>
|
|
83
|
-
</Modal>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { i18n } from 'i18next'
|
|
3
|
+
|
|
4
|
+
import { getContext } from 'svelte'
|
|
5
|
+
import Modal from '@isoftdata/svelte-modal'
|
|
6
|
+
import Input from '@isoftdata/svelte-input'
|
|
7
|
+
import { translate as defaultTranslate } from '@isoftdata/utility-string'
|
|
8
|
+
|
|
9
|
+
const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
sendPasswordRecoveryToken?: ((email: string | null) => void | Promise<void>) | undefined
|
|
13
|
+
doSendPasswordRecoveryToken: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { sendPasswordRecoveryToken = undefined, doSendPasswordRecoveryToken = $bindable() }: Props = $props()
|
|
17
|
+
let resetDate: Date | null | undefined = $state(undefined)
|
|
18
|
+
let email: string | null = $state(null)
|
|
19
|
+
let show: boolean = $state(false)
|
|
20
|
+
|
|
21
|
+
export function open(passwordRecoveryEmail: typeof email, lastResetDate: Date | null | undefined) {
|
|
22
|
+
email = passwordRecoveryEmail
|
|
23
|
+
resetDate = lastResetDate
|
|
24
|
+
show = true
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<Modal
|
|
29
|
+
bind:show
|
|
30
|
+
title={translate('configuration.user.accountInfo.passwordRecovery.header', 'Password Recovery')}
|
|
31
|
+
confirmButtonText={translate(
|
|
32
|
+
'configuration.user.accountInfo.passwordManagementModal.requestResetToken',
|
|
33
|
+
'Request Reset Token',
|
|
34
|
+
)}
|
|
35
|
+
confirmButtonIcon="check"
|
|
36
|
+
confirmButtonDisabled={!email}
|
|
37
|
+
close={() => (show = false)}
|
|
38
|
+
confirmButtonType="submit"
|
|
39
|
+
confirmButtonFormId="passwordRecoveryForm"
|
|
40
|
+
>
|
|
41
|
+
<form
|
|
42
|
+
id="passwordRecoveryForm"
|
|
43
|
+
onsubmit={async event => {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
try {
|
|
46
|
+
doSendPasswordRecoveryToken = true
|
|
47
|
+
await sendPasswordRecoveryToken?.(email)
|
|
48
|
+
show = false
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(err)
|
|
51
|
+
}
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<div class="row">
|
|
55
|
+
<Input
|
|
56
|
+
label={translate(
|
|
57
|
+
'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
|
|
58
|
+
'Last Password Set Date',
|
|
59
|
+
)}
|
|
60
|
+
value={resetDate?.toLocaleString() ?? ''}
|
|
61
|
+
labelParentClass="col-12 col-md-6 form-group mb-0"
|
|
62
|
+
readonly
|
|
63
|
+
/>
|
|
64
|
+
<Input
|
|
65
|
+
label={translate(
|
|
66
|
+
'configuration.user.accountInfo.passwordRecoveryModal.passwordRecoveryEmail',
|
|
67
|
+
'Password Recovery Email',
|
|
68
|
+
)}
|
|
69
|
+
value={email ?? ''}
|
|
70
|
+
labelParentClass="col-12 col-md-6 form-group mb-0"
|
|
71
|
+
readonly
|
|
72
|
+
/>
|
|
73
|
+
{#if !email}
|
|
74
|
+
<div class="alert alert-danger mt-3 mb-0">
|
|
75
|
+
{translate(
|
|
76
|
+
'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
|
|
77
|
+
'No recovery email has been set for this user.',
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
{/if}
|
|
81
|
+
</div>
|
|
82
|
+
</form>
|
|
83
|
+
</Modal>
|