Skip to content

Conversation

@sangeethailango
Copy link
Member

@sangeethailango sangeethailango commented Dec 29, 2025

Description

Implementation of workspace api tokens.

Type of Change

  • Feature (non-breaking change which adds functionality)

Summary by CodeRabbit

  • New Features

    • Added workspace-scoped API token management, allowing admins to create and manage tokens at the workspace level.
    • Implemented dynamic rate limiting for workspace API tokens with customizable request limits.
    • Introduced new workspace settings page for access token management with create, view, and delete capabilities.
  • Documentation

    • Updated UI labels and descriptions across 20+ languages to reflect access token terminology and management workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

sangeethailango and others added 19 commits December 15, 2025 15:44
- Added WorkspaceAPITokenEndpoint for managing API tokens within specific workspaces.
- Enhanced APITokenSerializer to associate tokens with workspaces and users.
- Updated URL routing to include endpoints for workspace API tokens.
- Introduced ServiceApiTokenEndpoint for handling service tokens linked to workspaces.
- Created base views for API token operations, including create, read, update, and delete functionalities.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

This pull request introduces workspace-scoped API token management, enabling administrators to create and manage API tokens bound to specific workspaces. The backend adds workspace validation in authentication middleware, dynamic rate limiting per workspace token, and new REST endpoints. The frontend provides a dedicated workspace settings page for token CRUD operations. Internationalization and services are updated to support the new workspace-scoped functionality.

Changes

