This commit is contained in:
2025-08-27 12:46:16 -04:00
parent a641b4e2d1
commit dc0ea9d4c7
3 changed files with 66 additions and 66 deletions

View File

@ -49,7 +49,7 @@ const Applications: React.FC = () => {
token_renewal_duration: '24h',
max_token_duration: '168h',
owner: {
type: 'user',
type: 'individual',
name: 'Admin User',
owner: 'admin@example.com',
},
@ -82,17 +82,40 @@ const Applications: React.FC = () => {
}
};
const parseDuration = (duration: string): number => {
// Convert duration string like "24h" to seconds
const match = duration.match(/^(\d+)([hmd]?)$/);
if (!match) return 86400; // Default to 24h in seconds
const value = parseInt(match[1]);
const unit = match[2] || 'h';
switch (unit) {
case 'm': return value * 60; // minutes to seconds
case 'h': return value * 3600; // hours to seconds
case 'd': return value * 86400; // days to seconds
default: return value * 3600; // default to hours
}
};
const handleSubmit = async (values: CreateApplicationRequest) => {
try {
// Convert duration strings to seconds for API
const apiValues = {
...values,
token_renewal_duration: parseDuration(values.token_renewal_duration),
max_token_duration: parseDuration(values.max_token_duration),
};
if (editingApp) {
await apiService.updateApplication(editingApp.app_id, values);
await apiService.updateApplication(editingApp.app_id, apiValues);
notifications.show({
title: 'Success',
message: 'Application updated successfully',
color: 'green',
});
} else {
await apiService.createApplication(values);
await apiService.createApplication(apiValues);
notifications.show({
title: 'Success',
message: 'Application created successfully',
@ -164,11 +187,8 @@ const Applications: React.FC = () => {
};
const appTypeOptions = [
{ value: 'web', label: 'Web Application' },
{ value: 'mobile', label: 'Mobile Application' },
{ value: 'api', label: 'API Service' },
{ value: 'cli', label: 'CLI Tool' },
{ value: 'service', label: 'Background Service' },
{ value: 'static', label: 'Static' },
{ value: 'user', label: 'User' },
];
const rows = applications.map((app) => (

View File

@ -27,12 +27,12 @@ const permissionHierarchy: PermissionNode[] = [
{
id: 'app',
label: 'Application',
description: 'Full control of applications',
description: 'Access to application management',
children: [
{
id: 'app.read',
label: 'Read',
description: 'View application details',
description: 'Read application information',
},
{
id: 'app.write',
@ -49,12 +49,12 @@ const permissionHierarchy: PermissionNode[] = [
{
id: 'token',
label: 'Token',
description: 'Full control of tokens',
description: 'Access to token management',
children: [
{
id: 'token.read',
label: 'Read',
description: 'View token details',
description: 'Read token information',
},
{
id: 'token.create',
@ -71,39 +71,49 @@ const permissionHierarchy: PermissionNode[] = [
{
id: 'repo',
label: 'Repository',
description: 'Full control of repositories',
description: 'Access to repository operations',
children: [
{
id: 'repo.read',
label: 'Read',
description: 'Read repository contents',
description: 'Read repository data',
},
{
id: 'repo.write',
label: 'Write',
description: 'Push to repositories',
description: 'Write to repositories',
},
{
id: 'repo.admin',
label: 'Admin',
description: 'Full repository administration',
description: 'Administrative access to repositories',
},
],
},
{
id: 'permission',
label: 'Permission',
description: 'Full control of permissions',
description: 'Access to permission management',
children: [
{
id: 'permission.read',
label: 'Read',
description: 'View permission details',
description: 'Read permission information',
},
{
id: 'permission.write',
label: 'Write',
description: 'Modify permissions',
description: 'Create and update permissions',
},
{
id: 'permission.grant',
label: 'Grant',
description: 'Grant permissions to tokens',
},
{
id: 'permission.revoke',
label: 'Revoke',
description: 'Revoke permissions from tokens',
},
],
},
@ -130,37 +140,16 @@ const PermissionTree: React.FC<PermissionTreeProps> = ({ permissions, onChange }
});
};
const isChildDisabled = (childId: string): boolean => {
// Find the parent of this child
for (const parent of permissionHierarchy) {
if (parent.children?.some(child => child.id === childId)) {
const wildcardPermission = `${parent.id}.*`;
return permissions.includes(wildcardPermission);
}
}
return false;
};
const getNodeState = (node: PermissionNode): 'checked' | 'indeterminate' | 'unchecked' => {
if (!node.children) {
// For leaf nodes, check if they're explicitly selected OR their parent wildcard is selected
const isExplicitlySelected = permissions.includes(node.id);
const isParentWildcardSelected = isChildDisabled(node.id);
return (isExplicitlySelected || isParentWildcardSelected) ? 'checked' : 'unchecked';
// For leaf nodes, check if they're explicitly selected
return permissions.includes(node.id) ? 'checked' : 'unchecked';
}
// Check if parent wildcard permission exists
const wildcardPermission = `${node.id}.*`;
if (permissions.includes(wildcardPermission)) {
return 'checked';
}
// Check children states
const checkedChildren = node.children.filter(child => {
const isExplicitlySelected = permissions.includes(child.id);
const isParentWildcardSelected = permissions.includes(wildcardPermission);
return isExplicitlySelected || isParentWildcardSelected;
});
// For parent nodes, check how many children are selected
const checkedChildren = node.children.filter(child =>
permissions.includes(child.id)
);
if (checkedChildren.length === 0) {
return 'unchecked';
@ -184,23 +173,19 @@ const PermissionTree: React.FC<PermissionTreeProps> = ({ permissions, onChange }
newPermissions = newPermissions.filter(p => p !== node.id);
}
} else {
// Parent node
const wildcardPermission = `${node.id}.*`;
// Parent node - add/remove all child permissions individually
if (checked) {
// Add wildcard permission and remove specific child permissions
if (!newPermissions.includes(wildcardPermission)) {
newPermissions.push(wildcardPermission);
}
// Remove specific child permissions as they're covered by wildcard
// Add all child permissions
node.children.forEach(child => {
if (!newPermissions.includes(child.id)) {
newPermissions.push(child.id);
}
});
} else {
// Remove all child permissions
node.children.forEach(child => {
newPermissions = newPermissions.filter(p => p !== child.id);
});
} else {
// Remove wildcard permission and all child permissions
newPermissions = newPermissions.filter(p =>
p !== wildcardPermission && !node.children!.some(child => child.id === p)
);
}
}
@ -246,7 +231,6 @@ const PermissionTree: React.FC<PermissionTreeProps> = ({ permissions, onChange }
onChange={(event) => handleNodeChange(node, event.currentTarget.checked)}
size="sm"
style={{ marginTop: '1px' }}
disabled={!node.children && isChildDisabled(node.id)}
/>
<Box style={{ flex: 1 }}>
@ -254,7 +238,6 @@ const PermissionTree: React.FC<PermissionTreeProps> = ({ permissions, onChange }
<Text
size="sm"
fw={hasChildren ? 600 : 500}
c={!node.children && isChildDisabled(node.id) ? 'dimmed' : undefined}
>
{node.label}
{hasChildren && ' (all)'}
@ -263,10 +246,7 @@ const PermissionTree: React.FC<PermissionTreeProps> = ({ permissions, onChange }
<Text
size="xs"
c="dimmed"
style={{
whiteSpace: 'nowrap',
opacity: !node.children && isChildDisabled(node.id) ? 0.6 : 1
}}
style={{ whiteSpace: 'nowrap' }}
>
- {node.description}
</Text>

View File

@ -56,7 +56,7 @@ const Tokens: React.FC = () => {
initialValues: {
app_id: '',
owner: {
type: 'user',
type: 'individual',
name: 'Admin User',
owner: 'admin@example.com',
},