diff --git a/.gitignore b/.gitignore index c9089f1b9..60adfca77 100644 --- a/.gitignore +++ b/.gitignore @@ -48,5 +48,6 @@ devenv.local.nix # AI Tools /.claude/settings.local.json PLAN.md +plans/ /.crush/ /.playwright-mcp diff --git a/frontend/src/i18n/lang/en.json b/frontend/src/i18n/lang/en.json index 3d4b43c12..c65726dd9 100644 --- a/frontend/src/i18n/lang/en.json +++ b/frontend/src/i18n/lang/en.json @@ -212,11 +212,16 @@ "text1": "Are you sure you want to delete the token \"{token}\"?", "text2": "This will revoke access to all applications or integrations using it. You cannot undo this." }, + "projectScopeExplanation": "Optionally restrict this token to a specific project. Leave empty for access to all projects.", + "includeSubProjects": "Include sub-projects", + "allProjects": "All projects", + "withSubProjects": "+ sub-projects", "attributes": { "title": "Title", "titlePlaceholder": "Enter a title you will recognize later", "expiresAt": "Expires at", - "permissions": "Permissions" + "permissions": "Permissions", + "projectScope": "Project scope" } }, "sessions": { diff --git a/frontend/src/modelTypes/IApiToken.ts b/frontend/src/modelTypes/IApiToken.ts index 189549c4d..1ee14d2e4 100644 --- a/frontend/src/modelTypes/IApiToken.ts +++ b/frontend/src/modelTypes/IApiToken.ts @@ -10,5 +10,7 @@ export interface IApiToken extends IAbstract { token: string permissions: IApiPermission expiresAt: Date + projectId: number + includeSubProjects: boolean created: Date } diff --git a/frontend/src/models/apiTokenModel.ts b/frontend/src/models/apiTokenModel.ts index a23227004..c17dac368 100644 --- a/frontend/src/models/apiTokenModel.ts +++ b/frontend/src/models/apiTokenModel.ts @@ -7,6 +7,8 @@ export default class ApiTokenModel extends AbstractModel { token = '' permissions = null expiresAt: Date = null + projectId = 0 + includeSubProjects = false created: Date = null constructor(data: Partial = {}) { diff --git a/frontend/src/views/user/settings/ApiTokens.vue b/frontend/src/views/user/settings/ApiTokens.vue index 6c7f81624..d61543398 100644 --- a/frontend/src/views/user/settings/ApiTokens.vue +++ b/frontend/src/views/user/settings/ApiTokens.vue @@ -16,6 +16,9 @@ import {useI18n} from 'vue-i18n' import Message from '@/components/misc/Message.vue' import FormField from '@/components/input/FormField.vue' import type {IApiToken} from '@/modelTypes/IApiToken' +import type {IProject} from '@/modelTypes/IProject' +import ProjectSearch from '@/components/tasks/partials/ProjectSearch.vue' +import {useProjectStore} from '@/stores/projects' const service = new ApiTokenService() const tokens = ref([]) @@ -32,9 +35,14 @@ const newTokenPermissionValid = ref(true) const apiTokenTitle = ref() const tokenCreatedSuccessMessage = ref('') +const selectedProject = ref(null) +const includeSubProjects = ref(false) + const showDeleteModal = ref(false) const tokenToDelete = ref() +const projectStore = useProjectStore() + const {t} = useI18n() const route = useRoute() @@ -158,11 +166,16 @@ async function createToken() { newToken.value.expiresAt = new Date(newTokenExpiryCustom.value) } + newToken.value.projectId = selectedProject.value?.id || 0 + newToken.value.includeSubProjects = selectedProject.value ? includeSubProjects.value : false + const token = await service.create(newToken.value) tokenCreatedSuccessMessage.value = t('user.settings.apiTokens.tokenCreatedSuccess', {token: token.token}) newToken.value = new ApiTokenModel() newTokenExpiry.value = 30 newTokenExpiryCustom.value = new Date() + selectedProject.value = null + includeSubProjects.value = false resetPermissions() tokens.value.push(token) showCreateForm.value = false @@ -226,6 +239,7 @@ function toggleGroupPermissionsFromChild(group: string, checked: boolean) { {{ $t('misc.id') }} {{ $t('user.settings.apiTokens.attributes.title') }} + {{ $t('user.settings.apiTokens.attributes.projectScope') }} {{ $t('user.settings.apiTokens.attributes.permissions') }} {{ $t('user.settings.apiTokens.attributes.expiresAt') }} {{ $t('misc.created') }} @@ -241,6 +255,23 @@ function toggleGroupPermissionsFromChild(group: string, checked: boolean) { > {{ tk.id }} {{ tk.title }} + + + + {{ $t('user.settings.apiTokens.allProjects') }} + +