Cohort / File(s) Summary
Backend Authentication & Rate Limiting
apps/api/plane/api/middleware/api_authentication.py, apps/api/plane/api/rate_limit.py, apps/api/plane/api/views/base.py
Workspace-scoped API token validation: middleware now enforces token belongs to requested workspace; new WorkspaceTokenRateThrottle class extracts rate limits from token metadata; base view routing updated to select appropriate throttle based on token type (service vs. workspace-scoped).
Backend API Views & Endpoints
apps/api/plane/app/views/api/base.py, apps/api/plane/app/views/api/service.py, apps/api/plane/app/views/api/workspace.py
Removed global ServiceApiTokenEndpoint from base; relocated to dedicated service.py with POST-only endpoint for workspace service tokens. New WorkspaceAPITokenEndpoint (workspace.py) provides full CRUD (POST/GET/DELETE) for workspace-scoped personal tokens; uses WorkSpaceAdminPermission for access control.
Backend Routing & Serializers
apps/api/plane/app/urls/api.py, apps/api/plane/app/serializers/api.py, apps/api/plane/app/views/__init__.py, apps/api/plane/app/views/api/__init__.py
Two new URL patterns for workspace API tokens (list and detail). Updated serializer imports for consistency. Exports expanded to surface new endpoint classes.
Frontend: Workspace API Tokens Page
apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
New full-featured settings page for workspace API tokens: fetches tokens via WorkspaceAPITokenService, enforces admin permission, renders token list or empty state with CTA, integrates modals for create/delete flows with event tracking.
Frontend: Account API Tokens Page
apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
Refactored ApiTokensPage component: converted to typed FC with mobx observer; updated title source from workspace to account settings i18n keys; adjusted empty state and modal integration.
Frontend: Token Components
apps/web/core/components/api-token/modal/create-token-modal.tsx, apps/web/core/components/api-token/delete-token-modal.tsx, apps/web/core/components/api-token/token-list-item.tsx, apps/web/core/components/ui/loader/settings/api-token.tsx
All components extended with optional workspaceSlug prop to support workspace-scoped workflows; conditional service/API routing and event tracking based on workspace context; loader component now accepts title as prop instead of hard-coding translation.
Frontend: Routes & UI Configuration
apps/web/app/routes/core.ts, apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
New route for workspace access-tokens page; new icon (KeyRound) added to workspace settings sidebar.
Constants: Settings & Fetch Keys
packages/constants/src/workspace.ts, packages/constants/src/settings.ts, apps/web/core/constants/fetch-keys.ts
New workspace setting "access-tokens" with admin-only access and routing; added to GROUPED_WORKSPACE_SETTINGS under DEVELOPER category; new fetch key generator WORKSPACE_API_TOKENS_LIST(workspaceSlug).
Constants: Event Tracking
packages/constants/src/event-tracker/core.ts
New workspace-scoped PAT tracking events (pat_created, pat_deleted) and UI elements (HEADER_ADD_PAT_BUTTON, EMPTY_STATE_ADD_PAT_BUTTON, LIST_ITEM_DELETE_ICON) added to WORKSPACE_SETTINGS_TRACKER_EVENTS and WORKSPACE_SETTINGS_TRACKER_ELEMENTS.
Services
packages/services/src/developer/workspace-api-token.service.ts, packages/services/src/developer/index.ts
New WorkspaceAPITokenService class providing list(), retrieve(), create(), and destroy() methods for workspace-scoped token operations; exported from developer services index.
Internationalization
packages/i18n/src/locales/*/translations.ts (20 languages: cs, de, en, es, fr, id, it, ja, ko, pl, pt-BR, ro, ru, sk, tr-TR, ua, vi-VN, zh-CN, zh-TW)
Consistent additions across all locales: new heading and description fields for workspace API tokens section; add_token label updated from "API token" to "access token" phrasing (localized). English locale also renamed account settings heading to title.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Rationale: The PR spans backend authentication logic (middleware + rate limiting + new endpoints), frontend page & component refactoring, service layer additions, settings/routing configuration, and extensive i18n updates across 20+ locales. While individual changes follow consistent patterns, the heterogeneous scope (backend control flow, frontend UI state, new service abstractions, and translation consistency) requires varied reasoning for each cohort. The authentication middleware changes and new endpoint implementations are logic-dense and warrant careful review.

Poem

🐰 A Token's Tale

With workspaces now scoped, our tokens take flight,
Each secured to its home, permissions ring right.
Rate-limited wisely, authenticated with care,
Access tokens bloom in the admin's fair square! 🔑✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete. It lacks required sections: detailed description of changes, test scenarios, screenshots/media, and references/issue links. Add a comprehensive description of the implementation, test scenarios that were executed, relevant screenshots showing the workspace tokens feature, and link to related issues (e.g., WEB-5512, PR #8339).
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main feature being added: workspace API tokens functionality.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@makeplane
Copy link

makeplane bot commented Dec 29, 2025

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@sangeethailango sangeethailango marked this pull request as ready for review December 29, 2025 09:39
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/web/app/routes/core.ts (1)

257-283: Path conflict between new workspace API tokens route and existing redirect

You now have two route entries for the exact same path :workspaceSlug/settings/api-tokens:

  • Workspace settings page route under the settings layout (Lines 257‑283).
  • Legacy redirect route sending the same path to routes/redirects/core/api-tokens.tsx (Lines 395‑397).

This duplication is likely to cause one of these behaviors (depending on how @react-router/dev resolves siblings):

  • The redirect still fires and makes the new workspace API tokens page unreachable.
  • Or the redirect becomes dead/never used, leaving stale behavior in the config.

Given the PR’s goal (workspace‑scoped API tokens), this path should probably resolve directly to the new workspace settings page, and the legacy redirect should either be deleted or updated to point somewhere else.

I recommend cleaning this up so there is a single, unambiguous route for :workspaceSlug/settings/api-tokens.

Proposed cleanup options

Option A — Remove legacy redirect if no longer needed:

-  // API tokens redirect: /:workspaceSlug/settings/api-tokens
-  // → /:workspaceSlug/settings/account/api-tokens
-  route(":workspaceSlug/settings/api-tokens", "routes/redirects/core/api-tokens.tsx"),

Option B — Keep redirect but move it to a different deprecated path (if you still need one), and let the new workspace settings route own :workspaceSlug/settings/api-tokens exclusively.

Also applies to: 395-397

apps/api/plane/app/views/api/base.py (2)

47-50: Add workspace filter to DELETE method for security.

The DELETE method is missing the workspace_id__isnull=True filter that was added to the GET methods. This could allow users to delete workspace-scoped tokens through the user token endpoint, bypassing workspace-level permissions.

🔎 Proposed fix
 def delete(self, request: Request, pk: str) -> Response:
-    api_token = APIToken.objects.get(user=request.user, pk=pk, is_service=False)
+    api_token = APIToken.objects.get(user=request.user, pk=pk, is_service=False, workspace_id__isnull=True)
     api_token.delete()
     return Response(status=status.HTTP_204_NO_CONTENT)

52-58: Add workspace filter to PATCH method for security.

The PATCH method is missing the workspace_id__isnull=True filter that was added to the GET methods. This could allow users to modify workspace-scoped tokens through the user token endpoint, bypassing workspace-level permissions.

🔎 Proposed fix
 def patch(self, request: Request, pk: str) -> Response:
-    api_token = APIToken.objects.get(user=request.user, pk=pk)
+    api_token = APIToken.objects.get(user=request.user, pk=pk, workspace_id__isnull=True)
     serializer = APITokenSerializer(api_token, data=request.data, partial=True)
     if serializer.is_valid():
         serializer.save()
🧹 Nitpick comments (2)
apps/api/plane/api/rate_limit.py (1)

114-124: Consider extracting duplicated rate-limit header logic.

The allow_request logic for computing X-RateLimit-Remaining and X-RateLimit-Reset headers is repeated across ApiKeyRateThrottle, ServiceTokenRateThrottle, and WorkspaceTokenRateThrottle. Consider extracting this into a shared mixin or base class to reduce duplication and ensure consistency.

apps/api/plane/api/middleware/api_authentication.py (1)

44-46: Consider reducing database writes for last_used updates.

Updating last_used on every successful authentication adds a write operation per request. For high-traffic endpoints, consider:

  • Batching updates asynchronously
  • Using a sampling approach (update every N requests)
  • Caching with periodic flush

This is a minor performance consideration and may be acceptable depending on traffic patterns.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 630d2b9 and ae0550e.

📒 Files selected for processing (48)
  • apps/api/plane/api/middleware/api_authentication.py
  • apps/api/plane/api/rate_limit.py
  • apps/api/plane/api/views/base.py
  • apps/api/plane/app/serializers/api.py
  • apps/api/plane/app/urls/api.py
  • apps/api/plane/app/views/__init__.py
  • apps/api/plane/app/views/api/__init__.py
  • apps/api/plane/app/views/api/base.py
  • apps/api/plane/app/views/api/service.py
  • apps/api/plane/app/views/api/workspace.py
  • apps/api/plane/db/migrations/0113_webhook_version.py
  • apps/api/plane/db/models/api.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/db/models/webhook.py
  • apps/api/plane/db/models/workspace.py
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • apps/web/app/routes/core.ts
  • apps/web/core/components/api-token/delete-token-modal.tsx
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
  • apps/web/core/components/api-token/token-list-item.tsx
  • apps/web/core/components/ui/loader/settings/api-token.tsx
  • apps/web/core/constants/fetch-keys.ts
  • packages/constants/src/event-tracker/core.ts
  • packages/constants/src/settings.ts
  • packages/constants/src/workspace.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/en/translations.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • packages/i18n/src/locales/tr-TR/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/services/src/developer/index.ts
  • packages/services/src/developer/workspace-api-token.service.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}

📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{ts,tsx,mts,cts}: Use const type parameters for more precise literal inference in TypeScript 5.0+
Use the satisfies operator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicit is return types in filter/check functions
Use NoInfer<T> utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing in switch(true) blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacy experimentalDecorators
Use using declarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Use with { type: "json" } for import attributes; avoid deprecated assert syntax (TypeScript 5.3/5.8+)
Use import type explicitly when importing types to ensure they are erased during compilation, respecting verbatimModuleSyntax flag
Use .ts, .mts, .cts extensions in import type statements (TypeScript 5.2+)
Use import type { Type } from "mod" with { "resolution-mode": "import" } for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize new Set methods like union, intersection, etc., when available (TypeScript 5.5+)
Use Object.groupBy / Map.groupBy standard methods for grouping instead of external libraries (TypeScript 5.4+)
Use Promise.withResolvers() for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted, toSpliced, with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields via super in classes (TypeScript 5....

Files:

  • apps/web/core/constants/fetch-keys.ts
  • packages/services/src/developer/index.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • apps/web/core/components/ui/loader/settings/api-token.tsx
  • packages/constants/src/workspace.ts
  • packages/constants/src/settings.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/routes/core.ts
  • apps/web/core/components/api-token/token-list-item.tsx
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/constants/src/event-tracker/core.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/services/src/developer/workspace-api-token.service.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • apps/web/core/components/api-token/delete-token-modal.tsx
  • packages/i18n/src/locales/tr-TR/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
  • packages/i18n/src/locales/en/translations.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enable TypeScript strict mode and ensure all files are fully typed

Files:

  • apps/web/core/constants/fetch-keys.ts
  • packages/services/src/developer/index.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • apps/web/core/components/ui/loader/settings/api-token.tsx
  • packages/constants/src/workspace.ts
  • packages/constants/src/settings.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/routes/core.ts
  • apps/web/core/components/api-token/token-list-item.tsx
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/constants/src/event-tracker/core.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/services/src/developer/workspace-api-token.service.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • apps/web/core/components/api-token/delete-token-modal.tsx
  • packages/i18n/src/locales/tr-TR/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
  • packages/i18n/src/locales/en/translations.ts
**/*.{js,jsx,ts,tsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with Tailwind plugin for code formatting, run pnpm fix:format

Files:

  • apps/web/core/constants/fetch-keys.ts
  • packages/services/src/developer/index.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • apps/web/core/components/ui/loader/settings/api-token.tsx
  • packages/constants/src/workspace.ts
  • packages/constants/src/settings.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/routes/core.ts
  • apps/web/core/components/api-token/token-list-item.tsx
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/constants/src/event-tracker/core.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/services/src/developer/workspace-api-token.service.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • apps/web/core/components/api-token/delete-token-modal.tsx
  • packages/i18n/src/locales/tr-TR/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
  • packages/i18n/src/locales/en/translations.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately

Files:

  • apps/web/core/constants/fetch-keys.ts
  • packages/services/src/developer/index.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • apps/web/core/components/ui/loader/settings/api-token.tsx
  • packages/constants/src/workspace.ts
  • packages/constants/src/settings.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/routes/core.ts
  • apps/web/core/components/api-token/token-list-item.tsx
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/constants/src/event-tracker/core.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/services/src/developer/workspace-api-token.service.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • apps/web/core/components/api-token/delete-token-modal.tsx
  • packages/i18n/src/locales/tr-TR/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
  • packages/i18n/src/locales/en/translations.ts
🧠 Learnings (12)
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to **/package.json : Use `workspace:*` for internal packages and `catalog:` for external dependencies in imports

Applied to files:

  • apps/web/core/constants/fetch-keys.ts
  • packages/services/src/developer/index.ts
📚 Learning: 2025-09-02T08:14:49.260Z
Learnt from: sriramveeraghanta
Repo: makeplane/plane PR: 7697
File: apps/web/app/(all)/[workspaceSlug]/(projects)/header.tsx:12-13
Timestamp: 2025-09-02T08:14:49.260Z
Learning: The star-us-link.tsx file in apps/web/app/(all)/[workspaceSlug]/(projects)/ already has "use client" directive at the top, making it a proper Client Component for hook usage.

Applied to files:

  • packages/services/src/developer/index.ts
📚 Learning: 2025-10-21T17:22:05.204Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7989
File: apps/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx:45-46
Timestamp: 2025-10-21T17:22:05.204Z
Learning: In the makeplane/plane repository, the refactor from useParams() to params prop is specifically scoped to page.tsx and layout.tsx files in apps/web/app (Next.js App Router pattern). Other components (hooks, regular client components, utilities) should continue using the useParams() hook as that is the correct pattern for non-route components.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • apps/web/core/components/api-token/token-list-item.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
📚 Learning: 2025-07-23T18:18:06.875Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

Applied to files:

  • apps/api/plane/api/middleware/api_authentication.py
📚 Learning: 2025-12-23T14:18:32.899Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/models/api.py:35-35
Timestamp: 2025-12-23T14:18:32.899Z
Learning: Django REST Framework rate limit strings are flexible: only the first character of the time unit matters. Acceptable formats include: "60/s", "60/sec", "60/second" (all equivalent), "60/m", "60/min", "60/minute" (all equivalent), "60/h", "60/hr", "60/hour" (all equivalent), and "60/d", "60/day" (all equivalent). Abbreviations like "min" are valid and do not need to be changed to "minute". Apply this guidance to any Python files in the project that configure DRF throttling rules.

Applied to files:

  • apps/api/plane/api/middleware/api_authentication.py
  • apps/api/plane/api/views/base.py
  • apps/api/plane/app/views/api/__init__.py
  • apps/api/plane/app/views/__init__.py
  • apps/api/plane/db/models/workspace.py
  • apps/api/plane/api/rate_limit.py
  • apps/api/plane/db/models/api.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/app/views/api/workspace.py
  • apps/api/plane/app/views/api/base.py
  • apps/api/plane/app/serializers/api.py
  • apps/api/plane/db/migrations/0113_webhook_version.py
  • apps/api/plane/app/views/api/service.py
  • apps/api/plane/app/urls/api.py
  • apps/api/plane/db/models/webhook.py
📚 Learning: 2025-10-09T20:42:31.843Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T20:42:31.843Z
Learning: In the makeplane/plane repository, React types are globally available through TypeScript configuration. Type annotations like React.FC, React.ReactNode, etc. can be used without explicitly importing the React namespace. The codebase uses the modern JSX transform, so React imports are not required for JSX or type references.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • apps/web/core/components/api-token/token-list-item.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
  • apps/web/core/components/api-token/modal/create-token-modal.tsx
📚 Learning: 2025-10-01T15:30:17.605Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7888
File: packages/propel/src/avatar/avatar.stories.tsx:2-3
Timestamp: 2025-10-01T15:30:17.605Z
Learning: In the makeplane/plane repository, avoid suggesting inline type imports (e.g., `import { Avatar, type TAvatarSize }`) due to bundler compatibility issues. Keep type imports and value imports as separate statements.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
📚 Learning: 2025-05-14T13:16:23.323Z
Learnt from: vamsikrishnamathala
Repo: makeplane/plane PR: 7061
File: web/core/components/workspace-notifications/root.tsx:18-18
Timestamp: 2025-05-14T13:16:23.323Z
Learning: In the Plane project codebase, the path alias `@/plane-web` resolves to the `ce` directory, making imports like `@/plane-web/hooks/use-notification-preview` correctly resolve to files in `web/ce/hooks/`.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
📚 Learning: 2025-12-29T08:58:39.209Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/migrations/0113_webhook_version.py:7-14
Timestamp: 2025-12-29T08:58:39.209Z
Learning: In the Plane codebase, when adding product tour or onboarding fields via migrations, it's intentional to set existing records to `True` (completed) while having the model default to `False` for new records. This ensures existing users don't see tours they don't need.

Applied to files:

  • apps/api/plane/db/models/workspace.py
  • apps/api/plane/db/models/user.py
  • apps/api/plane/db/migrations/0113_webhook_version.py
📚 Learning: 2025-10-09T22:12:26.424Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T22:12:26.424Z
Learning: When `types/react` is installed in a TypeScript project (which is standard for React + TypeScript codebases), React types (React.FC, React.ReactNode, React.ComponentProps, etc.) are globally available by design. These type annotations can and should be used without explicitly importing the React namespace. This is a TypeScript/DefinitelyTyped feature, not codebase-specific configuration.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/shared-state/**/*.{ts,tsx} : Maintain MobX stores in `packages/shared-state` using reactive patterns

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx
📚 Learning: 2025-03-11T19:42:41.769Z
Learnt from: janreges
Repo: makeplane/plane PR: 6743
File: packages/i18n/src/store/index.ts:160-161
Timestamp: 2025-03-11T19:42:41.769Z
Learning: In the Plane project, the file 'packages/i18n/src/store/index.ts' already includes support for Polish language translations with the case "pl".

Applied to files:

  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/cs/translations.ts
🧬 Code graph analysis (15)
apps/web/core/constants/fetch-keys.ts (1)
apps/space/core/store/publish/publish.store.ts (1)
  • workspaceSlug (93-95)
packages/constants/src/settings.ts (1)
packages/constants/src/workspace.ts (1)
  • WORKSPACE_SETTINGS (74-117)
apps/api/plane/api/middleware/api_authentication.py (3)
apps/api/plane/db/models/api.py (1)
  • APIToken (19-44)
apps/api/plane/db/models/workspace.py (1)
  • Workspace (125-188)
apps/api/plane/tests/conftest.py (1)
  • api_token (46-53)
apps/api/plane/api/views/base.py (2)
apps/api/plane/api/rate_limit.py (3)
  • ApiKeyRateThrottle (9-47)
  • ServiceTokenRateThrottle (50-88)
  • WorkspaceTokenRateThrottle (91-126)
apps/api/plane/db/models/api.py (1)
  • APIToken (19-44)
apps/api/plane/app/views/api/__init__.py (3)
apps/api/plane/app/views/api/base.py (1)
  • ApiTokenEndpoint (16-58)
apps/api/plane/app/views/api/service.py (1)
  • ServiceApiTokenEndpoint (15-37)
apps/api/plane/app/views/api/workspace.py (1)
  • WorkspaceAPITokenEndpoint (18-59)
apps/api/plane/app/views/__init__.py (2)
apps/api/plane/app/views/api/base.py (1)
  • ApiTokenEndpoint (16-58)
apps/api/plane/app/views/api/workspace.py (1)
  • WorkspaceAPITokenEndpoint (18-59)
packages/services/src/developer/workspace-api-token.service.ts (2)
packages/constants/src/endpoints.ts (1)
  • API_BASE_URL (1-1)
apps/space/core/store/publish/publish.store.ts (1)
  • workspaceSlug (93-95)
apps/api/plane/api/rate_limit.py (1)
apps/api/plane/db/models/api.py (1)
  • APIToken (19-44)
apps/web/core/components/api-token/delete-token-modal.tsx (4)
packages/services/src/developer/workspace-api-token.service.ts (1)
  • WorkspaceAPITokenService (10-73)
apps/space/core/store/publish/publish.store.ts (1)
  • workspaceSlug (93-95)
apps/web/core/constants/fetch-keys.ts (2)
  • WORKSPACE_API_TOKENS_LIST (146-147)
  • API_TOKENS_LIST (145-145)
packages/constants/src/event-tracker/core.ts (2)
  • WORKSPACE_SETTINGS_TRACKER_EVENTS (475-489)
  • PROFILE_SETTINGS_TRACKER_EVENTS (434-448)
apps/api/plane/db/models/user.py (1)
apps/api/plane/utils/exporters/schemas/base.py (1)
  • BooleanField (97-105)
apps/api/plane/app/views/api/workspace.py (4)
apps/api/plane/app/serializers/api.py (2)
  • APITokenSerializer (12-23)
  • APITokenReadSerializer (26-36)
apps/api/plane/utils/permissions/workspace.py (1)
  • WorkSpaceAdminPermission (57-67)
apps/api/plane/app/views/api/base.py (3)
  • post (17-35)
  • get (37-45)
  • delete (47-50)
apps/api/plane/tests/conftest.py (1)
  • api_token (46-53)
apps/api/plane/app/views/api/base.py (3)
apps/api/plane/db/models/api.py (1)
  • APIToken (19-44)
apps/api/plane/app/serializers/api.py (1)
  • APITokenReadSerializer (26-36)
apps/api/plane/app/views/api/workspace.py (1)
  • get (46-54)
apps/api/plane/db/migrations/0113_webhook_version.py (1)
apps/api/plane/db/models/workspace.py (2)
  • get_default_product_tour (115-122)
  • WorkspaceUserProperties (313-355)
apps/web/core/components/api-token/modal/create-token-modal.tsx (4)
packages/services/src/developer/workspace-api-token.service.ts (1)
  • WorkspaceAPITokenService (10-73)
apps/space/core/store/publish/publish.store.ts (1)
  • workspaceSlug (93-95)
apps/web/core/constants/fetch-keys.ts (2)
  • WORKSPACE_API_TOKENS_LIST (146-147)
  • API_TOKENS_LIST (145-145)
packages/constants/src/event-tracker/core.ts (2)
  • WORKSPACE_SETTINGS_TRACKER_EVENTS (475-489)
  • PROFILE_SETTINGS_TRACKER_EVENTS (434-448)
apps/api/plane/app/urls/api.py (1)
apps/api/plane/app/views/api/workspace.py (1)
  • WorkspaceAPITokenEndpoint (18-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build packages
🔇 Additional comments (62)
packages/i18n/src/locales/id/translations.ts (1)

1723-1723: LGTM! Translation correctly reflects workspace-scoped tokens.

The Indonesian translation has been appropriately updated to specify "workspace access token" instead of a generic API token, aligning with the PR's implementation of workspace-scoped API token management.

packages/i18n/src/locales/it/translations.ts (1)

1727-1727: LGTM! Translation accurately reflects workspace-scoped API tokens.

The Italian translation correctly updates the label from a generic "Add API token" to the more specific "Add workspace access token", properly reflecting the workspace-scoped nature of the API tokens feature being implemented in this PR.

packages/i18n/src/locales/ko/translations.ts (1)

1706-1706: LGTM! Translation update aligns with workspace API token feature.

The Korean translation has been appropriately updated from "API 토큰 추가" (Add API token) to "워크스페이스 액세스 토큰 추가" (Add workspace access token), which accurately reflects the workspace-scoped nature of the new token functionality introduced in this PR.

packages/i18n/src/locales/sk/translations.ts (1)

1714-1714: LGTM! Translation aligns with workspace API tokens feature.

The updated Slovak translation correctly reflects the workspace-scoped nature of the API tokens being implemented in this PR. The change from "Pridať API token" (Add API token) to "Pridať token prístupu k pracovnému priestoru" (Add workspace access token) provides better clarity and specificity for users.

packages/i18n/src/locales/pt-BR/translations.ts (1)

1735-1735: LGTM! Translation improvement enhances clarity.

The updated translation from "Adicionar token de API" to "Adicionar token de acesso ao espaço de trabalho" is more specific and accurately reflects that these are workspace-scoped tokens rather than generic API tokens. This aligns well with the PR's objective of implementing workspace API token functionality.

packages/i18n/src/locales/vi-VN/translations.ts (1)

1723-1723: LGTM! Translation improves clarity for workspace-scoped tokens.

The updated Vietnamese translation now specifies "Thêm token truy cập không gian làm việc" (Add workspace access token) instead of the generic "Thêm token API" (Add API token). This change better reflects the workspace-scoped nature of these tokens and aligns with the PR's objective to implement workspace API token management.

The terminology is consistent with other workspace-related translations throughout this file that use "không gian làm việc" for workspace.

packages/i18n/src/locales/ru/translations.ts (1)

1717-1717: LGTM! Translation accurately reflects workspace-scoped API tokens.

The Russian translation has been appropriately updated from "Добавить то��ен" (Add token) to "Добавить токен доступа к рабочему пространству" (Add workspace access token). This change is grammatically correct, natural in Russian, and aligns perfectly with the PR's objective of implementing workspace-scoped API tokens.

packages/i18n/src/locales/tr-TR/translations.ts (1)

1723-1723: LGTM! Translation correctly updated for workspace-scoped tokens.

The Turkish translation accurately reflects the workspace access token terminology introduced in this PR. The grammar and apostrophe usage with "token'ı" follows proper Turkish orthography conventions.

packages/i18n/src/locales/zh-TW/translations.ts (1)

1695-1695: LGTM! Translation update correctly reflects workspace-scoped token terminology.

The updated translation from "新增 API 權杖" to "新增工作區存取權杖" (Add Workspace Access Token) accurately reflects the workspace-scoped nature of the API tokens introduced in this PR. The translation is grammatically correct and consistent with other workspace-related terminology used throughout the file.

packages/i18n/src/locales/zh-CN/translations.ts (1)

1692-1694: Translation correctly implements workspace-scoped API tokens across all locales.

The update from "添加 API 令牌" to "添加工作区访问令牌" appropriately adds workspace context and is consistently applied across all 19+ locale files, ensuring uniform labeling throughout the application.

packages/i18n/src/locales/pl/translations.ts (1)

1715-1715: LGTM! Translation accurately reflects workspace-scoped API tokens.

The updated Polish translation correctly changes from a generic "API token" to "workspace access token," aligning with the PR's workspace-scoped API token implementation. The terminology "obszar roboczy" (workspace) is consistent throughout the file. This change is part of a coordinated translation update across all 18+ language files in the project, confirming the consistency of the effort.

The new translation is notably longer (43 vs 19 characters). Consider verifying that this text displays properly in the UI, especially in buttons or constrained layouts, though the proportional length increase is consistent with the corresponding changes in other languages.

packages/i18n/src/locales/cs/translations.ts (1)

1712-1712: LGTM! Translation updated to reflect workspace-scoped tokens.

The Czech translation has been correctly updated from "Add API token" to "Add workspace access token", aligning with the broader workspace API tokens feature introduced in this PR.

apps/api/plane/app/serializers/api.py (1)

1-6: LGTM! Import organization improved.

The explicit imports for django.utils.timezone and rest_framework.serializers improve code clarity with no functional changes to the serializers.

apps/api/plane/db/models/workspace.py (2)

115-122: LGTM! Product tour defaults correctly configured.

The get_default_product_tour() function appropriately returns False for all tour flags on new records, while the migration (0113_webhook_version.py) sets existing records to True to mark tours as completed for existing users.

Based on learnings, this pattern ensures existing users don't see tours they don't need.


338-338: LGTM! Product tour field addition.

The product_tour JSONField correctly uses the get_default_product_tour function as its default, enabling per-user tracking of product tour completion across different features.

packages/i18n/src/locales/es/translations.ts (1)

1737-1737: LGTM! Spanish translation updated for workspace tokens.

The translation has been correctly updated from "Add API token" to "Add workspace access token", maintaining consistency with the workspace API tokens feature across all supported locales.

apps/api/plane/db/models/api.py (1)

35-35: LGTM! Rate limit field addition.

The allowed_rate_limit field with default "60/min" correctly supports per-token rate limiting for workspace API tokens. The format is valid for Django REST Framework throttling.

Based on learnings, DRF rate limit abbreviations like "min" are valid and equivalent to "minute".

packages/i18n/src/locales/fr/translations.ts (1)

1734-1753: Workspace API token label update looks good

The new wording clearly indicates a workspace-scoped access token and remains consistent with surrounding API token copy.

packages/i18n/src/locales/ja/translations.ts (1)

1711-1731: Japanese workspace token label aligns with new semantics

The updated add_token string correctly clarifies this as a workspace access token while remaining consistent with the surrounding API token copy.

apps/api/plane/app/urls/api.py (1)

2-30: Workspace API token endpoints are wired consistently

The new import and URL patterns cleanly extend the existing token API surface:

  • workspaces/<str:slug>/api-tokens/ and workspaces/<str:slug>/api-tokens/<uuid:pk>/ map to WorkspaceAPITokenEndpoint, matching its (slug, pk?) signature.
  • Naming (workspace-api-tokens, workspace-api-tokens-details) follows the existing api-tokens conventions.

One thing to double‑check outside this file: WorkspaceAPITokenEndpoint currently exposes POST/GET/DELETE only. If you ever need to edit workspace tokens (e.g., label or expiry) similar to user tokens, you’ll also want a PATCH handler and corresponding expectations on the client.

packages/i18n/src/locales/ua/translations.ts (1)

1716-1735: Ukrainian workspace token label matches new concept

The updated add_token text clearly communicates that this is a workspace access token and stays consistent with the rest of the workspace settings section.

apps/api/plane/app/views/__init__.py (1)

164-165: Publicly exporting WorkspaceAPITokenEndpoint is consistent

Re‑exporting WorkspaceAPITokenEndpoint alongside ApiTokenEndpoint and ServiceApiTokenEndpoint keeps the views package’s public surface coherent and simplifies imports for URL configuration.

apps/api/plane/db/models/webhook.py (1)

41-41: LGTM! Version field addition looks good.

The addition of the version field to the Webhook model is straightforward and follows Django model conventions. The default value of "v1" and max_length of 50 are appropriate for version tracking.

packages/services/src/developer/index.ts (1)

3-3: LGTM! Service export follows existing patterns.

The re-export of the workspace API token service is consistent with the existing service exports in this file and appropriately extends the public API surface.

packages/i18n/src/locales/de/translations.ts (1)

1732-1732: LGTM! Translation update aligns with workspace-scoped tokens.

The translation change from "API-Token hinzufügen" to "Workspace-Zugriffstoken hinzufügen" (Add API Token → Add Workspace Access Token) appropriately reflects the workspace-scoped nature of the new token functionality.

apps/api/plane/db/models/user.py (1)

236-237: LGTM! Navigation tour field follows established patterns.

The addition of is_navigation_tour_completed follows the established pattern for product tour fields in the Profile model. The default of False is appropriate for new users, with existing users being handled via migration.

Based on learnings, this aligns with the project's approach to tour/onboarding fields.

apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx (1)

2-2: LGTM! Icon addition is appropriate and consistent.

The addition of the KeyRound icon for API tokens is:

  • Semantically appropriate for representing API tokens/keys
  • Consistent with the existing icon mapping pattern
  • Properly imported from lucide-react

Also applies to: 28-28

apps/web/core/constants/fetch-keys.ts (1)

146-147: LGTM! Fetch key follows established patterns.

The WORKSPACE_API_TOKENS_LIST function follows the same pattern as other workspace-scoped fetch keys in this file, using consistent naming conventions and the toUpperCase() transformation.

apps/api/plane/app/views/api/__init__.py (1)

1-3: LGTM! Clean API surface for token endpoints.

The module consolidates token endpoint exports appropriately, following standard Python package patterns and creating a clean public API surface.

apps/api/plane/app/views/api/base.py (1)

37-45: LGTM! GET methods properly filter workspace tokens.

The addition of workspace_id__isnull=True to both the list and detail GET methods ensures that workspace-scoped tokens are not exposed through the user API token endpoints. This is a critical security enhancement that properly separates user tokens from workspace tokens.

apps/web/core/components/api-token/token-list-item.tsx (2)

25-27: LGTM!

The conditional tracker element selection correctly distinguishes between workspace-scoped and profile-scoped contexts. The ternary expression is clear and the tracker constants are appropriately named.


31-36: LGTM!

The workspaceSlug prop is correctly propagated to DeleteApiTokenModal, enabling workspace-scoped token deletion when applicable.

packages/constants/src/settings.ts (1)

40-40: LGTM!

The api-tokens setting is correctly added to the DEVELOPER category, consistent with the workspace settings structure.

packages/constants/src/workspace.ts (2)

110-116: LGTM!

The new api-tokens workspace setting follows the established pattern with correct access control (admin-only), consistent href structure, and proper highlight function. The i18n label key aligns with the translation structure.


135-135: LGTM!

The api-tokens entry is correctly appended to WORKSPACE_SETTINGS_LINKS, making it available in workspace settings navigation.

apps/web/core/components/ui/loader/settings/api-token.tsx (1)

3-12: LGTM!

Good refactor to accept title as a prop instead of hardcoding the translation. This makes the loader reusable across different contexts (workspace and profile API tokens pages) while delegating translation responsibility to the caller.

apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/api-tokens/page.tsx (4)

26-26: Module-level service instantiation is acceptable here.

The WorkspaceAPITokenService is instantiated at module level. This is a common pattern for stateless services and is fine since the service likely doesn't hold request-specific state. Just ensure the service class is designed to be reused across requests.


41-44: LGTM!

The SWR conditional fetching pattern is correctly implemented—both the key and fetcher are null when the user lacks admin permissions, preventing unauthorized API calls while maintaining the hooks' call order.


50-52: LGTM!

Good guard clause: returns NotAuthorizedView when user info is loaded but lacks admin permissions. The workspaceUserInfo check ensures the permission state is determined before rendering the unauthorized view.


79-86: Consider adding a key prop stability check.

The token list renders correctly with token.id as the key. The implementation is clean.

apps/api/plane/api/middleware/api_authentication.py (1)

48-49: All workspace-scoped API routes consistently use slug as the URL parameter name, making the middleware's assumption correct. No action needed.

Likely an incorrect or invalid review comment.

apps/api/plane/api/views/base.py (1)

63-75: LGTM!

The throttle selection logic is well-structured:

  1. Single database query for the base queryset
  2. In-memory filtering for service and workspace tokens
  3. Clear priority: service tokens → workspace tokens → default API key throttle
  4. Early returns prevent unnecessary checks

Note: While the APIToken model does not enforce mutual exclusivity between is_service=True and workspace_id at the database level, the current logic handles this correctly by prioritizing service tokens over workspace tokens, so any ambiguous token would be treated as a service token as intended.

apps/api/plane/api/rate_limit.py (1)

102-110: Database query on every request may impact performance.

The allow_request method queries the database for the token's allowed_rate_limit on every request. Consider caching the rate limit (e.g., in Django's cache framework with the API key as the cache key) to reduce database load under high traffic.

apps/web/core/components/api-token/modal/create-token-modal.tsx (3)

1-26: LGTM! Imports and service initialization are correct.

The workspace-scoped token support is properly set up with appropriate imports, props type extension, and service instantiation.


54-70: LGTM! API call selection and cache mutation are correctly implemented.

The conditional logic properly selects the appropriate service and mutation key based on whether the token is workspace-scoped or global.


71-95: LGTM! Event tracking properly differentiates workspace vs. profile contexts.

Success and error event tracking correctly uses workspace-specific or profile-specific event names based on the context, ensuring accurate analytics.

packages/services/src/developer/workspace-api-token.service.ts (3)

1-13: LGTM! Class structure and constructor follow established patterns.

The service class correctly extends APIService and follows the same initialization pattern as other service classes in the codebase.


21-42: LGTM! CRUD methods are correctly implemented.

The list and retrieve methods properly construct workspace-scoped endpoints and handle responses and errors consistently.


51-72: LGTM! Create and destroy methods are correctly implemented.

Both methods properly construct workspace-scoped endpoints, handle payloads appropriately, and follow consistent error handling patterns.

apps/web/core/components/api-token/delete-token-modal.tsx (3)

1-26: LGTM! Setup mirrors create-token-modal pattern correctly.

Imports, props extension, and service instantiation follow the same pattern established in the create modal, ensuring consistency.


37-56: LGTM! Deletion logic and cache management are correct.

The conditional service selection and cache mutation properly handle both workspace-scoped and global token deletion.


57-86: LGTM! Event tracking properly differentiates contexts.

Success and error tracking correctly uses workspace-specific or profile-specific events, maintaining consistency with the create modal implementation.

packages/i18n/src/locales/en/translations.ts (2)

1410-1413: LGTM! Translation key renamed for consistency.

The key rename from heading to title in account settings maintains the same display text while improving naming consistency.


1573-1578: LGTM! Workspace token translations properly added.

The new translation keys clearly differentiate workspace tokens from personal tokens with appropriate labels:

  • "Workspace Access Tokens" for heading/title
  • "Add Workspace access token" for the action button
packages/constants/src/event-tracker/core.ts (1)

486-508: LGTM! Workspace-scoped event tracking constants properly added.

The new PAT events and UI element identifiers correctly distinguish workspace-level token tracking from profile-level tracking, with appropriate prefixing to avoid naming collisions.

apps/api/plane/app/views/api/workspace.py (1)

18-21: LGTM! Permission class correctly restricts access.

The WorkSpaceAdminPermission correctly restricts token management to workspace admins and members, which is appropriate for workspace-scoped API tokens.

apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/api-tokens/page.tsx (3)

1-40: LGTM! Component structure and loading state are correct.

The component properly uses FC type, mobx observer, and handles the loading state with appropriate translation keys for account-scoped tokens.


46-58: LGTM! Header with button correctly configured.

The SettingsHeading properly includes an add-token button with correct event tracking for the profile/account context (no workspaceSlug passed to modal).


59-86: LGTM! Token list and empty state are correctly implemented.

The conditional rendering properly shows either the token list or an appropriately configured empty state, with correct event tracking for the account context.

apps/api/plane/db/migrations/0113_webhook_version.py (3)

7-21: LGTM! Product tour default correctly set for existing users.

The migration sets existing records to True (completed) while the model default is False for new records. This is intentional to prevent existing users from seeing tours they don't need.

Based on learnings, this pattern is standard in the Plane codebase.


17-21: LGTM! Data migration efficiently populates product tour.

The bulk update approach is performant and correctly sets the product tour field for all existing workspace user properties records.


30-52: LGTM! All field additions are correctly configured.

The migration adds four fields with appropriate defaults:

  • webhook.version: versioning support for webhooks
  • profile.is_navigation_tour_completed: tracking navigation tour completion
  • workspaceuserproperties.product_tour: feature tour tracking with correct default pattern
  • apitoken.allowed_rate_limit: rate limit configuration (format is valid per DRF standards)

The RunPython operation runs after field additions, ensuring correct execution order.

Based on learnings, the rate limit format '60/min' is valid for DRF throttling.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/api/plane/app/views/api/workspace.py (1)

23-44: Add error handling for workspace lookup.

Line 31 uses Workspace.objects.get(slug=slug) without error handling. If the workspace doesn't exist, this will raise DoesNotExist and return a 500 error instead of a proper 404 response.

🔎 Recommended fix using get_object_or_404
+from django.shortcuts import get_object_or_404
+
 class WorkspaceAPITokenEndpoint(BaseAPIView):
     ...
     def post(self, request: Request, slug: str) -> Response:
         label = request.data.get("label", str(uuid4().hex))
         description = request.data.get("description", "")
         expired_at = request.data.get("expired_at", None)

         # Check the user type
         user_type = 1 if request.user.is_bot else 0

-        workspace = Workspace.objects.get(slug=slug)
+        workspace = get_object_or_404(Workspace, slug=slug)

         api_token = APIToken.objects.create(
             label=label,
             description=description,
             user=request.user,
             user_type=user_type,
             expired_at=expired_at,
             workspace=workspace,
         )

         serializer = APITokenSerializer(api_token)

         return Response(serializer.data, status=status.HTTP_201_CREATED)
🧹 Nitpick comments (1)
apps/api/plane/app/views/api/workspace.py (1)

56-62: Fix variable naming inconsistency.

The variable api_tokens (plural) should be api_token (singular) when retrieving a single object for clarity.

🔎 Proposed refactor
         else:
             try:
-                api_tokens = APIToken.objects.get(workspace__slug=slug, pk=pk, user=request.user)
+                api_token = APIToken.objects.get(workspace__slug=slug, pk=pk, user=request.user)
             except APIToken.DoesNotExist:
                 return Response({"error": "API token does not exist"}, status=status.HTTP_404_NOT_FOUND)

-            serializer = APITokenReadSerializer(api_tokens)
+            serializer = APITokenReadSerializer(api_token)
             return Response(serializer.data, status=status.HTTP_200_OK)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae0550e and 26eba89.

📒 Files selected for processing (1)
  • apps/api/plane/app/views/api/workspace.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-23T18:18:06.875Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

Applied to files:

  • apps/api/plane/app/views/api/workspace.py
📚 Learning: 2025-12-23T14:18:32.899Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/models/api.py:35-35
Timestamp: 2025-12-23T14:18:32.899Z
Learning: Django REST Framework rate limit strings are flexible: only the first character of the time unit matters. Acceptable formats include: "60/s", "60/sec", "60/second" (all equivalent), "60/m", "60/min", "60/minute" (all equivalent), "60/h", "60/hr", "60/hour" (all equivalent), and "60/d", "60/day" (all equivalent). Abbreviations like "min" are valid and do not need to be changed to "minute". Apply this guidance to any Python files in the project that configure DRF throttling rules.

Applied to files:

  • apps/api/plane/app/views/api/workspace.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: check:lint
  • GitHub Check: check:types
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/api/plane/app/views/api/workspace.py (2)

1-21: LGTM!

Imports are well-organized and the permission class appropriately restricts access to workspace administrators.


64-71: LGTM!

The DELETE method correctly implements error handling with try-except and returns appropriate status codes (404 for not found, 204 for successful deletion). The filters properly enforce security by checking workspace, user, and service token status.

@sangeethailango
Copy link
Member Author

sangeethailango commented Dec 30, 2025

#8339 needs to be merged before this, as it contains the allowed_rate_limit field, which is required here.

@vamsikrishnamathala vamsikrishnamathala marked this pull request as draft December 30, 2025 10:59
@vamsikrishnamathala vamsikrishnamathala marked this pull request as ready for review December 30, 2025 11:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/i18n/src/locales/ko/translations.ts (1)

1704-1726: Inconsistent terminology within the API tokens section.

The api_tokens section uses mixed terminology:

  • heading (line 1705) and title (line 1707) use "API 토큰" (API token)
  • add_token (line 1708) uses "액세스 토큰 추가" (Add access token)

For consistency and clarity, consider using the same term throughout this section. If "API 토큰" and "액세스 토큰" refer to the same concept, standardize on one term. If they represent different concepts, the distinction should be documented.

🔎 Suggested fix for consistency

Option 1: Standardize on "API 토큰":

-        add_token: "액세스 토큰 추가",
+        add_token: "API 토큰 추가",

Option 2: Standardize on "액세스 토큰":

-        heading: "API 토큰",
+        heading: "액세스 토큰",
         description: "보안 API 토큰을 생성하여 데이터를 외부 시스템 및 애플리케이션과 통합합니다.",
-        title: "API 토큰",
+        title: "액세스 토큰",
♻️ Duplicate comments (1)
packages/i18n/src/locales/ro/translations.ts (1)

1726-1733: Update the entire api_tokens section to use consistent "workspace access token" terminology.

The Romanian translation has a terminology inconsistency that was previously identified. The section mixes old "cheie secretă API" (API secret key) terminology with the newer "token de acces" (access token) terminology, but neither aligns with the workspace-scoped API token feature introduced in this PR.

Current inconsistencies:

  • heading (line 1726): "Chei secrete API" → should reflect workspace tokens
  • description (line 1727): "chei secrete API sigure" → should reflect workspace tokens
  • add_token (line 1729): "Adaugă token de acces" → should be "token de acces la spațiul de lucru"
  • create_token (line 1731): "Creează cheie secretă" → should reflect workspace token terminology
  • generate_token (line 1733): "Generează cheie secretă" → should reflect workspace token terminology

All other locales (English, Czech, German, French, Spanish, Italian, Portuguese) have already made comprehensive updates to "Workspace Access Tokens" terminology. The Romanian translations should be updated consistently to match this internationalization pattern.

Recommended updates
       api_tokens: {
-        heading: "Chei secrete API",
-        description: "Generează chei secrete API sigure pentru a integra datele tale cu sisteme și aplicații externe.",
+        heading: "Tokenuri de acces la spațiul de lucru",
+        description: "Generează tokenuri de acces sigure pentru a integra datele tale din spațiul de lucru cu sisteme și aplicații externe.",
         title: "Chei secrete API",
-        add_token: "Adaugă token de acces",
-        create_token: "Creează cheie secretă",
+        add_token: "Adaugă token de acces la spațiul de lucru",
+        create_token: "Creează token de acces la spațiul de lucru",
         never_expires: "Nu expiră niciodată",
-        generate_token: "Generează cheie secretă",
+        generate_token: "Generează token de acces la spațiul de lucru",
         generating: "Se generează",

Also update the delete section strings (lines 1735-1737) to use "token de acces la spațiul de lucru" instead of "cheia secretă API".

🧹 Nitpick comments (1)
apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx (1)

41-44: Consider adding error handling for the SWR data fetch.

The current implementation doesn't destructure or handle the error from useSWR. If the API call fails, users will see either a loading state indefinitely or stale data without any error feedback.

🔎 Recommended addition for error handling
-  const { data: tokens } = useSWR(
+  const { data: tokens, error } = useSWR(
     canPerformWorkspaceAdminActions ? WORKSPACE_API_TOKENS_LIST(workspaceSlug) : null,
     canPerformWorkspaceAdminActions ? () => workspaceApiTokenService.list(workspaceSlug) : null
   );

Then add error state handling in the render logic:

{!tokens && !error ? (
  <APITokenSettingsLoader title={t("workspace_settings.settings.api_tokens.title")} />
) : error ? (
  <div className="flex items-center justify-center h-full">
    <EmptyStateCompact
      assetKey="error"
      title={t("common.error.label")}
      description={t("common.error.message")}
    />
  </div>
) : (
  // ... existing token list/empty state
)}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5004073 and a32412e.

📒 Files selected for processing (24)
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • apps/web/app/routes/core.ts
  • packages/constants/src/settings.ts
  • packages/constants/src/workspace.ts
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/de/translations.ts
  • packages/i18n/src/locales/en/translations.ts
  • packages/i18n/src/locales/es/translations.ts
  • packages/i18n/src/locales/fr/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/sk/translations.ts
  • packages/i18n/src/locales/tr-TR/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • packages/i18n/src/locales/tr-TR/translations.ts
  • packages/i18n/src/locales/ja/translations.ts
  • packages/constants/src/settings.ts
  • packages/constants/src/workspace.ts
  • packages/i18n/src/locales/sk/translations.ts
  • packages/i18n/src/locales/pl/translations.ts
  • packages/i18n/src/locales/ua/translations.ts
  • packages/i18n/src/locales/en/translations.ts
  • packages/i18n/src/locales/fr/translations.ts
  • apps/web/app/routes/core.ts
  • packages/i18n/src/locales/it/translations.ts
  • packages/i18n/src/locales/zh-CN/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/sidebar.tsx
  • packages/i18n/src/locales/es/translations.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}

📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{ts,tsx,mts,cts}: Use const type parameters for more precise literal inference in TypeScript 5.0+
Use the satisfies operator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicit is return types in filter/check functions
Use NoInfer<T> utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing in switch(true) blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacy experimentalDecorators
Use using declarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Use with { type: "json" } for import attributes; avoid deprecated assert syntax (TypeScript 5.3/5.8+)
Use import type explicitly when importing types to ensure they are erased during compilation, respecting verbatimModuleSyntax flag
Use .ts, .mts, .cts extensions in import type statements (TypeScript 5.2+)
Use import type { Type } from "mod" with { "resolution-mode": "import" } for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize new Set methods like union, intersection, etc., when available (TypeScript 5.5+)
Use Object.groupBy / Map.groupBy standard methods for grouping instead of external libraries (TypeScript 5.4+)
Use Promise.withResolvers() for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted, toSpliced, with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields via super in classes (TypeScript 5....

Files:

  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/de/translations.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enable TypeScript strict mode and ensure all files are fully typed

Files:

  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/de/translations.ts
**/*.{js,jsx,ts,tsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with Tailwind plugin for code formatting, run pnpm fix:format

Files:

  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/de/translations.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately

Files:

  • packages/i18n/src/locales/pt-BR/translations.ts
  • packages/i18n/src/locales/ko/translations.ts
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
  • packages/i18n/src/locales/cs/translations.ts
  • packages/i18n/src/locales/vi-VN/translations.ts
  • packages/i18n/src/locales/ru/translations.ts
  • packages/i18n/src/locales/zh-TW/translations.ts
  • packages/i18n/src/locales/ro/translations.ts
  • packages/i18n/src/locales/id/translations.ts
  • packages/i18n/src/locales/de/translations.ts
🧠 Learnings (1)
📚 Learning: 2025-10-21T17:22:05.204Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7989
File: apps/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx:45-46
Timestamp: 2025-10-21T17:22:05.204Z
Learning: In the makeplane/plane repository, the refactor from useParams() to params prop is specifically scoped to page.tsx and layout.tsx files in apps/web/app (Next.js App Router pattern). Other components (hooks, regular client components, utilities) should continue using the useParams() hook as that is the correct pattern for non-route components.

Applied to files:

  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
packages/i18n/src/locales/pt-BR/translations.ts (1)

1734-1737: Verify terminology consistency between heading and button label.

The section heading uses "Tokens de API" (API tokens) while the button label uses "token de acesso" (access token). This terminology mismatch could cause user confusion.

  • Heading (line 1734): "Tokens de API"
  • Button (line 1737): "Adicionar token de acesso"

Please confirm whether:

  1. This generic "access token" terminology is intentional to accommodate multiple token types
  2. Other locale files follow the same pattern
  3. The UI implementation consistently uses "access token" terminology

If the generic terminology is intentional, consider updating the heading to match (e.g., "Tokens de acesso") for consistency, or update the button to be more specific (e.g., "Adicionar token de API") to match the heading.

packages/i18n/src/locales/cs/translations.ts (1)

1711-1712: LGTM! New translation keys for API tokens section.

The new heading and description keys appropriately support the workspace API tokens feature introduced in this PR. The structure and placement within workspace_settings.api_tokens are correct.

packages/i18n/src/locales/zh-TW/translations.ts (2)

1694-1695: LGTM! New translation keys added for API tokens UI.

The heading and description additions properly support the workspace API tokens feature. The structure follows existing i18n patterns in this file.


1697-1697: Terminology is consistent across all locales.

The add_token translation to "新增存取權杖" (Add access token) aligns with the English source and is uniformly applied across all 20 locale files. The intentional distinction between the section heading "API 權杖" (API tokens) and the action label "存取權杖" (access token) is maintained consistently across all languages, confirming this is a deliberate product terminology design rather than an inconsistency.

packages/i18n/src/locales/vi-VN/translations.ts (2)

1725-1725: LGTM: Terminology updated to "access token".

The change from "Thêm token API" to "Thêm token truy cập" (Add access token) broadens the terminology and aligns with the UI text changes mentioned in the AI summary across multiple locales.


1722-1724: Both heading and title keys are intentionally present and correctly placed.

The api_tokens section within workspace_settings consistently includes both keys across all locales (confirmed in English: heading: "Access Tokens" and title: "Access Tokens"). They serve different UI purposes and no duplication exists. The structure and translations are correct.

packages/i18n/src/locales/de/translations.ts (1)

1730-1753: Translations look good! The terminology distinction is intentional and consistent.

The German translations are grammatically correct and professionally written. The new heading and description strings provide clear context for the API tokens feature.

The distinction between "API-Tokens" (heading) and "Zugriffstoken" (add_token) is intentional and follows a consistent pattern across all locales. Each locale distinguishes between the feature concept (API tokens as a section header) and the specific user action (adding an access token). This improves user clarity by using more accessible terminology for the button action.

packages/i18n/src/locales/ru/translations.ts (1)

1716-1720: LGTM! Translation keys properly added for workspace API tokens.

The Russian translations correctly add the new heading and description keys and update the add_token label to use "токен доступа" (access token) terminology, aligning with the broader feature changes across locales.

apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/access-tokens/page.tsx (3)

1-26: Clean imports and service instantiation pattern.

The module-level service instantiation is appropriate here since WorkspaceAPITokenService appears to be stateless and only receives workspaceSlug as a method parameter (line 43).


46-52: Proper authorization flow and page title handling.

The permission check correctly waits for workspaceUserInfo to load before showing the unauthorized view, while the SWR conditional fetching prevents data access attempts without permissions. The dynamic page title handles missing workspace data gracefully.


54-115: Well-structured component with proper event tracking and conditional rendering.

The render logic correctly:

  • Shows loading state while data fetches
  • Integrates event tracking for user interactions (header button and empty state CTA)
  • Conditionally renders token list or empty state based on data
  • Properly passes workspaceSlug to child components for workspace-scoped operations
  • Uses appropriate translation keys that align with the i18n updates in this PR

The MobX observer wrapper (line 117) ensures reactive updates when workspace data changes.

description: "Generujte bezpečné API tokeny pro integraci vašich dat s externími systémy a aplikacemi.",
title: "API Tokeny",
add_token: "Přidat API token",
add_token: "Přidat token přístupu",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the structure of the i18n locales directory
git ls-files packages/i18n/src/locales/ | head -20

Repository: makeplane/plane

Length of output: 920


🏁 Script executed:

# Search for all token-related keys and values in the Czech translations
echo "=== Czech translations with 'token' ==="
rg -n "token" packages/i18n/src/locales/cs/translations.ts -i

Repository: makeplane/plane

Length of output: 886


🏁 Script executed:

# Check what other locales use for similar token terminology
echo "=== Checking English locale for token terminology ==="
rg -n "token" packages/i18n/src/locales/en/translations.ts -i -A1

echo ""
echo "=== Checking German locale for token terminology ==="
rg -n "token" packages/i18n/src/locales/de/translations.ts -i -A1

echo ""
echo "=== Checking French locale for token terminology ==="
rg -n "token" packages/i18n/src/locales/fr/translations.ts -i -A1

Repository: makeplane/plane

Length of output: 3417


🏁 Script executed:

# Count occurrences of "API token" vs "token přístupu" and other token variations in Czech
echo "=== Token terminology counts in Czech translations ==="
echo "Occurrences of 'API token':"
rg -c "API token" packages/i18n/src/locales/cs/translations.ts
echo "Occurrences of 'token přístupu':"
rg -c "token přístupu" packages/i18n/src/locales/cs/translations.ts
echo "All lines with 'token' (case-insensitive):"
rg -n "token" packages/i18n/src/locales/cs/translations.ts -i

Repository: makeplane/plane

Length of output: 1009


Update remaining Czech token terminology for consistency with the new "token přístupu" terminology.

The change at line 1714 from "Přidat API token" to "Přidat token přístupu" aligns with English ("Add access token"), German ("Zugriffstoken"), and French ("jeton d'accès") locales. However, the Czech translations still contain inconsistent terminology:

  • Line 1711: heading: "API Tokeny" should be "Tokeny přístupu" or "Přístupové tokeny"
  • Line 1712-1713: References to "API tokeny" should be updated to match
  • Line 1720: title: "Smazat API token" should be "Smazat token přístupu"
  • Line 1735: title: "Žádné API tokeny" should be "Žádné tokeny přístupu"

For reference, English uses consistent "Access Tokens" throughout the section while maintaining "API tokens" only in the description for technical context.

🤖 Prompt for AI Agents
In packages/i18n/src/locales/cs/translations.ts around lines 1711–1735, the
Czech locale uses mixed "API token" wording; update the strings to use the
consistent "token přístupu" terminology: change heading at ~1711 from "API
Tokeny" to "Tokeny přístupu" (or "Přístupové tokeny"), update the following
lines (~1712–1713) to replace any "API tokeny" occurrences with the chosen
"token přístupu" phrase, change the deletion title at ~1720 from "Smazat API
token" to "Smazat token přístupu", and change the empty-state title at ~1735
from "Žádné API tokeny" to "Žádné tokeny přístupu" so all labels match the new
terminology.
Comment on lines +1722 to +1725
heading: "Token API",
description: "Buat token API yang aman untuk mengintegrasikan data Anda dengan sistem dan aplikasi eksternal.",
title: "Token API",
add_token: "Tambah token API",
add_token: "Tambah token akses",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify terminology consistency in Indonesian translations for API tokens

echo "=== Checking 'Token API' occurrences in Indonesian translations ==="
rg -n "Token API" packages/i18n/src/locales/id/translations.ts

echo -e "\n=== Checking 'token akses' occurrences in Indonesian translations ==="
rg -n "token akses" packages/i18n/src/locales/id/translations.ts

echo -e "\n=== Checking full api_tokens section in Indonesian translations ==="
rg -nA15 "api_tokens:" packages/i18n/src/locales/id/translations.ts | head -30

echo -e "\n=== Checking English translation for comparison ==="
rg -nA15 "api_tokens:" packages/i18n/src/locales/en/translations.ts | head -30

Repository: makeplane/plane

Length of output: 3447


Ensure consistent terminology in Indonesian API tokens translation.

The translation mixes "Token API" and "token akses" within the same feature section:

  • heading (line 1722): "Token API"
  • title (line 1724): "Token API"
  • add_token (line 1725): "Tambah token akses"
  • delete.title (line 1731): "Hapus token API"

The English version uses "Access Tokens" consistently throughout. Either standardize the Indonesian on "Token API" or use "token akses" consistently to match the English terminology and improve UX clarity.

🤖 Prompt for AI Agents
packages/i18n/src/locales/id/translations.ts lines 1722-1725 (and related keys
around 1731): the Indonesian copy mixes "Token API" and "token akses" for the
same feature; pick one term and make all keys in this feature consistent (e.g.,
change add_token to "Tambah Token API" and change delete.title to "Hapus Token
API", or alternatively convert heading/title to use "token akses" if you prefer
that term), then update all occurrences in this section so the same phrase is
used everywhere and run a quick grep to ensure no mixed usages remain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment