From dc0ea9d4c7eb0da9af98aea763a350ca6795f6f0 Mon Sep 17 00:00:00 2001 From: Ryan Copley Date: Wed, 27 Aug 2025 12:46:16 -0400 Subject: [PATCH] - --- kms/web/src/components/Applications.tsx | 36 +++++++-- kms/web/src/components/PermissionTree.tsx | 94 +++++++++-------------- kms/web/src/components/Tokens.tsx | 2 +- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/kms/web/src/components/Applications.tsx b/kms/web/src/components/Applications.tsx index 6bfd496..2f2ce4c 100644 --- a/kms/web/src/components/Applications.tsx +++ b/kms/web/src/components/Applications.tsx @@ -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) => ( diff --git a/kms/web/src/components/PermissionTree.tsx b/kms/web/src/components/PermissionTree.tsx index 7b00d95..08ed4df 100644 --- a/kms/web/src/components/PermissionTree.tsx +++ b/kms/web/src/components/PermissionTree.tsx @@ -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 = ({ 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 = ({ 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 = ({ permissions, onChange } onChange={(event) => handleNodeChange(node, event.currentTarget.checked)} size="sm" style={{ marginTop: '1px' }} - disabled={!node.children && isChildDisabled(node.id)} /> @@ -254,7 +238,6 @@ const PermissionTree: React.FC = ({ permissions, onChange } {node.label} {hasChildren && ' (all)'} @@ -263,10 +246,7 @@ const PermissionTree: React.FC = ({ permissions, onChange } - {node.description} diff --git a/kms/web/src/components/Tokens.tsx b/kms/web/src/components/Tokens.tsx index e8a990b..288dabe 100644 --- a/kms/web/src/components/Tokens.tsx +++ b/kms/web/src/components/Tokens.tsx @@ -56,7 +56,7 @@ const Tokens: React.FC = () => { initialValues: { app_id: '', owner: { - type: 'user', + type: 'individual', name: 'Admin User', owner: 'admin@example.com', },