Skip to content

Fix workspace slug normalization for accented names#9162

Open
naderelkhouri wants to merge 1 commit into
makeplane:previewfrom
naderelkhouri:fix/workspace-slug-normalization
Open

Fix workspace slug normalization for accented names#9162
naderelkhouri wants to merge 1 commit into
makeplane:previewfrom
naderelkhouri:fix/workspace-slug-normalization

Conversation

@naderelkhouri
Copy link
Copy Markdown

@naderelkhouri naderelkhouri commented May 28, 2026

What\n- Normalize workspace slug input before submission so names with accents/diacritics (e.g. "çã") become ASCII-safe slugs (e.g. "ca")\n- Normalize slug availability checks in the backend\n- Add serializer coverage for slug normalization\n\n## Why\nThe workspace creation flow could send non-ASCII slugs to the API, which resulted in 400 responses even though the workspace name itself was valid.\n\n## Verification\n- python3 -m py_compile on the touched Python files\n- git diff --check

Summary by CodeRabbit

  • Bug Fixes
    • Workspace URLs now consistently normalize special characters and unicode characters (including accented letters) across all workspace creation and management workflows
    • Enhanced workspace URL slug validation with improved consistency and more robust edge-case handling throughout the platform

Review Change Stack

Normalize workspace slug input before validation and submission so accented names like çã are converted to ASCII-safe slugs (e.g. ca). Also normalize slug availability checks and add serializer coverage for the normalization path.
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

This PR standardizes workspace slug handling across the application by introducing a shared normalizeSlug utility and applying it consistently across frontend components, backend validation, and API integration. The change replaces scattered inline normalization logic with a unified, Unicode-aware slug normalization process.

Changes

Unified Workspace Slug Normalization

Layer / File(s) Summary
Slug normalization utility function
packages/utils/src/validation.ts
Introduces normalizeSlug(slug: string) that removes Unicode diacritics, lowercases, converts whitespace to hyphens, filters disallowed characters, and cleans up repeated/leading/trailing hyphens.
Backend validation and endpoint integration
apps/api/plane/license/api/serializers/workspace.py, apps/api/plane/license/api/views/workspace.py, apps/api/plane/tests/unit/serializers/test_workspace.py
WorkspaceSerializer normalizes slug input before validating uniqueness and restricted values; the workspace slug-check endpoint normalizes the query parameter and returns {"status": False} if normalization yields empty. New test verifies Unicode-to-ASCII normalization.
Frontend workspace creation components
apps/admin/app/(all)/(dashboard)/workspace/create/form.tsx, apps/web/core/components/onboarding/create-workspace.tsx, apps/web/core/components/onboarding/steps/workspace/create.tsx, apps/web/core/components/workspace/create-workspace-form.tsx
Four components import and apply normalizeSlug when deriving slug from name input and when normalizing direct slug edits, replacing inline regex/lowercasing logic. Slug input displays and validates normalized values immediately.
Service layer URL encoding
apps/web/core/services/workspace.service.ts
workspaceSlugCheck method now URL-encodes the slug parameter via encodeURIComponent before making the API request.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A slug takes shape with diacritics shed,
From café to cafe, the normalizer said.
Frontend and backend now speak as one,
Unicode chaos beautifully undone! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers the what, why, and verification steps but lacks the standard template structure with Type of Change, Screenshots, and Test Scenarios sections. Use the repository's standard PR template with sections for Type of Change, Screenshots/Media, and Test Scenarios for consistency and clarity.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: normalizing workspace slugs to handle accented characters, which directly addresses the core issue in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82712457c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.replace(/\s+/g, "-")
.replace(/[^a-z0-9_-]/g, "")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve typed hyphen separators in slug inputs

Because the updated workspace URL fields call normalizeSlug on every onChange, this trailing-hyphen strip makes manual slugs with hyphen separators effectively untypeable: after a user types acme-, the stored value immediately becomes acme, so the next character produces acmeteam instead of acme-team. This affects the create-workspace slug inputs that were changed to store normalizeSlug(e.target.value); consider only trimming edge hyphens on submit/blur or using a less destructive live normalizer.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
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: 0

🧹 Nitpick comments (1)
apps/web/core/services/workspace.service.ts (1)

200-206: 💤 Low value

Consider using params object for consistency.

While the encodeURIComponent approach is correct, other methods in this file use the params object for query parameters (e.g., searchWorkspace at line 216, searchEntity at line 331). Using params would be more consistent and eliminates the need for manual encoding:

♻️ Optional refactor for consistency
 async workspaceSlugCheck(slug: string): Promise<any> {
-  return this.get(`/api/workspace-slug-check/?slug=${encodeURIComponent(slug)}`)
+  return this.get(`/api/workspace-slug-check/`, {
+    params: { slug },
+  })
     .then((response) => response?.data)
     .catch((error) => {
       throw error?.response?.data;
     });
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/core/services/workspace.service.ts` around lines 200 - 206, The
workspaceSlugCheck function currently builds a manual query string with
encodeURIComponent; change it to pass the slug via a params object to this.get
for consistency with searchWorkspace/searchEntity and to avoid manual encoding:
update workspaceSlugCheck (the async workspaceSlugCheck(slug: string):
Promise<any>) to call this.get('/api/workspace-slug-check/', { params: { slug }
}) and preserve the existing .then(response => response?.data).catch(error => {
throw error?.response?.data; }) behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/web/core/services/workspace.service.ts`:
- Around line 200-206: The workspaceSlugCheck function currently builds a manual
query string with encodeURIComponent; change it to pass the slug via a params
object to this.get for consistency with searchWorkspace/searchEntity and to
avoid manual encoding: update workspaceSlugCheck (the async
workspaceSlugCheck(slug: string): Promise<any>) to call
this.get('/api/workspace-slug-check/', { params: { slug } }) and preserve the
existing .then(response => response?.data).catch(error => { throw
error?.response?.data; }) behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f8c1170-089b-4cbc-854f-6d5af2e89a8d

📥 Commits

Reviewing files that changed from the base of the PR and between 248f5d6 and 8271245.

📒 Files selected for processing (9)
  • apps/admin/app/(all)/(dashboard)/workspace/create/form.tsx
  • apps/api/plane/license/api/serializers/workspace.py
  • apps/api/plane/license/api/views/workspace.py
  • apps/api/plane/tests/unit/serializers/test_workspace.py
  • apps/web/core/components/onboarding/create-workspace.tsx
  • apps/web/core/components/onboarding/steps/workspace/create.tsx
  • apps/web/core/components/workspace/create-workspace-form.tsx
  • apps/web/core/services/workspace.service.ts
  • packages/utils/src/validation.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants