From 68097cf7004f3d7f1d6e5ff57f7adf5b001f513d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 11:18:06 +0000 Subject: [PATCH] feat: add quick presets for API token permission selection Add preset buttons (Read Only, Task Management, Project Management, Full Access) to the API token creation form so users don't have to manually select every individual permission. https://claude.ai/code/session_01QDWqXJmjriYoAcvMD43vmx --- frontend/src/i18n/lang/en.json | 7 ++ .../src/views/user/settings/ApiTokens.vue | 100 ++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/frontend/src/i18n/lang/en.json b/frontend/src/i18n/lang/en.json index 3d4b43c12..91ec114d3 100644 --- a/frontend/src/i18n/lang/en.json +++ b/frontend/src/i18n/lang/en.json @@ -207,6 +207,13 @@ "tokenCreatedSuccess": "Here is your new api token: {token}", "tokenCreatedNotSeeAgain": "Store it in a secure location, you won't see it again!", "selectAll": "Select all", + "presets": { + "title": "Quick presets", + "readOnly": "Read only", + "tasks": "Task management", + "projects": "Project management", + "fullAccess": "Full access" + }, "delete": { "header": "Delete this token", "text1": "Are you sure you want to delete the token \"{token}\"?", diff --git a/frontend/src/views/user/settings/ApiTokens.vue b/frontend/src/views/user/settings/ApiTokens.vue index 6c7f81624..4399b729a 100644 --- a/frontend/src/views/user/settings/ApiTokens.vue +++ b/frontend/src/views/user/settings/ApiTokens.vue @@ -41,6 +41,86 @@ const route = useRoute() const now = new Date() +interface TokenPreset { + id: string + groups: Record +} + +const presets: TokenPreset[] = [ + { + id: 'readOnly', + groups: { + '*': ['read_one', 'read_all'], + }, + }, + { + id: 'tasks', + groups: { + 'tasks': '*', + 'tasks_attachments': '*', + 'tasks_assignees': '*', + 'tasks_labels': '*', + 'tasks_comments': '*', + 'tasks_relations': '*', + 'labels': ['read_one', 'read_all', 'create'], + 'projects': ['read_one', 'read_all'], + 'projects_views': ['read_one', 'read_all'], + 'projects_views_tasks': ['read_one', 'read_all'], + }, + }, + { + id: 'projects', + groups: { + 'projects': '*', + 'projects_views': '*', + 'projects_teams': '*', + 'projects_users': '*', + 'projects_shares': '*', + 'projects_webhooks': '*', + 'projects_buckets': '*', + 'projects_views_tasks': '*', + 'tasks': ['read_one', 'read_all'], + 'teams': ['read_one', 'read_all'], + }, + }, + { + id: 'fullAccess', + groups: { + '*': '*', + }, + }, +] + +function applyPreset(preset: TokenPreset) { + resetPermissions() + + for (const [groupKey, permissions] of Object.entries(preset.groups)) { + if (groupKey === '*') { + // Apply to all groups + for (const group of Object.keys(availableRoutes.value)) { + applyPermissionsToGroup(group, permissions) + } + } else if (availableRoutes.value[groupKey]) { + applyPermissionsToGroup(groupKey, permissions) + } + } +} + +function applyPermissionsToGroup(group: string, permissions: string[] | '*') { + if (permissions === '*') { + // Select all permissions in this group + selectPermissionGroup(group, true) + newTokenPermissionsGroup.value[group] = true + } else { + for (const perm of permissions) { + if (newTokenPermissions.value[group]?.[perm] !== undefined) { + newTokenPermissions.value[group][perm] = true + } + } + toggleGroupPermissionsFromChild(group, true) + } +} + const flatPickerConfig = computed(() => ({ altFormat: t('date.altFormatLong'), altInput: true, @@ -334,6 +414,26 @@ function toggleGroupPermissionsFromChild(group: string, checked: boolean) {

{{ $t('user.settings.apiTokens.permissionExplanation') }}

+ + +
+ +
+ + {{ $t(`user.settings.apiTokens.presets.${preset.id}`) }} + +
+
+