diff --git a/admin/core/components/workspace/list-item.tsx b/admin/core/components/workspace/list-item.tsx index 9289140f7dc..691e9dbb6cc 100644 --- a/admin/core/components/workspace/list-item.tsx +++ b/admin/core/components/workspace/list-item.tsx @@ -22,7 +22,7 @@ export const WorkspaceListItem = observer(({ workspaceId }: TWorkspaceListItemPr return ( diff --git a/admin/core/services/workspace.service.ts b/admin/core/services/workspace.service.ts index 1de24fd9b00..81ba36a6f76 100644 --- a/admin/core/services/workspace.service.ts +++ b/admin/core/services/workspace.service.ts @@ -30,7 +30,8 @@ export class WorkspaceService extends APIService { * @returns Promise */ async workspaceSlugCheck(slug: string): Promise { - return this.get(`/api/instances/workspace-slug-check/?slug=${slug}`) + const params = new URLSearchParams({ slug }); + return this.get(`/api/instances/workspace-slug-check/?${params.toString()}`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/admin/core/store/workspace.store.ts b/admin/core/store/workspace.store.ts index dafe96760b4..f892e14f0ca 100644 --- a/admin/core/store/workspace.store.ts +++ b/admin/core/store/workspace.store.ts @@ -14,7 +14,7 @@ export interface IWorkspaceStore { // computed workspaceIds: string[]; // helper actions - hydrate: (data: any) => void; + hydrate: (data: Record) => void; getWorkspaceById: (workspaceId: string) => IWorkspace | undefined; // fetch actions fetchWorkspaces: () => Promise; @@ -59,9 +59,9 @@ export class WorkspaceStore implements IWorkspaceStore { // helper actions /** * @description Hydrates the workspaces - * @param data - any + * @param data - Record */ - hydrate = (data: any) => { + hydrate = (data: Record) => { if (data) this.workspaces = data; }; diff --git a/apiserver/plane/license/api/serializers/workspace.py b/apiserver/plane/license/api/serializers/workspace.py index 1d3bfa8905b..75dd938e45d 100644 --- a/apiserver/plane/license/api/serializers/workspace.py +++ b/apiserver/plane/license/api/serializers/workspace.py @@ -18,6 +18,9 @@ def validate_slug(self, value): # Check if the slug is restricted if value in RESTRICTED_WORKSPACE_SLUGS: raise serializers.ValidationError("Slug is not valid") + # Check uniqueness case-insensitively + if Workspace.objects.filter(slug__iexact=value).exists(): + raise serializers.ValidationError("Slug is already in use") return value class Meta: diff --git a/apiserver/plane/license/api/views/workspace.py b/apiserver/plane/license/api/views/workspace.py index af9e8773ad3..14118d85bc8 100644 --- a/apiserver/plane/license/api/views/workspace.py +++ b/apiserver/plane/license/api/views/workspace.py @@ -25,7 +25,7 @@ def get(self, request): ) workspace = ( - Workspace.objects.filter(slug=slug).exists() + Workspace.objects.filter(slug__iexact=slug).exists() or slug in RESTRICTED_WORKSPACE_SLUGS ) return Response({"status": not workspace}, status=status.HTTP_200_OK) diff --git a/packages/ui/src/icons/workspace-icon.tsx b/packages/ui/src/icons/workspace-icon.tsx index 07872b264ca..e15d33f30b4 100644 --- a/packages/ui/src/icons/workspace-icon.tsx +++ b/packages/ui/src/icons/workspace-icon.tsx @@ -3,7 +3,14 @@ import * as React from "react"; import { ISvgIcons } from "./type"; export const WorkspaceIcon: React.FC = ({ className }) => ( - +