handleRedirectUriChange(index, e.target.value)}
@@ -238,6 +275,7 @@ export function ClientForm({ client }: ClientFormProps) {
type="button"
variant="ghost"
size="icon"
+ data-testid={`remove-redirect-uri-${index}`}
onClick={() => handleRemoveRedirectUri(index)}
disabled={isPending}
>
@@ -250,6 +288,7 @@ export function ClientForm({ client }: ClientFormProps) {
type="button"
variant="outline"
size="sm"
+ data-testid="add-redirect-uri"
onClick={handleAddRedirectUri}
disabled={isPending}
>
@@ -264,19 +303,124 @@ export function ClientForm({ client }: ClientFormProps) {
Scopes this application can request
-
- {SUPPORTED_SCOPES.map((scope) => (
-
- ))}
+
+ {/* Special Scopes (openid, offline_access) */}
+ {SPECIAL_SCOPES.map((scope) => {
+ const isSelected = allowedScopes.includes(scope.key);
+ const isRequired = scope.required;
+ return (
+
+ );
+ })}
+
+ {/* Resource Scopes (grouped by resource) */}
+ {SCOPE_RESOURCES.map((resource) => {
+ const resourceScopes = getScopesByResource(resource.key);
+ const isFullySelected = isResourceFullySelected(resource.key);
+ const isPartiallySelected = isResourcePartiallySelected(resource.key);
+
+ return (
+
+ {/* Resource Header */}
+
+
+ {/* Operation Checkboxes */}
+
+ {resourceScopes.map((scope) => {
+ const isSelected = allowedScopes.includes(scope.key);
+ const op = OPERATIONS[scope.operation!];
+ const OpIcon = op.icon;
+
+ return (
+
+ );
+ })}
+
+
+ );
+ })}
@@ -284,6 +428,7 @@ export function ClientForm({ client }: ClientFormProps) {
setIsFirstParty(e.target.checked)}
disabled={isPending}
@@ -298,12 +443,13 @@ export function ClientForm({ client }: ClientFormProps) {
-