@checkstack/auth-frontend 0.6.4 → 0.6.5

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 CHANGED
@@ -1,5 +1,60 @@
1
1
  # @checkstack/auth-frontend
2
2
 
3
+ ## 0.6.5
4
+
5
+ ### Patch Changes
6
+
7
+ - f23f3c9: Phase 12 of the v1 polishing plan: three coordinated cleanup items that
8
+ close out half-finished features ahead of v1.0.
9
+
10
+ `@checkstack/incident-backend` adds focused unit-test coverage for
11
+ `IncidentService.hasActiveIncidentWithSuppression` in
12
+ `core/incident-backend/src/service.test.ts`. The new tests exercise the
13
+ real query-builder logic against a programmable mock data source and
14
+ pin down the active-only silencing contract: returns `true` only when
15
+ an unresolved incident with `suppressNotifications=true` is associated
16
+ with the queried `systemId`; returns `false` for resolved incidents,
17
+ incidents with `suppressNotifications=false`, systems with no incident
18
+ associations, and other systems' silenced incidents. No runtime
19
+ changes; the service code was already correct end-to-end (write path
20
+ through `IncidentEditor`, read path through the healthcheck queue
21
+ executor and dependency notifications). A companion docs page,
22
+ `docs/src/content/docs/architecture/alert-silencing.md`, documents the
23
+ contract, the two read sites, and the dispatch paths silencing does
24
+ NOT cover so users aren't surprised when an unaware channel keeps
25
+ firing.
26
+
27
+ `@checkstack/auth-frontend` surfaces inline role assignment inside the
28
+ user-creation dialog so admins can pick role(s) atomically with the
29
+ create call. `CreateUserDialog` now renders a checkbox list of
30
+ assignable roles (those with `isAssignable !== false`); on submit,
31
+ `UsersTab` awaits `createCredentialUser`, then immediately calls
32
+ `updateUserRoles` with the selected role IDs. On partial failure
33
+ (user created, role assignment failed) the UI surfaces a warning toast
34
+ naming the recovery path rather than silently misreporting success. No
35
+ new endpoints — reuses the existing `createCredentialUser` +
36
+ `updateUserRoles` contract pair. A companion docs page,
37
+ `docs/src/content/docs/architecture/users-and-teams.md`, documents the
38
+ identity / role / team model, the two S2S endpoints
39
+ (`checkResourceTeamAccess`, `getAccessibleResourceIds`) other plugins
40
+ should call to honour team grants, and explicitly defers audit
41
+ logging, CSV export, team-scoped resource-management UI, and deletion
42
+ side-effect handling to v1.1.
43
+
44
+ The third item — deleting the empty `core/status-frontend/` and
45
+ `core/status-page-backend/` shells — is tooling-only and intentionally
46
+ ships without a changeset; neither shell had a `package.json`, source
47
+ file, or downstream importer.
48
+
49
+ - Updated dependencies [f23f3c9]
50
+ - Updated dependencies [f23f3c9]
51
+ - Updated dependencies [f23f3c9]
52
+ - Updated dependencies [f23f3c9]
53
+ - @checkstack/common@0.11.0
54
+ - @checkstack/frontend-api@0.5.2
55
+ - @checkstack/ui@1.10.0
56
+ - @checkstack/auth-common@0.7.1
57
+
3
58
  ## 0.6.4
4
59
 
5
60
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/auth-frontend",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "license": "Elastic-2.0",
5
5
  "type": "module",
6
6
  "main": "src/index.tsx",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@checkstack/frontend-api": "0.5.1",
22
22
  "@checkstack/common": "0.10.0",
23
- "@checkstack/ui": "1.8.3",
23
+ "@checkstack/ui": "1.9.0",
24
24
  "react": "^18.2.0",
25
25
  "react-router-dom": "^6.22.0",
26
26
  "lucide-react": "^0.344.0",
@@ -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
- createUserMutation.mutate(data);
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
  </>