@checkstack/auth-frontend 0.6.4 → 0.6.6
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/CHANGELOG.md +73 -0
- package/package.json +6 -6
- package/src/components/CreateUserDialog.tsx +51 -1
- package/src/components/UsersTab.tsx +21 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# @checkstack/auth-frontend
|
|
2
2
|
|
|
3
|
+
## 0.6.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [e2d6f25]
|
|
8
|
+
- Updated dependencies [41c77f4]
|
|
9
|
+
- Updated dependencies [41c77f4]
|
|
10
|
+
- Updated dependencies [41c77f4]
|
|
11
|
+
- Updated dependencies [41c77f4]
|
|
12
|
+
- Updated dependencies [4832e33]
|
|
13
|
+
- Updated dependencies [6d52276]
|
|
14
|
+
- Updated dependencies [35bc682]
|
|
15
|
+
- Updated dependencies [c39ee69]
|
|
16
|
+
- @checkstack/frontend-api@0.6.0
|
|
17
|
+
- @checkstack/ui@1.11.0
|
|
18
|
+
- @checkstack/common@0.12.0
|
|
19
|
+
- @checkstack/auth-common@0.7.2
|
|
20
|
+
|
|
21
|
+
## 0.6.5
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- f23f3c9: Phase 12 of the v1 polishing plan: three coordinated cleanup items that
|
|
26
|
+
close out half-finished features ahead of v1.0.
|
|
27
|
+
|
|
28
|
+
`@checkstack/incident-backend` adds focused unit-test coverage for
|
|
29
|
+
`IncidentService.hasActiveIncidentWithSuppression` in
|
|
30
|
+
`core/incident-backend/src/service.test.ts`. The new tests exercise the
|
|
31
|
+
real query-builder logic against a programmable mock data source and
|
|
32
|
+
pin down the active-only silencing contract: returns `true` only when
|
|
33
|
+
an unresolved incident with `suppressNotifications=true` is associated
|
|
34
|
+
with the queried `systemId`; returns `false` for resolved incidents,
|
|
35
|
+
incidents with `suppressNotifications=false`, systems with no incident
|
|
36
|
+
associations, and other systems' silenced incidents. No runtime
|
|
37
|
+
changes; the service code was already correct end-to-end (write path
|
|
38
|
+
through `IncidentEditor`, read path through the healthcheck queue
|
|
39
|
+
executor and dependency notifications). A companion docs page,
|
|
40
|
+
`docs/src/content/docs/architecture/alert-silencing.md`, documents the
|
|
41
|
+
contract, the two read sites, and the dispatch paths silencing does
|
|
42
|
+
NOT cover so users aren't surprised when an unaware channel keeps
|
|
43
|
+
firing.
|
|
44
|
+
|
|
45
|
+
`@checkstack/auth-frontend` surfaces inline role assignment inside the
|
|
46
|
+
user-creation dialog so admins can pick role(s) atomically with the
|
|
47
|
+
create call. `CreateUserDialog` now renders a checkbox list of
|
|
48
|
+
assignable roles (those with `isAssignable !== false`); on submit,
|
|
49
|
+
`UsersTab` awaits `createCredentialUser`, then immediately calls
|
|
50
|
+
`updateUserRoles` with the selected role IDs. On partial failure
|
|
51
|
+
(user created, role assignment failed) the UI surfaces a warning toast
|
|
52
|
+
naming the recovery path rather than silently misreporting success. No
|
|
53
|
+
new endpoints — reuses the existing `createCredentialUser` +
|
|
54
|
+
`updateUserRoles` contract pair. A companion docs page,
|
|
55
|
+
`docs/src/content/docs/architecture/users-and-teams.md`, documents the
|
|
56
|
+
identity / role / team model, the two S2S endpoints
|
|
57
|
+
(`checkResourceTeamAccess`, `getAccessibleResourceIds`) other plugins
|
|
58
|
+
should call to honour team grants, and explicitly defers audit
|
|
59
|
+
logging, CSV export, team-scoped resource-management UI, and deletion
|
|
60
|
+
side-effect handling to v1.1.
|
|
61
|
+
|
|
62
|
+
The third item — deleting the empty `core/status-frontend/` and
|
|
63
|
+
`core/status-page-backend/` shells — is tooling-only and intentionally
|
|
64
|
+
ships without a changeset; neither shell had a `package.json`, source
|
|
65
|
+
file, or downstream importer.
|
|
66
|
+
|
|
67
|
+
- Updated dependencies [f23f3c9]
|
|
68
|
+
- Updated dependencies [f23f3c9]
|
|
69
|
+
- Updated dependencies [f23f3c9]
|
|
70
|
+
- Updated dependencies [f23f3c9]
|
|
71
|
+
- @checkstack/common@0.11.0
|
|
72
|
+
- @checkstack/frontend-api@0.5.2
|
|
73
|
+
- @checkstack/ui@1.10.0
|
|
74
|
+
- @checkstack/auth-common@0.7.1
|
|
75
|
+
|
|
3
76
|
## 0.6.4
|
|
4
77
|
|
|
5
78
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/auth-frontend",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.tsx",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"test:e2e": "bunx playwright test"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@checkstack/frontend-api": "0.5.
|
|
22
|
-
"@checkstack/common": "0.
|
|
23
|
-
"@checkstack/ui": "1.
|
|
21
|
+
"@checkstack/frontend-api": "0.5.2",
|
|
22
|
+
"@checkstack/common": "0.11.0",
|
|
23
|
+
"@checkstack/ui": "1.10.0",
|
|
24
24
|
"react": "^18.2.0",
|
|
25
25
|
"react-router-dom": "^6.22.0",
|
|
26
26
|
"lucide-react": "^0.344.0",
|
|
27
27
|
"better-auth": "^1.1.8",
|
|
28
|
-
"@checkstack/auth-common": "0.7.
|
|
28
|
+
"@checkstack/auth-common": "0.7.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"typescript": "^5.0.0",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"@playwright/test": "^1.49.0",
|
|
34
34
|
"@checkstack/test-utils-frontend": "0.0.5",
|
|
35
35
|
"@checkstack/tsconfig": "0.0.7",
|
|
36
|
-
"@checkstack/scripts": "0.3.
|
|
36
|
+
"@checkstack/scripts": "0.3.3"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -9,27 +9,39 @@ import {
|
|
|
9
9
|
Button,
|
|
10
10
|
Input,
|
|
11
11
|
Label,
|
|
12
|
+
Checkbox,
|
|
12
13
|
} from "@checkstack/ui";
|
|
13
14
|
import { passwordSchema } from "@checkstack/auth-common";
|
|
15
|
+
import type { Role } from "../api";
|
|
14
16
|
|
|
15
17
|
interface CreateUserDialogProps {
|
|
16
18
|
open: boolean;
|
|
17
19
|
onOpenChange: (open: boolean) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Assignable roles, surfaced as an optional multi-select inside the
|
|
22
|
+
* dialog so admins can pick role(s) atomically with user creation.
|
|
23
|
+
* Roles where `isAssignable === false` (e.g. anonymous) are filtered
|
|
24
|
+
* out by the caller before being passed in.
|
|
25
|
+
*/
|
|
26
|
+
assignableRoles: Role[];
|
|
18
27
|
onSubmit: (data: {
|
|
19
28
|
name: string;
|
|
20
29
|
email: string;
|
|
21
30
|
password: string;
|
|
31
|
+
roleIds: string[];
|
|
22
32
|
}) => Promise<void>;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
export const CreateUserDialog: React.FC<CreateUserDialogProps> = ({
|
|
26
36
|
open,
|
|
27
37
|
onOpenChange,
|
|
38
|
+
assignableRoles,
|
|
28
39
|
onSubmit,
|
|
29
40
|
}) => {
|
|
30
41
|
const [name, setName] = useState("");
|
|
31
42
|
const [email, setEmail] = useState("");
|
|
32
43
|
const [password, setPassword] = useState("");
|
|
44
|
+
const [selectedRoleIds, setSelectedRoleIds] = useState<string[]>([]);
|
|
33
45
|
const [loading, setLoading] = useState(false);
|
|
34
46
|
const [validationErrors, setValidationErrors] = useState<string[]>([]);
|
|
35
47
|
|
|
@@ -39,6 +51,7 @@ export const CreateUserDialog: React.FC<CreateUserDialogProps> = ({
|
|
|
39
51
|
setName("");
|
|
40
52
|
setEmail("");
|
|
41
53
|
setPassword("");
|
|
54
|
+
setSelectedRoleIds([]);
|
|
42
55
|
setValidationErrors([]);
|
|
43
56
|
}
|
|
44
57
|
}, [open]);
|
|
@@ -68,13 +81,21 @@ export const CreateUserDialog: React.FC<CreateUserDialogProps> = ({
|
|
|
68
81
|
|
|
69
82
|
setLoading(true);
|
|
70
83
|
try {
|
|
71
|
-
await onSubmit({ name, email, password });
|
|
84
|
+
await onSubmit({ name, email, password, roleIds: selectedRoleIds });
|
|
72
85
|
onOpenChange(false);
|
|
73
86
|
} finally {
|
|
74
87
|
setLoading(false);
|
|
75
88
|
}
|
|
76
89
|
};
|
|
77
90
|
|
|
91
|
+
const handleToggleRole = (roleId: string) => {
|
|
92
|
+
setSelectedRoleIds((prev) =>
|
|
93
|
+
prev.includes(roleId)
|
|
94
|
+
? prev.filter((id) => id !== roleId)
|
|
95
|
+
: [...prev, roleId],
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
78
99
|
const isValid =
|
|
79
100
|
name.trim().length > 0 &&
|
|
80
101
|
email.trim().length > 0 &&
|
|
@@ -135,6 +156,35 @@ export const CreateUserDialog: React.FC<CreateUserDialogProps> = ({
|
|
|
135
156
|
At least 8 characters with uppercase, lowercase, and number
|
|
136
157
|
</p>
|
|
137
158
|
</div>
|
|
159
|
+
{assignableRoles.length > 0 && (
|
|
160
|
+
<div className="grid gap-2">
|
|
161
|
+
<Label>Roles</Label>
|
|
162
|
+
<div className="flex flex-col gap-2 max-h-40 overflow-y-auto">
|
|
163
|
+
{assignableRoles.map((role) => (
|
|
164
|
+
<div
|
|
165
|
+
key={role.id}
|
|
166
|
+
className="flex items-center space-x-2"
|
|
167
|
+
>
|
|
168
|
+
<Checkbox
|
|
169
|
+
id={`create-role-${role.id}`}
|
|
170
|
+
checked={selectedRoleIds.includes(role.id)}
|
|
171
|
+
onCheckedChange={() => handleToggleRole(role.id)}
|
|
172
|
+
/>
|
|
173
|
+
<label
|
|
174
|
+
htmlFor={`create-role-${role.id}`}
|
|
175
|
+
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
176
|
+
>
|
|
177
|
+
{role.name}
|
|
178
|
+
</label>
|
|
179
|
+
</div>
|
|
180
|
+
))}
|
|
181
|
+
</div>
|
|
182
|
+
<p className="text-xs text-muted-foreground">
|
|
183
|
+
Optional. Roles are assigned immediately after the user is
|
|
184
|
+
created.
|
|
185
|
+
</p>
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
138
188
|
</div>
|
|
139
189
|
<DialogFooter>
|
|
140
190
|
<Button
|
|
@@ -84,10 +84,6 @@ export const UsersTab: React.FC<UsersTabProps> = ({
|
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
const createUserMutation = authClient.createCredentialUser.useMutation({
|
|
87
|
-
onSuccess: () => {
|
|
88
|
-
toast.success("User created successfully");
|
|
89
|
-
void onDataChange();
|
|
90
|
-
},
|
|
91
87
|
onError: (error) => {
|
|
92
88
|
toast.error(
|
|
93
89
|
extractErrorMessage(error, "Failed to create user"),
|
|
@@ -122,8 +118,27 @@ export const UsersTab: React.FC<UsersTabProps> = ({
|
|
|
122
118
|
name: string;
|
|
123
119
|
email: string;
|
|
124
120
|
password: string;
|
|
121
|
+
roleIds: string[];
|
|
125
122
|
}) => {
|
|
126
|
-
|
|
123
|
+
const { roleIds, ...credentials } = data;
|
|
124
|
+
const { userId } = await createUserMutation.mutateAsync(credentials);
|
|
125
|
+
|
|
126
|
+
if (roleIds.length > 0) {
|
|
127
|
+
try {
|
|
128
|
+
await updateRolesMutation.mutateAsync({ userId, roles: roleIds });
|
|
129
|
+
toast.success("User created with roles assigned");
|
|
130
|
+
} catch {
|
|
131
|
+
// updateRolesMutation.onError already surfaced a toast; the user
|
|
132
|
+
// record itself still exists, so flag the partial success.
|
|
133
|
+
toast.warning(
|
|
134
|
+
"User created, but role assignment failed. Edit the user to retry.",
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
toast.success("User created successfully");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await onDataChange();
|
|
127
142
|
};
|
|
128
143
|
|
|
129
144
|
return (
|
|
@@ -242,6 +257,7 @@ export const UsersTab: React.FC<UsersTabProps> = ({
|
|
|
242
257
|
<CreateUserDialog
|
|
243
258
|
open={createUserDialogOpen}
|
|
244
259
|
onOpenChange={setCreateUserDialogOpen}
|
|
260
|
+
assignableRoles={roles.filter((role) => role.isAssignable !== false)}
|
|
245
261
|
onSubmit={handleCreateUser}
|
|
246
262
|
/>
|
|
247
263
|
</>
|