@checkstack/auth-frontend 0.1.0 → 0.3.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.
@@ -19,20 +19,20 @@ import {
19
19
  AlertDescription,
20
20
  } from "@checkstack/ui";
21
21
  import { Check } from "lucide-react";
22
- import type { Role, Permission } from "../api";
22
+ import type { Role, AccessRuleEntry } from "../api";
23
23
 
24
24
  interface RoleDialogProps {
25
25
  open: boolean;
26
26
  onOpenChange: (open: boolean) => void;
27
27
  role?: Role;
28
- permissions: Permission[];
29
- /** Whether current user has this role (prevents permission elevation) */
28
+ accessRulesList: AccessRuleEntry[];
29
+ /** Whether current user has this role (prevents access elevation) */
30
30
  isUserRole?: boolean;
31
31
  onSave: (params: {
32
32
  id?: string;
33
33
  name: string;
34
34
  description?: string;
35
- permissions: string[];
35
+ accessRules: string[];
36
36
  }) => Promise<void>;
37
37
  }
38
38
 
@@ -40,14 +40,14 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
40
40
  open,
41
41
  onOpenChange,
42
42
  role,
43
- permissions,
43
+ accessRulesList,
44
44
  isUserRole = false,
45
45
  onSave,
46
46
  }) => {
47
47
  const [name, setName] = useState(role?.name || "");
48
48
  const [description, setDescription] = useState(role?.description || "");
49
- const [selectedPermissions, setSelectedPermissions] = useState<Set<string>>(
50
- new Set(role?.permissions || [])
49
+ const [selectedAccessRules, setSelectedAccessRules] = useState<Set<string>>(
50
+ new Set(role?.accessRules || [])
51
51
  );
52
52
  const [saving, setSaving] = useState(false);
53
53
 
@@ -55,49 +55,45 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
55
55
  React.useEffect(() => {
56
56
  setName(role?.name || "");
57
57
  setDescription(role?.description || "");
58
- setSelectedPermissions(new Set(role?.permissions || []));
58
+ setSelectedAccessRules(new Set(role?.accessRules || []));
59
59
  }, [role]);
60
60
 
61
61
  const isEditing = !!role;
62
62
  const isAdminRole = role?.id === "admin";
63
- // Disable permissions for admin (wildcard) or user's own roles (prevent elevation)
64
- const permissionsDisabled = isAdminRole || isUserRole;
63
+ // Disable access rules for admin (wildcard) or user's own roles (prevent elevation)
64
+ const accessRulesDisabled = isAdminRole || isUserRole;
65
65
 
66
- // Group permissions by plugin
67
- const permissionsByPlugin: Record<string, Permission[]> = {};
68
- for (const perm of permissions) {
66
+ // Group access rules by plugin
67
+ const accessRulesByPlugin: Record<string, AccessRuleEntry[]> = {};
68
+ for (const perm of accessRulesList) {
69
69
  const [plugin] = perm.id.split(".");
70
- if (!permissionsByPlugin[plugin]) {
71
- permissionsByPlugin[plugin] = [];
70
+ if (!accessRulesByPlugin[plugin]) {
71
+ accessRulesByPlugin[plugin] = [];
72
72
  }
73
- permissionsByPlugin[plugin].push(perm);
73
+ accessRulesByPlugin[plugin].push(perm);
74
74
  }
75
75
 
76
- const handleTogglePermission = (permissionId: string) => {
77
- const newSelected = new Set(selectedPermissions);
78
- if (newSelected.has(permissionId)) {
79
- newSelected.delete(permissionId);
76
+ const handleToggleAccessRule = (accessRuleId: string) => {
77
+ const newSelected = new Set(selectedAccessRules);
78
+ if (newSelected.has(accessRuleId)) {
79
+ newSelected.delete(accessRuleId);
80
80
  } else {
81
- newSelected.add(permissionId);
81
+ newSelected.add(accessRuleId);
82
82
  }
83
- setSelectedPermissions(newSelected);
83
+ setSelectedAccessRules(newSelected);
84
84
  };
85
85
 
86
- const handleSave = async () => {
86
+ const handleSave = () => {
87
87
  setSaving(true);
88
- try {
89
- await onSave({
90
- ...(isEditing && { id: role.id }),
91
- name,
92
- description: description || undefined,
93
- permissions: [...selectedPermissions],
94
- });
95
- onOpenChange(false);
96
- } catch (error) {
97
- console.error("Failed to save role:", error);
98
- } finally {
99
- setSaving(false);
100
- }
88
+ onSave({
89
+ ...(isEditing && { id: role.id }),
90
+ name,
91
+ description: description || undefined,
92
+ accessRules: [...selectedAccessRules],
93
+ });
94
+ // Dialog closing and saving state are managed by the parent via onDataChange callback
95
+ onOpenChange(false);
96
+ setSaving(false);
101
97
  };
102
98
 
103
99
  let buttonText = "Create";
@@ -114,8 +110,8 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
114
110
  <DialogTitle>{isEditing ? "Edit Role" : "Create Role"}</DialogTitle>
115
111
  <DialogDescription className="sr-only">
116
112
  {isEditing
117
- ? "Modify the settings and permissions for this role"
118
- : "Create a new role with specific permissions"}
113
+ ? "Modify the settings and access rules for this role"
114
+ : "Create a new role with specific access rules"}
119
115
  </DialogDescription>
120
116
  </DialogHeader>
121
117
 
@@ -141,23 +137,23 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
141
137
  </div>
142
138
 
143
139
  <div>
144
- <Label className="text-base">Permissions</Label>
140
+ <Label className="text-base">Access Rules</Label>
145
141
  <p className="text-sm text-muted-foreground mt-1 mb-3">
146
- Select permissions to grant to this role. Permissions are
142
+ Select access rules to grant to this role. Access rules are
147
143
  organized by plugin.
148
144
  </p>
149
145
  {isAdminRole && (
150
146
  <Alert variant="info" className="mb-3">
151
147
  <AlertDescription>
152
- The administrator role has wildcard access to all permissions.
153
- These cannot be modified.
148
+ The administrator role has wildcard access to all access
149
+ rules. These cannot be modified.
154
150
  </AlertDescription>
155
151
  </Alert>
156
152
  )}
157
153
  {!isAdminRole && isUserRole && (
158
154
  <Alert variant="info" className="mb-3">
159
155
  <AlertDescription>
160
- You cannot modify permissions for a role you currently have.
156
+ You cannot modify access rules for a role you currently have.
161
157
  This prevents accidental self-lockout from the system.
162
158
  </AlertDescription>
163
159
  </Alert>
@@ -165,10 +161,10 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
165
161
  <div className="border rounded-lg">
166
162
  <Accordion
167
163
  type="multiple"
168
- defaultValue={Object.keys(permissionsByPlugin)}
164
+ defaultValue={Object.keys(accessRulesByPlugin)}
169
165
  className="w-full"
170
166
  >
171
- {Object.entries(permissionsByPlugin).map(([plugin, perms]) => (
167
+ {Object.entries(accessRulesByPlugin).map(([plugin, perms]) => (
172
168
  <AccordionItem key={plugin} value={plugin}>
173
169
  <AccordionTrigger className="px-4 hover:no-underline">
174
170
  <div className="flex items-center justify-between flex-1 pr-2">
@@ -177,7 +173,7 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
177
173
  </span>
178
174
  <span className="text-xs text-muted-foreground">
179
175
  {
180
- perms.filter((p) => selectedPermissions.has(p.id))
176
+ perms.filter((p) => selectedAccessRules.has(p.id))
181
177
  .length
182
178
  }{" "}
183
179
  / {perms.length} selected
@@ -187,15 +183,15 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
187
183
  <AccordionContent className="px-4">
188
184
  <div
189
185
  className={`space-y-${
190
- permissionsDisabled ? "2" : "3"
186
+ accessRulesDisabled ? "2" : "3"
191
187
  } pt-2`}
192
188
  >
193
189
  {perms.map((perm) => {
194
190
  const isAssigned =
195
- isAdminRole || selectedPermissions.has(perm.id);
191
+ isAdminRole || selectedAccessRules.has(perm.id);
196
192
 
197
- // Use view-style design when permissions are disabled
198
- if (permissionsDisabled) {
193
+ // Use view-style design when access rules are disabled
194
+ if (accessRulesDisabled) {
199
195
  return (
200
196
  <div
201
197
  key={perm.id}
@@ -239,7 +235,7 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
239
235
  );
240
236
  }
241
237
 
242
- // Use editable checkbox design when permissions are editable
238
+ // Use editable checkbox design when access rules are editable
243
239
  return (
244
240
  <div
245
241
  key={perm.id}
@@ -247,9 +243,9 @@ export const RoleDialog: React.FC<RoleDialogProps> = ({
247
243
  >
248
244
  <Checkbox
249
245
  id={`perm-${perm.id}`}
250
- checked={selectedPermissions.has(perm.id)}
246
+ checked={selectedAccessRules.has(perm.id)}
251
247
  onCheckedChange={() =>
252
- handleTogglePermission(perm.id)
248
+ handleToggleAccessRule(perm.id)
253
249
  }
254
250
  className="mt-0.5"
255
251
  />
@@ -16,15 +16,14 @@ import {
16
16
  useToast,
17
17
  } from "@checkstack/ui";
18
18
  import { Plus, Edit, Trash2 } from "lucide-react";
19
- import { useApi } from "@checkstack/frontend-api";
20
- import { rpcApiRef } from "@checkstack/frontend-api";
19
+ import { usePluginClient } from "@checkstack/frontend-api";
21
20
  import { AuthApi } from "@checkstack/auth-common";
22
- import type { Role, Permission } from "../api";
21
+ import type { Role, AccessRuleEntry } from "../api";
23
22
  import { RoleDialog } from "./RoleDialog";
24
23
 
25
24
  export interface RolesTabProps {
26
25
  roles: Role[];
27
- permissions: Permission[];
26
+ accessRulesList: AccessRuleEntry[];
28
27
  userRoleIds: string[];
29
28
  canReadRoles: boolean;
30
29
  canCreateRoles: boolean;
@@ -35,7 +34,7 @@ export interface RolesTabProps {
35
34
 
36
35
  export const RolesTab: React.FC<RolesTabProps> = ({
37
36
  roles,
38
- permissions,
37
+ accessRulesList,
39
38
  userRoleIds,
40
39
  canReadRoles,
41
40
  canCreateRoles,
@@ -43,14 +42,51 @@ export const RolesTab: React.FC<RolesTabProps> = ({
43
42
  canDeleteRoles,
44
43
  onDataChange,
45
44
  }) => {
46
- const rpcApi = useApi(rpcApiRef);
47
- const authClient = rpcApi.forPlugin(AuthApi);
45
+ const authClient = usePluginClient(AuthApi);
48
46
  const toast = useToast();
49
47
 
50
48
  const [roleToDelete, setRoleToDelete] = useState<string>();
51
49
  const [roleDialogOpen, setRoleDialogOpen] = useState(false);
52
50
  const [editingRole, setEditingRole] = useState<Role | undefined>();
53
51
 
52
+ // Mutations
53
+ const createRoleMutation = authClient.createRole.useMutation({
54
+ onSuccess: () => {
55
+ toast.success("Role created successfully");
56
+ void onDataChange();
57
+ },
58
+ onError: (error) => {
59
+ toast.error(
60
+ error instanceof Error ? error.message : "Failed to create role"
61
+ );
62
+ },
63
+ });
64
+
65
+ const updateRoleMutation = authClient.updateRole.useMutation({
66
+ onSuccess: () => {
67
+ toast.success("Role updated successfully");
68
+ void onDataChange();
69
+ },
70
+ onError: (error) => {
71
+ toast.error(
72
+ error instanceof Error ? error.message : "Failed to update role"
73
+ );
74
+ },
75
+ });
76
+
77
+ const deleteRoleMutation = authClient.deleteRole.useMutation({
78
+ onSuccess: () => {
79
+ toast.success("Role deleted successfully");
80
+ setRoleToDelete(undefined);
81
+ void onDataChange();
82
+ },
83
+ onError: (error) => {
84
+ toast.error(
85
+ error instanceof Error ? error.message : "Failed to delete role"
86
+ );
87
+ },
88
+ });
89
+
54
90
  const handleCreateRole = () => {
55
91
  setEditingRole(undefined);
56
92
  setRoleDialogOpen(true);
@@ -65,46 +101,23 @@ export const RolesTab: React.FC<RolesTabProps> = ({
65
101
  id?: string;
66
102
  name: string;
67
103
  description?: string;
68
- permissions: string[];
104
+ accessRules: string[];
69
105
  }) => {
70
- try {
71
- if (params.id) {
72
- await authClient.updateRole({
73
- id: params.id,
74
- name: params.name,
75
- description: params.description,
76
- permissions: params.permissions,
77
- });
78
- toast.success("Role updated successfully");
79
- } else {
80
- await authClient.createRole({
81
- name: params.name,
82
- description: params.description,
83
- permissions: params.permissions,
84
- });
85
- toast.success("Role created successfully");
86
- }
87
- await onDataChange();
88
- } catch (error: unknown) {
89
- toast.error(
90
- error instanceof Error ? error.message : "Failed to save role"
91
- );
92
- throw error;
93
- }
106
+ await (params.id ? updateRoleMutation.mutateAsync({
107
+ id: params.id,
108
+ name: params.name,
109
+ description: params.description,
110
+ accessRules: params.accessRules,
111
+ }) : createRoleMutation.mutateAsync({
112
+ name: params.name,
113
+ description: params.description,
114
+ accessRules: params.accessRules,
115
+ }));
94
116
  };
95
117
 
96
- const handleDeleteRole = async () => {
118
+ const handleDeleteRole = () => {
97
119
  if (!roleToDelete) return;
98
- try {
99
- await authClient.deleteRole(roleToDelete);
100
- toast.success("Role deleted successfully");
101
- setRoleToDelete(undefined);
102
- await onDataChange();
103
- } catch (error: unknown) {
104
- toast.error(
105
- error instanceof Error ? error.message : "Failed to delete role"
106
- );
107
- }
120
+ deleteRoleMutation.mutate(roleToDelete);
108
121
  };
109
122
 
110
123
  return (
@@ -128,7 +141,7 @@ export const RolesTab: React.FC<RolesTabProps> = ({
128
141
  <TableHeader>
129
142
  <TableRow>
130
143
  <TableHead>Role</TableHead>
131
- <TableHead>Permissions</TableHead>
144
+ <TableHead>Access Rules</TableHead>
132
145
  <TableHead className="text-right">Actions</TableHead>
133
146
  </TableRow>
134
147
  </TableHeader>
@@ -159,7 +172,7 @@ export const RolesTab: React.FC<RolesTabProps> = ({
159
172
  </TableCell>
160
173
  <TableCell>
161
174
  <span className="text-sm text-muted-foreground">
162
- {role.permissions?.length || 0} permissions
175
+ {role.accessRules?.length || 0} access rules
163
176
  </span>
164
177
  </TableCell>
165
178
  <TableCell className="text-right">
@@ -192,7 +205,7 @@ export const RolesTab: React.FC<RolesTabProps> = ({
192
205
  )
193
206
  ) : (
194
207
  <p className="text-muted-foreground">
195
- You don't have permission to view roles.
208
+ You don't have access to view roles.
196
209
  </p>
197
210
  )}
198
211
  </CardContent>
@@ -202,7 +215,7 @@ export const RolesTab: React.FC<RolesTabProps> = ({
202
215
  open={roleDialogOpen}
203
216
  onOpenChange={setRoleDialogOpen}
204
217
  role={editingRole}
205
- permissions={permissions}
218
+ accessRulesList={accessRulesList}
206
219
  isUserRole={editingRole ? userRoleIds.includes(editingRole.id) : false}
207
220
  onSave={handleSaveRole}
208
221
  />
@@ -15,8 +15,7 @@ import {
15
15
  useToast,
16
16
  } from "@checkstack/ui";
17
17
  import { Shield, RefreshCw } from "lucide-react";
18
- import { useApi } from "@checkstack/frontend-api";
19
- import { rpcApiRef } from "@checkstack/frontend-api";
18
+ import { usePluginClient } from "@checkstack/frontend-api";
20
19
  import { AuthApi } from "@checkstack/auth-common";
21
20
  import type { AuthStrategy } from "../api";
22
21
  import { AuthStrategyCard } from "./AuthStrategyCard";
@@ -34,8 +33,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
34
33
  canManageRegistration,
35
34
  onDataChange,
36
35
  }) => {
37
- const rpcApi = useApi(rpcApiRef);
38
- const authClient = rpcApi.forPlugin(AuthApi);
36
+ const authClient = usePluginClient(AuthApi);
39
37
  const toast = useToast();
40
38
 
41
39
  const [reloading, setReloading] = useState(false);
@@ -45,14 +43,9 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
45
43
  >({});
46
44
 
47
45
  // Registration state
48
- const [registrationSchema, setRegistrationSchema] = useState<
49
- Record<string, unknown> | undefined
50
- >();
51
46
  const [registrationSettings, setRegistrationSettings] = useState<{
52
47
  allowRegistration: boolean;
53
48
  }>({ allowRegistration: true });
54
- const [loadingRegistration, setLoadingRegistration] = useState(true);
55
- const [savingRegistration, setSavingRegistration] = useState(false);
56
49
  const [registrationValid, setRegistrationValid] = useState(true);
57
50
 
58
51
  // Initialize strategy configs when strategies change
@@ -64,104 +57,101 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
64
57
  setStrategyConfigs(configs);
65
58
  }, [strategies]);
66
59
 
67
- // Fetch registration data when we have permission
60
+ // Query: Registration schema (admin only)
61
+ const { data: registrationSchema, isLoading: schemaLoading } =
62
+ authClient.getRegistrationSchema.useQuery(
63
+ {},
64
+ { enabled: canManageRegistration }
65
+ );
66
+
67
+ // Query: Registration status (admin only)
68
+ const { data: registrationStatus, isLoading: statusLoading } =
69
+ authClient.getRegistrationStatus.useQuery(
70
+ {},
71
+ { enabled: canManageRegistration }
72
+ );
73
+
74
+ // Sync fetched settings to local state
68
75
  useEffect(() => {
69
- if (!canManageRegistration) {
70
- setLoadingRegistration(false);
71
- return;
76
+ if (registrationStatus) {
77
+ setRegistrationSettings(registrationStatus);
72
78
  }
79
+ }, [registrationStatus]);
73
80
 
74
- const fetchRegistrationData = async () => {
75
- setLoadingRegistration(true);
76
- try {
77
- const [schema, status] = await Promise.all([
78
- authClient.getRegistrationSchema(),
79
- authClient.getRegistrationStatus(),
80
- ]);
81
- setRegistrationSchema(schema);
82
- setRegistrationSettings(status);
83
- } catch (error) {
84
- console.error("Failed to fetch registration data:", error);
85
- } finally {
86
- setLoadingRegistration(false);
87
- }
88
- };
89
- fetchRegistrationData();
90
- }, [canManageRegistration, authClient]);
81
+ const loadingRegistration = schemaLoading || statusLoading;
82
+
83
+ // Mutations
84
+ const updateStrategyMutation = authClient.updateStrategy.useMutation({
85
+ onSuccess: () => {
86
+ toast.success("Strategy updated");
87
+ void onDataChange();
88
+ },
89
+ onError: (error) => {
90
+ toast.error(
91
+ error instanceof Error ? error.message : "Failed to update strategy"
92
+ );
93
+ },
94
+ });
95
+
96
+ const setRegistrationMutation = authClient.setRegistrationStatus.useMutation({
97
+ onSuccess: () => {
98
+ toast.success("Registration settings saved");
99
+ },
100
+ onError: (error) => {
101
+ toast.error(
102
+ error instanceof Error ? error.message : "Failed to save settings"
103
+ );
104
+ },
105
+ });
106
+
107
+ const reloadAuthMutation = authClient.reloadAuth.useMutation({
108
+ onSuccess: () => {
109
+ toast.success("Authentication system reloaded");
110
+ void onDataChange();
111
+ setReloading(false);
112
+ },
113
+ onError: (error) => {
114
+ toast.error(
115
+ error instanceof Error ? error.message : "Failed to reload auth"
116
+ );
117
+ setReloading(false);
118
+ },
119
+ });
91
120
 
92
121
  const handleToggleStrategy = async (strategyId: string, enabled: boolean) => {
93
- try {
94
- await authClient.updateStrategy({ id: strategyId, enabled });
95
- await onDataChange();
96
- } catch (error: unknown) {
97
- const message =
98
- error instanceof Error ? error.message : "Failed to toggle strategy";
99
- toast.error(message);
100
- }
122
+ await updateStrategyMutation.mutateAsync({ id: strategyId, enabled });
101
123
  };
102
124
 
103
125
  const handleSaveStrategyConfig = async (
104
126
  strategyId: string,
105
127
  config: Record<string, unknown>
106
128
  ) => {
107
- try {
108
- const strategy = strategies.find((s) => s.id === strategyId);
109
- if (!strategy) {
110
- toast.error("Strategy not found");
111
- return;
112
- }
113
- setStrategyConfigs({
114
- ...strategyConfigs,
115
- [strategyId]: config,
116
- });
117
- await authClient.updateStrategy({
118
- id: strategyId,
119
- enabled: strategy.enabled,
120
- config,
121
- });
122
- toast.success(
123
- "Configuration saved successfully! Click 'Reload Authentication' to apply changes."
124
- );
125
- } catch (error: unknown) {
126
- const message =
127
- error instanceof Error
128
- ? error.message
129
- : "Failed to save strategy configuration";
130
- toast.error(message);
129
+ const strategy = strategies.find((s) => s.id === strategyId);
130
+ if (!strategy) {
131
+ toast.error("Strategy not found");
132
+ return;
131
133
  }
134
+ setStrategyConfigs({
135
+ ...strategyConfigs,
136
+ [strategyId]: config,
137
+ });
138
+ await updateStrategyMutation.mutateAsync({
139
+ id: strategyId,
140
+ enabled: strategy.enabled,
141
+ config,
142
+ });
143
+ toast.success(
144
+ "Configuration saved successfully! Click 'Reload Authentication' to apply changes."
145
+ );
132
146
  };
133
147
 
134
- const handleSaveRegistration = async () => {
135
- setSavingRegistration(true);
136
- try {
137
- await authClient.setRegistrationStatus(registrationSettings);
138
- toast.success("Registration settings saved successfully");
139
- } catch (error: unknown) {
140
- toast.error(
141
- error instanceof Error
142
- ? error.message
143
- : "Failed to save registration settings"
144
- );
145
- } finally {
146
- setSavingRegistration(false);
147
- }
148
+ const handleSaveRegistration = () => {
149
+ setRegistrationMutation.mutate(registrationSettings);
148
150
  };
149
151
 
150
- const handleReloadAuth = async () => {
152
+ const handleReloadAuth = () => {
151
153
  setReloading(true);
152
- try {
153
- await authClient.reloadAuth();
154
- toast.success("Authentication system reloaded successfully");
155
- await onDataChange();
156
- } catch (error: unknown) {
157
- toast.error(
158
- error instanceof Error
159
- ? error.message
160
- : "Failed to reload authentication"
161
- );
162
- } finally {
163
- setReloading(false);
164
- }
154
+ reloadAuthMutation.mutate({});
165
155
  };
166
156
 
167
157
  const enabledStrategies = strategies.filter((s) => s.enabled);
@@ -183,7 +173,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
183
173
  ) : registrationSchema ? (
184
174
  <div className="space-y-4">
185
175
  <DynamicForm
186
- schema={registrationSchema}
176
+ schema={registrationSchema as Record<string, unknown>}
187
177
  value={registrationSettings}
188
178
  onChange={(value) =>
189
179
  setRegistrationSettings(
@@ -193,10 +183,14 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
193
183
  onValidChange={setRegistrationValid}
194
184
  />
195
185
  <Button
196
- onClick={() => void handleSaveRegistration()}
197
- disabled={savingRegistration || !registrationValid}
186
+ onClick={handleSaveRegistration}
187
+ disabled={
188
+ setRegistrationMutation.isPending || !registrationValid
189
+ }
198
190
  >
199
- {savingRegistration ? "Saving..." : "Save Settings"}
191
+ {setRegistrationMutation.isPending
192
+ ? "Saving..."
193
+ : "Save Settings"}
200
194
  </Button>
201
195
  </div>
202
196
  ) : (
@@ -206,7 +200,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
206
200
  )
207
201
  ) : (
208
202
  <p className="text-sm text-muted-foreground">
209
- You don't have permission to manage registration settings.
203
+ You don't have access to manage registration settings.
210
204
  </p>
211
205
  )}
212
206
  </CardContent>
@@ -268,7 +262,7 @@ export const StrategiesTab: React.FC<StrategiesTabProps> = ({
268
262
 
269
263
  {!canManageStrategies && (
270
264
  <p className="text-xs text-muted-foreground mt-4">
271
- You don't have permission to manage strategies.
265
+ You don't have access to manage strategies.
272
266
  </p>
273
267
  )}
274
268
  </div>