-
This commit is contained in:
@ -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) => (
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -56,7 +56,7 @@ const Tokens: React.FC = () => {
|
||||
initialValues: {
|
||||
app_id: '',
|
||||
owner: {
|
||||
type: 'user',
|
||||
type: 'individual',
|
||||
name: 'Admin User',
|
||||
owner: 'admin@example.com',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user