Skip to content

Comments

feat: workspace management from admin app#6093

Merged
theparthacus merged 3 commits intopreviewfrom
chore-workspace-management
Nov 26, 2024
Merged

feat: workspace management from admin app#6093
theparthacus merged 3 commits intopreviewfrom
chore-workspace-management

Conversation

@prateekshourya29
Copy link
Member

@prateekshourya29 prateekshourya29 commented Nov 26, 2024

This PR introduces a Workspace Management page in admin mode, allowing instance admins to view and create workspaces. It also includes an option to disable workspace creation by the users.

Media

image image

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced workspace creation functionality, including a new form and management page.
    • Added conditional rendering to inform users when workspace creation is disabled.
  • Improvements

    • Enhanced clarity and consistency of UI text across various components.
    • Updated error handling and validation messages for better user guidance during workspace creation.
  • Bug Fixes

    • Corrected text and links for improved navigation and user interaction.
  • Chores

    • Refactored code for better readability and maintainability, including updates to imports and component structures.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2024

Walkthrough

This pull request introduces several modifications across various components in the admin interface, primarily focusing on improving text clarity, updating class names for styling consistency, and adding new features related to workspace management. Key changes include hyperlink enhancements for user interaction, adjustments to button styles, and the introduction of new components and services for workspace creation and management. The updates also include conditional rendering based on workspace creation permissions, ensuring a cohesive user experience.

Changes

File Path Change Summary
admin/app/ai/form.tsx Updated message to include a hyperlink for contacting the AI models vendor.
admin/app/authentication/github/form.tsx Changed class name for the navigation link from link-neutral to neutral-primary.
admin/app/authentication/gitlab/form.tsx Changed class name for the "Go back" link from link-neutral to neutral-primary.
admin/app/authentication/google/form.tsx Changed class name for the "Go back" link from link-neutral to neutral-primary.
admin/app/authentication/page.tsx Updated text for clarity; refactored toggle switch logic for enabling sign-ups.
admin/app/email/email-config-form.tsx Changed label for "Sender email address" and updated text in the authentication section for clarity.
admin/app/general/form.tsx Updated telemetry-related text for clarity; no functional changes.
admin/app/general/intercom.tsx Updated text labels for clarity; no functional changes.
admin/app/workspace/create/form.tsx Introduced WorkspaceCreateForm component for workspace creation with validation and state management.
admin/app/workspace/create/page.tsx Introduced WorkspaceCreatePage component for structured workspace creation layout.
admin/app/workspace/layout.tsx Defined WorkspaceManagementLayout for workspace management layout.
admin/app/workspace/page.tsx Introduced WorkspaceManagementPage for managing workspaces with pagination and loading states.
admin/ce/components/common/upgrade-button.tsx Updated hyperlink destination and displayed text for the upgrade button.
admin/core/components/admin-sidebar/help-section.tsx Minor tooltip text updates; no functional changes.
admin/core/components/admin-sidebar/sidebar-menu.tsx Added new workspace link with an icon; updated descriptions for existing links.
admin/core/components/auth-header.tsx Enhanced header title generation for new workspace paths.
admin/core/components/new-user-popup.tsx Updated imports and simplified redirection logic for the new user popup.
admin/core/components/workspace/index.ts Added export statement for re-exporting from ./list-item.
admin/core/components/workspace/list-item.tsx Introduced WorkspaceListItem component for displaying workspace details.
admin/core/hooks/store/index.ts Added export for use-workspace functionality.
admin/core/hooks/store/use-workspace.tsx Introduced useWorkspace custom hook for accessing workspace context.
admin/core/services/workspace.service.ts Introduced WorkspaceService class for API interactions related to workspaces.
admin/core/store/root.store.ts Integrated WorkspaceStore into CoreRootStore for workspace management.
admin/core/store/workspace.store.ts Introduced WorkspaceStore for MobX-based state management of workspaces.
apiserver/plane/app/views/workspace/base.py Added check for DISABLE_WORKSPACE_CREATION in workspace creation logic.
apiserver/plane/license/api/serializers/__init__.py Added import for WorkspaceSerializer.
apiserver/plane/license/api/serializers/user.py Introduced UserLiteSerializer for user data serialization.
apiserver/plane/license/api/serializers/workspace.py Introduced WorkspaceSerializer for workspace serialization with validation.
apiserver/plane/license/api/views/__init__.py Added new workspace-related endpoints.
apiserver/plane/license/api/views/instance.py Updated instance endpoint to include workspace creation status in response.
apiserver/plane/license/api/views/workspace.py Introduced endpoints for workspace availability check and management.
apiserver/plane/license/management/commands/configure_instance.py Added configuration key for DISABLE_WORKSPACE_CREATION.
apiserver/plane/license/urls.py Added new URL patterns for workspace management endpoints.
packages/constants/index.ts Updated exports to include workspace module.
packages/constants/workspace.ts Introduced ORGANIZATION_SIZE and RESTRICTED_URLS constants.
packages/types/src/instance/base.d.ts Updated types to include workspace creation configuration keys.
packages/types/src/instance/index.d.ts Added export for workspace module.
packages/types/src/instance/workspace.d.ts Introduced TInstanceWorkspaceConfigurationKeys type alias.
packages/types/src/workspace.d.ts Added total_projects property to IWorkspace interface and defined TWorkspacePaginationInfo type.
packages/ui/src/icons/index.ts Added export for workspace-icon module.
packages/ui/src/icons/workspace-icon.tsx Introduced WorkspaceIcon component for workspace representation.
web/app/create-workspace/page.tsx Implemented conditional rendering based on workspace creation permissions.
web/ce/helpers/instance.helper.ts Introduced getIsWorkspaceCreationDisabled function for checking workspace creation permissions.
web/core/components/account/auth-forms/auth-header.tsx Updated text content for authentication steps for clarity.
web/core/components/account/auth-forms/email.tsx Modified email input placeholder text.
web/core/components/onboarding/create-or-join-workspaces.tsx Updated rendering logic to include workspace creation permissions check.
web/core/components/onboarding/create-workspace.tsx Enhanced labels and validation messages for workspace creation form.
web/core/components/workspace/create-workspace-form.tsx Updated labels and error messages for clarity in workspace creation form.
web/core/components/workspace/settings/workspace-details.tsx Updated organization size handling to use new import.
web/core/components/workspace/sidebar/dropdown.tsx Added conditional rendering for workspace creation link based on permissions.
web/core/constants/workspace.ts Removed ORGANIZATION_SIZE and RESTRICTED_URLS constants.
web/ee/helpers/instance.helper.ts Re-exported all entities from ce/helpers/instance.helper.

Possibly related PRs

Suggested labels

🧹chore, 🐛bug

Suggested reviewers

  • SatishGandham
  • anmolsinghbhatia
  • rahulramesha

🐰 In the meadow, changes abound,
New workspaces are here, joyfully found!
With links that connect and forms that delight,
Creating and managing feels just right!
So hop along, let’s celebrate this cheer,
For a world of workspaces is finally here!
🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@prateekshourya29 prateekshourya29 marked this pull request as ready for review November 26, 2024 18:23
@theparthacus theparthacus merged commit 05d3e3a into preview Nov 26, 2024
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: 19

🧹 Outside diff range and nitpick comments (65)
packages/types/src/instance/workspace.d.ts (1)

1-1: Add JSDoc documentation for better maintainability.

The type declaration is well-designed and serves its purpose for workspace configuration. However, adding documentation would improve maintainability.

Consider adding JSDoc comments to document the purpose and usage:

+/**
+ * Configuration keys specific to workspace management in an instance.
+ * Used to control workspace-related features and permissions.
+ */
export type TInstanceWorkspaceConfigurationKeys = "DISABLE_WORKSPACE_CREATION";
apiserver/plane/license/api/serializers/user.py (1)

3-6: Consider adding admin-relevant fields.

The serializer implementation is clean and secure. However, since this is being used in an admin context for workspace management, consider adding fields that would be helpful for administrators:

  • created_at: To know when the user was created
  • last_active_at: To track user activity
  • is_active: To know if the user account is active
 class UserLiteSerializer(BaseSerializer):
     class Meta:
         model = User
-        fields = ["id", "email", "first_name", "last_name",]
+        fields = [
+            "id", "email", "first_name", "last_name",
+            "created_at", "last_active_at", "is_active",
+        ]
web/ce/helpers/instance.helper.ts (1)

3-7: Consider adding TypeScript types and documentation.

The function would benefit from explicit type safety and documentation.

Here's a suggested improvement:

+ /**
+  * Checks if workspace creation is disabled for the current instance
+  * @returns {boolean} true if workspace creation is disabled, false otherwise
+  */
- export const getIsWorkspaceCreationDisabled = () => {
+ export const getIsWorkspaceCreationDisabled = (): boolean => {
  const instanceConfig = store.instance.config;

-  return instanceConfig?.is_workspace_creation_disabled;
+  return instanceConfig?.is_workspace_creation_disabled ?? false;
};
admin/app/workspace/layout.tsx (2)

1-4: Consider grouping imports by external and internal dependencies.

While the imports are clean, consider organizing them into groups for better readability:

+// external imports
 import { ReactNode } from "react";
 import { Metadata } from "next";
 
+// internal imports
 // layouts
 import { AdminLayout } from "@/layouts/admin-layout";

6-8: Consider a more platform-agnostic page title.

The current title includes "Web" which might not be necessary since this is an admin interface that could potentially be accessed from different platforms.

 export const metadata: Metadata = {
-  title: "Workspace Management - Plane Web",
+  title: "Workspace Management - Plane",
 };
admin/core/hooks/store/use-workspace.tsx (2)

6-10: LGTM! Consider adding JSDoc documentation.

The hook implementation is solid with proper typing and error handling. Consider adding JSDoc documentation to improve IDE support and usage guidance.

Add documentation like this:

+/**
+ * Hook to access workspace store functionality.
+ * @returns {IWorkspaceStore} The workspace store instance
+ * @throws {Error} When used outside of StoreProvider
+ * @example
+ * const workspaceStore = useWorkspace();
+ * await workspaceStore.createWorkspace(data);
+ */
export const useWorkspace = (): IWorkspaceStore => {

8-9: Consider enhancing runtime type safety.

While TypeScript provides compile-time type safety, adding runtime type checking for the workspace property could prevent potential runtime issues.

Consider this enhancement:

-  if (context === undefined) throw new Error("useWorkspace must be used within StoreProvider");
-  return context.workspace;
+  if (context === undefined || !context.workspace) {
+    throw new Error(
+      "useWorkspace must be used within StoreProvider and workspace store must be initialized"
+    );
+  }
+  return context.workspace;
admin/ce/components/common/upgrade-button.tsx (2)

12-13: Consider making the upgrade URL configurable via environment

The upgrade button implementation looks good, but consider making the URL configurable through environment variables to support different deployment scenarios (staging, production, etc.).

Consider this approach:

+// constants
+const UPGRADE_URL = process.env.NEXT_PUBLIC_UPGRADE_URL || "https://plane.so/pricing?mode=self-hosted";

export const UpgradeButton: React.FC = () => (
-  <a href="https://plane.so/pricing?mode=self-hosted" target="_blank" className={cn(getButtonStyling("primary", "sm"))}>
+  <a href={UPGRADE_URL} target="_blank" className={cn(getButtonStyling("primary", "sm"))}>

12-13: Consider adding click tracking for analytics

To better understand upgrade button engagement, consider adding analytics tracking to the click event.

Example implementation:

+// utils
+import { trackEvent } from "@/utils/analytics";

export const UpgradeButton: React.FC = () => (
   <a 
     href="https://plane.so/pricing?mode=self-hosted" 
     target="_blank" 
+    onClick={() => trackEvent("upgrade_button_clicked", { source: "admin_app" })}
     className={cn(getButtonStyling("primary", "sm"))}
   >
apiserver/plane/license/api/views/__init__.py (1)

17-18: LGTM with a minor formatting suggestion

The new imports align well with the workspace management feature. Consider breaking the import into multiple lines to address the line length warning:

-from .workspace import InstanceWorkSpaceAvailabilityCheckEndpoint, InstanceWorkSpaceEndpoint
+from .workspace import (
+    InstanceWorkSpaceAvailabilityCheckEndpoint,
+    InstanceWorkSpaceEndpoint,
+)
🧰 Tools
🪛 Ruff (0.8.0)

18-18: Line too long (92 > 88)

(E501)

🪛 GitHub Check: Codacy Static Code Analysis

[notice] 18-18: apiserver/plane/license/api/views/init.py#L18
'.workspace.InstanceWorkSpaceAvailabilityCheckEndpoint' imported but unused (F401)

admin/app/workspace/create/page.tsx (2)

7-19: Add accessibility attributes to improve user experience

The layout structure is well-organized, but could benefit from improved accessibility.

Consider applying these improvements:

-<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
+<main role="main" className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
-  <div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
+  <header className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
-    <div className="text-xl font-medium text-custom-text-100">
+    <h1 className="text-xl font-medium text-custom-text-100">
       Create a new workspace on this instance.
-    </div>
+    </h1>
     <div className="text-sm font-normal text-custom-text-300" 
+        aria-label="Additional information">
       You will need to invite users from Workspace Settings after you create this workspace.
     </div>
-  </div>
+  </header>
   <div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4"
+      role="region" aria-label="Workspace creation form">
     <WorkspaceCreateForm />
   </div>
-</div>
+</main>

1-21: Consider implementing error boundaries and loading states

As this is a critical admin functionality for workspace management, consider these architectural improvements:

  1. Wrap the component with an error boundary to gracefully handle runtime errors
  2. Add loading states during workspace creation
  3. Implement proper success/error notifications

Would you like me to provide example implementations for these improvements?

apiserver/plane/license/api/serializers/workspace.py (1)

23-34: Consider explicitly listing allowed fields instead of using "all".

Using fields = "__all__" might accidentally expose sensitive fields added to the model in the future. Consider explicitly listing the fields that should be exposed through the API.

     class Meta:
         model = Workspace
-        fields = "__all__"
+        fields = [
+            "id",
+            "name",
+            "slug",
+            "owner",
+            "logo_url",
+            "total_projects",
+            "total_members",
+            "created_by",
+            "updated_by",
+            "created_at",
+            "updated_at",
+        ]
         read_only_fields = [
             "id",
             "created_by",
             "updated_by",
             "created_at",
             "updated_at",
             "owner",
             "logo_url",
         ]
admin/core/store/root.store.ts (1)

31-35: Consider maintaining consistent store initialization order

The order of store resets in resetOnSignOut differs from the initialization order in the constructor. To prevent potential issues with store dependencies, consider maintaining the same order:

  resetOnSignOut() {
    localStorage.setItem("theme", "system");
+   this.theme = new ThemeStore(this);
    this.instance = new InstanceStore(this);
    this.user = new UserStore(this);
-   this.theme = new ThemeStore(this);
    this.workspace = new WorkspaceStore(this);
  }
packages/ui/src/icons/index.ts (1)

36-36: Consider maintaining alphabetical order of exports

While the export addition is correct and aligns with the workspace management feature, consider moving it up to maintain the alphabetical ordering pattern of the file.

 export * from "./user-activity-icon";
+export * from "./workspace-icon";
 export * from "./favorite-folder-icon";
 export * from "./planned-icon";
 export * from "./in-progress-icon";
 export * from "./done-icon";
 export * from "./pending-icon";
 export * from "./pi-chat";
-export * from "./workspace-icon";
admin/core/services/workspace.service.ts (1)

17-25: Enhance error handling and type safety.

Consider the following improvements:

  1. Add proper error typing and handling
  2. Type the cursor parameter
  3. Consider moving the API endpoint to a constants file
-  async getWorkspaces(nextPageCursor?: string): Promise<TWorkspacePaginationInfo> {
-    return this.get<TWorkspacePaginationInfo>("/api/instances/workspaces/", {
+  private readonly ENDPOINTS = {
+    WORKSPACES: "/api/instances/workspaces/",
+  } as const;
+
+  type WorkspaceError = {
+    error: string;
+    message: string;
+  };
+
+  async getWorkspaces(
+    nextPageCursor?: string | null
+  ): Promise<TWorkspacePaginationInfo> {
+    return this.get<TWorkspacePaginationInfo>(this.ENDPOINTS.WORKSPACES, {
       cursor: nextPageCursor,
     })
       .then((response) => response.data)
-      .catch((error) => {
-        throw error?.response?.data;
+      .catch((error: unknown) => {
+        const errorResponse = error?.response?.data as WorkspaceError;
+        throw errorResponse ?? new Error('Failed to fetch workspaces');
       });
admin/core/components/new-user-popup.tsx (1)

34-36: Consider adding aria-label for better accessibility

The navigation implementation using Next.js Link is good, but could benefit from additional accessibility attributes.

Consider adding an aria-label to provide more context:

-<Link href="/workspace/create" className={getButtonStyling("primary", "sm")}>
+<Link 
+  href="/workspace/create" 
+  className={getButtonStyling("primary", "sm")}
+  aria-label="Create new workspace"
+>
apiserver/plane/license/urls.py (1)

60-69: Consider documenting the architectural decision.

The placement of workspace management endpoints within the license module suggests these are instance-wide administrative features. Consider documenting this architectural decision to clarify:

  1. Why these endpoints belong in the license module
  2. How they relate to other workspace management features
  3. The separation of concerns between instance-level and regular workspace management
packages/ui/src/icons/workspace-icon.tsx (1)

7-12: Add documentation for the SVG path.

The SVG path is quite complex and could benefit from documentation explaining the visual structure it creates.

Add a comment above the path element explaining that it represents a building/office structure with windows and doors, which helps other developers understand the icon's visual representation:

   <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
+    {/* Building/office structure with windows and entrance */}
     <path
       fillRule="evenodd"
       clipRule="evenodd"
packages/types/src/instance/base.d.ts (1)

40-40: Consider adding JSDoc documentation for the new configuration flag.

The is_workspace_creation_disabled property is clear but would benefit from documentation explaining its purpose and impact.

+  /** Flag to control whether workspace creation is disabled for regular users. When true, only admins can create workspaces. */
   is_workspace_creation_disabled: boolean;
admin/core/components/auth-header.tsx (2)

36-39: Consider making the route handling more specific

While the added cases support the new workspace management functionality, there are a few concerns:

  1. The "create" case is very generic and might conflict with other create routes in the future. Consider making it more specific, like "workspace-create".
  2. The current implementation might not handle nested workspace routes optimally.

Consider this more robust approach:

      case "workspace":
        return "Workspace";
-     case "create":
-       return "Create";
+     case "workspace-create":
+       return "Create Workspace";
      default:
-       return pathName.toUpperCase();
+       // Handle nested workspace routes
+       if (pathName.startsWith('workspace-')) {
+         return pathName.split('-')
+           .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+           .join(' ');
+       }
+       return pathName.toUpperCase();

Line range hint 47-58: Enhance breadcrumb generation for workspace routes

The current breadcrumb generation might benefit from workspace-specific handling to ensure consistent navigation hierarchy.

Consider these improvements:

// Add type safety for known routes
type AdminRoute = "general" | "workspace" | "workspace-create" | /* other routes */;

const generateBreadcrumbItems = (pathname: string) => {
  const pathSegments = pathname.split("/").slice(1);
  pathSegments.pop();

  let currentUrl = "";
  return pathSegments.map((segment) => {
    currentUrl += "/" + segment;
    
    // Special handling for workspace routes
    if (segment.startsWith('workspace')) {
      const workspaceContext = {
        title: getHeaderTitle(segment),
        href: currentUrl,
        // Add any workspace-specific metadata needed for rendering
        isWorkspaceRoute: true
      };
      return workspaceContext;
    }

    return {
      title: getHeaderTitle(segment),
      href: currentUrl
    };
  });
};
web/core/components/account/auth-forms/auth-header.tsx (1)

24-24: Fix inconsistent capitalization in header text

The header text shows inconsistent capitalization:

  • Line 24, 28: "Log in or sign up"
  • Line 32: "Log in or Sign up"

This should be consistent across all steps.

-      header: "Log in or Sign up",
+      header: "Log in or sign up",

Also applies to: 28-29, 32-33

admin/core/components/workspace/list-item.tsx (1)

1-13: Consider improving imports organization and type documentation

  • Consider moving the ExternalLink import to the UI imports section since it's a UI component
  • Add JSDoc documentation for the TWorkspaceListItemProps type to describe its purpose and usage
 import { observer } from "mobx-react";
 import Link from "next/link";
-import { ExternalLink } from "lucide-react";
 // helpers
 import { Tooltip } from "@plane/ui";
+import { ExternalLink } from "lucide-react";
 import { WEB_BASE_URL } from "@/helpers/common.helper";
 import { getFileURL } from "@/helpers/file.helper";
 // hooks
 import { useWorkspace } from "@/hooks/store";

+/**
+ * Props for the WorkspaceListItem component
+ * @property {string} workspaceId - Unique identifier of the workspace to display
+ */
 type TWorkspaceListItemProps = {
   workspaceId: string;
 };
admin/app/ai/form.tsx (1)

124-129: Add accessibility attributes to the contact link

While the link implementation is good, let's enhance it with proper accessibility attributes to match other external links in the file.

Apply this diff to improve accessibility and maintain consistency with other external links in the component:

-            <a className="underline font-medium" href="https://plane.so/contact">
+            <a
+              href="https://plane.so/contact"
+              target="_blank"
+              className="text-custom-primary-100 hover:underline font-medium"
+              rel="noreferrer"
+            >

This change:

  • Adds target="_blank" for external link behavior
  • Adds rel="noreferrer" for security
  • Updates styling to match other external links in the form
admin/app/authentication/page.tsx (1)

83-87: Optimize the toggle logic for better performance and readability.

While the if-else structure is more readable than a ternary operator, the Boolean(parseInt()) conversion is unnecessary overhead.

Consider simplifying the logic:

-                        if (Boolean(parseInt(enableSignUpConfig)) === true) {
-                          updateConfig("ENABLE_SIGNUP", "0");
-                        } else {
-                          updateConfig("ENABLE_SIGNUP", "1");
-                        }
+                        const newValue = enableSignUpConfig === "1" ? "0" : "1";
+                        updateConfig("ENABLE_SIGNUP", newValue);
web/core/components/onboarding/create-or-join-workspaces.tsx (2)

40-41: Consider simplifying the permission check logic.

The double negative in the current implementation makes it slightly harder to read at first glance.

Consider this more straightforward approach:

- const isWorkspaceCreationEnabled = getIsWorkspaceCreationDisabled() === false;
+ const isWorkspaceCreationEnabled = !getIsWorkspaceCreationDisabled();

86-88: Consider extracting the error message text.

For better maintainability and potential internationalization, consider extracting the error message to a constant or translation key.

Example:

const WORKSPACE_CREATION_DISABLED_MESSAGE = 
  "You don't seem to have any invites to a workspace and your instance admin has restricted " +
  "creation of new workspaces. Please ask a workspace owner or admin to invite you to a workspace first " +
  "and come back to this screen to join.";

Then use it in the JSX:

<span>{WORKSPACE_CREATION_DISABLED_MESSAGE}</span>
web/app/create-workspace/page.tsx (2)

Line range hint 41-44: Add error handling and loading state

The form submission handler should handle potential API failures and provide feedback to users during the submission process.

+const [isSubmitting, setIsSubmitting] = useState(false);
+
 const onSubmit = async (workspace: IWorkspace) => {
-  await updateUserProfile({ last_workspace_id: workspace.id }).then(() => router.push(`/${workspace.slug}`));
+  try {
+    setIsSubmitting(true);
+    await updateUserProfile({ last_workspace_id: workspace.id });
+    router.push(`/${workspace.slug}`);
+  } catch (error) {
+    // Handle error appropriately (e.g., show toast notification)
+    console.error("Failed to create workspace:", error);
+  } finally {
+    setIsSubmitting(false);
+  }
 };

77-82: Consider making email template configurable

The email template is currently hardcoded. Consider moving it to a configuration file or constants to make it easier to maintain and customize.

+// Add to constants file
+const EMAIL_TEMPLATES = {
+  WORKSPACE_REQUEST: {
+    subject: "Requesting a new workspace",
+    body: (user: { first_name: string; last_name: string; email: string }) =>
+      `Hi instance admin(s),\n\nPlease create a new workspace with the URL [/workspace-name] for [purpose of creating the workspace].\n\nThanks,\n${user.first_name} ${user.last_name}\n${user.email}`,
+  },
+};

// In component
<a
  href={`mailto:?subject=${encodeURIComponent(EMAIL_TEMPLATES.WORKSPACE_REQUEST.subject)}&body=${encodeURIComponent(EMAIL_TEMPLATES.WORKSPACE_REQUEST.body(currentUser))}`}
  className={getButtonStyling("outline-primary", "md")}
>
  Request instance admin
</a>
admin/app/general/form.tsx (1)

120-131: Fix spacing in telemetry description text

The text changes improve clarity and transparency. However, there's a missing space after the period in "collected.This".

Apply this diff to fix the spacing:

-                No PII is collected.This anonymized data is used to understand how you use Plane and build new features
+                No PII is collected. This anonymized data is used to understand how you use Plane and build new features
admin/app/workspace/page.tsx (3)

32-32: Improve type safety for configuration value.

The nullish coalescing with an empty string default might lead to type confusion. Consider using a boolean default instead.

-const disableWorkspaceCreation = formattedConfig?.DISABLE_WORKSPACE_CREATION ?? "";
+const disableWorkspaceCreation = formattedConfig?.DISABLE_WORKSPACE_CREATION ?? "0";

39-68: Enhance error handling and simplify promise chain.

The error handling could be more informative, and the promise chain can be simplified.

 const updateConfig = async (key: TInstanceConfigurationKeys, value: string) => {
   setIsSubmitting(true);
+  try {
     const payload = {
       [key]: value,
     };

     const updateConfigPromise = updateInstanceConfigurations(payload);

     setPromiseToast(updateConfigPromise, {
       loading: "Saving configuration",
       success: {
         title: "Success",
         message: () => "Configuration saved successfully",
       },
       error: {
         title: "Error",
-        message: () => "Failed to save configuration",
+        message: (error) => `Failed to save configuration: ${error.message}`,
       },
     });

-    await updateConfigPromise
-      .then(() => {
-        setIsSubmitting(false);
-      })
-      .catch((err) => {
-        console.error(err);
-        setIsSubmitting(false);
-      });
+    await updateConfigPromise;
+  } catch (err) {
+    console.error("Failed to update instance configuration:", err);
+  } finally {
+    setIsSubmitting(false);
+  }
 };

70-165: Add ARIA labels for better accessibility.

Consider adding appropriate ARIA labels to improve accessibility for screen readers.

-<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
+<div 
+  className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col"
+  role="region"
+  aria-label="Workspace Management"
+>

-<Button variant="link-primary" onClick={() => fetchNextWorkspaces()}
+<Button
+  variant="link-primary"
+  onClick={() => fetchNextWorkspaces()}
+  aria-label="Load more workspaces"

-<ToggleSwitch
+<ToggleSwitch
+  aria-label="Toggle workspace creation permission"
admin/app/email/email-config-form.tsx (1)

180-182: Consider strengthening the security recommendation.

While the text is clearer about authentication being optional, consider emphasizing the security benefits of SMTP authentication more strongly. Many SMTP servers require authentication to prevent email abuse and protect against unauthorized use.

Consider updating the text to:

-  This is optional, but we recommend setting up a username and a password for your SMTP server.
+  While optional, setting up SMTP authentication with a username and password is strongly recommended to secure your email server and prevent unauthorized use.
apiserver/plane/license/api/views/instance.py (2)

133-133: Document the new response field in API documentation

The response field is_workspace_creation_disabled is properly implemented, but it should be documented in the API documentation to ensure clients are aware of this new configuration option.

Consider adding this field to the API documentation with:

  • Field name: is_workspace_creation_disabled
  • Type: boolean
  • Description: "Indicates whether workspace creation is disabled for regular users"
  • Default value: false

133-133: Consider migration strategy for existing workspaces

When deploying this feature, consider:

  1. Communication strategy for informing users about the new restriction
  2. Handling of existing workspace creation requests in the pipeline
  3. Impact on API clients that might assume workspace creation is always available
admin/app/workspace/create/form.tsx (2)

20-40: Consider optimizing state management.

The current implementation could be improved by:

  1. Combining related state variables
  2. Moving defaultValues to useForm's defaultValues option

Consider this refactoring:

-const [slugError, setSlugError] = useState(false);
-const [invalidSlug, setInvalidSlug] = useState(false);
-const [defaultValues, setDefaultValues] = useState<Partial<IWorkspace>>({
-  name: "",
-  slug: "",
-  organization_size: "",
-});
+const [slugValidation, setSlugValidation] = useState<{
+  error: boolean;
+  invalid: boolean;
+}>({ error: false, invalid: false });

 const {
   handleSubmit,
   control,
   setValue,
   getValues,
   formState: { errors, isSubmitting, isValid },
-} = useForm<IWorkspace>({ defaultValues, mode: "onChange" });
+} = useForm<IWorkspace>({
+  defaultValues: {
+    name: "",
+    slug: "",
+    organization_size: "",
+  },
+  mode: "onChange"
+});

75-81: Consider removing unnecessary cleanup effect.

The useEffect for saving form values on unmount might be redundant since:

  1. react-hook-form already manages form state
  2. The saved values aren't used when the component remounts

Consider removing this effect if the form values don't need to persist between unmount and remount cycles.

web/core/components/workspace/create-workspace-form.tsx (3)

138-139: Improve consistency in validation error messages

The regex allows underscores but the error message doesn't reflect this. Consider updating the message to be consistent with the allowed characters and the formatting style used in other messages.

-                  `Workspaces names can contain only (" "), ( - ), ( _ ) and alphanumeric characters.`,
+                  "Workspace names can contain only spaces, hyphens, underscores, and alphanumeric characters."

Line range hint 67-68: Enhance error handling and user feedback

The error messages could be more specific to help users better understand and resolve issues. Consider:

  1. Including the workspace name in success messages
  2. Providing more specific error messages for different failure scenarios
               setToast({
                 type: TOAST_TYPE.SUCCESS,
                 title: "Success!",
-                message: "Workspace created successfully.",
+                message: `Workspace "${formData.name}" created successfully.`,
               });

               if (onSubmit) await onSubmit(res);
             })
             .catch(() => {
               setToast({
                 type: TOAST_TYPE.ERROR,
                 title: "Error!",
-                message: "Workspace could not be created. Please try again.",
+                message: "Failed to create workspace. Please check your connection and try again.",
               });

Also applies to: 89-90, 95-99


Line range hint 35-35: Consider architectural improvements

The WorkspaceService instance could be moved to a custom hook or context to improve reusability and testability. Additionally, consider using zod for runtime validation of form default values.

Example implementation:

// hooks/use-workspace-service.ts
export const useWorkspaceService = () => {
  const workspaceService = useMemo(() => new WorkspaceService(), []);
  return workspaceService;
};

// types/workspace.schema.ts
import { z } from 'zod';

export const workspaceSchema = z.object({
  name: z.string(),
  slug: z.string(),
  organization_size: z.string()
});

export type WorkspaceFormData = z.infer<typeof workspaceSchema>;
web/core/components/workspace/settings/workspace-details.tsx (6)

7-8: Consider grouping related imports together

The imports could be better organized by grouping related imports together (e.g., all constants together, all types together, etc.).

- // constants
- import { ORGANIZATION_SIZE } from "@plane/constants";
- // types
- import { IWorkspace } from "@plane/types";
+ // types and constants
+ import { ORGANIZATION_SIZE } from "@plane/constants";
+ import { IWorkspace } from "@plane/types";

Line range hint 29-34: Consider making the default organization size configurable

The default organization size is hardcoded to "2-10". Consider making this configurable or using the first value from ORGANIZATION_SIZE for better maintainability.

+ const DEFAULT_ORG_SIZE = ORGANIZATION_SIZE[0];

const defaultValues: Partial<IWorkspace> = {
  name: "",
  url: "",
-  organization_size: "2-10",
+  organization_size: DEFAULT_ORG_SIZE,
  logo_url: null,
};

Line range hint 47-77: Improve error handling and loading state management

  1. The setTimeout for loading state is unnecessary and could lead to race conditions.
  2. Error handling could be more specific and user-friendly.
 const onSubmit = async (formData: IWorkspace) => {
   if (!currentWorkspace) return;

   setIsLoading(true);
   try {
     const payload: Partial<IWorkspace> = {
       name: formData.name,
       organization_size: formData.organization_size,
     };

     const res = await updateWorkspace(currentWorkspace.slug, payload);
     captureWorkspaceEvent({
       eventName: WORKSPACE_UPDATED,
       payload: {
         ...res,
         state: "SUCCESS",
         element: "Workspace general settings page",
       },
     });
     setToast({
       title: "Success!",
       type: TOAST_TYPE.SUCCESS,
       message: "Workspace updated successfully",
     });
   } catch (err) {
     captureWorkspaceEvent({
       eventName: WORKSPACE_UPDATED,
       payload: {
         state: "FAILED",
         element: "Workspace general settings page",
       },
     });
-    console.error(err);
+    const errorMessage = err instanceof Error ? err.message : "Failed to update workspace";
+    setToast({
+      title: "Error",
+      type: TOAST_TYPE.ERROR,
+      message: errorMessage,
+    });
   } finally {
-    setTimeout(() => {
-      setIsLoading(false);
-    }, 300);
+    setIsLoading(false);
   }
 };

Line range hint 79-98: Add logo URL validation

Consider adding validation for the logo URL to ensure it's a valid image URL before updating.

 const handleRemoveLogo = async () => {
   if (!currentWorkspace) return;

+  const validateImageUrl = (url: string): boolean => {
+    return url === "" || /\.(jpg|jpeg|png|gif|svg)$/i.test(url);
+  };
+
   await updateWorkspace(currentWorkspace.slug, {
     logo_url: "",
   })
     .then(() => {
       setToast({
         type: TOAST_TYPE.SUCCESS,
         title: "Success!",
         message: "Workspace picture removed successfully.",
       });
     })
     .catch((error) => {
+      const errorMessage = error instanceof Error 
+        ? error.message 
+        : "Failed to remove workspace picture";
       setToast({
         type: TOAST_TYPE.ERROR,
         title: "Error!",
-        message: "There was some error in deleting your profile picture. Please try again.",
+        message: errorMessage,
       });
     });
 };

Line range hint 100-111: Improve URL handling with a utility function

The current URL handling directly accesses the window object and uses string replacements. Consider creating a utility function for better maintainability and testing.

+ const getWorkspaceUrl = (slug: string): string => {
+   if (typeof window === "undefined") return slug;
+   const origin = new URL(window.location.origin);
+   return `${origin.host}/${slug}`;
+ };

 const handleCopyUrl = () => {
   if (!currentWorkspace) return;

-  copyUrlToClipboard(`${currentWorkspace.slug}`).then(() => {
+  copyUrlToClipboard(getWorkspaceUrl(currentWorkspace.slug)).then(() => {
     setToast({
       type: TOAST_TYPE.SUCCESS,
       title: "Workspace URL copied to the clipboard.",
     });
   });
 };

Line range hint 113-285: Enhance accessibility with ARIA labels and roles

The UI components could benefit from improved accessibility attributes.

- <button type="button" onClick={() => setIsImageUploadModalOpen(true)} disabled={!isAdmin}>
+ <button 
+   type="button" 
+   onClick={() => setIsImageUploadModalOpen(true)} 
+   disabled={!isAdmin}
+   aria-label="Upload workspace logo"
+   role="button"
+ >

- <div className="relative mx-auto flex h-14 w-14">
+ <div 
+   className="relative mx-auto flex h-14 w-14"
+   role="img"
+   aria-label="Workspace logo"
+ >

- <Button variant="primary" onClick={handleSubmit(onSubmit)} loading={isLoading}>
+ <Button 
+   variant="primary" 
+   onClick={handleSubmit(onSubmit)} 
+   loading={isLoading}
+   aria-busy={isLoading}
+ >
web/core/components/onboarding/create-workspace.tsx (3)

164-170: Consider extracting validation constants

The validation rules are good, but consider extracting magic numbers and regex patterns to named constants for better maintainability.

+// Add to constants file
+export const WORKSPACE_VALIDATION = {
+  NAME_MAX_LENGTH: 80,
+  SLUG_MAX_LENGTH: 48,
+  NAME_PATTERN: /^[\w\s-]*$/,
+  NAME_ERROR_MESSAGE: 'Workspaces names can contain only (" "), ( - ), ( _ ) and alphanumeric characters.'
+};

 // In component
 maxLength: {
-  value: 80,
+  value: WORKSPACE_VALIDATION.NAME_MAX_LENGTH,
   message: "Limit your name to 80 characters"
 }

Also applies to: 209-212


228-229: Optimize slug validation logic

The current implementation makes two separate state updates. Consider combining them for better performance.

-if (/^[a-zA-Z0-9_-]+$/.test(e.target.value)) setInvalidSlug(false);
-else setInvalidSlug(true);
+const isValidSlug = /^[a-zA-Z0-9_-]+$/.test(e.target.value);
+setInvalidSlug(!isValidSlug);

241-241: Consider preparing for internationalization

The UI text improvements are good, but consider extracting all user-facing strings to translation constants for future localization support.

+// Add to translation file
+export const WORKSPACE_CREATION_MESSAGES = {
+  URL_TAKEN: 'This URL is taken. Try something else.',
+  INVALID_URL: 'URLs can contain only ( - ), ( _ ) and alphanumeric characters.',
+  TEAM_SIZE_LABEL: 'How many people will use this workspace?',
+  SELECT_RANGE: 'Select a range'
+};

-<p className="text-sm text-red-500">This URL is taken. Try something else.</p>
+<p className="text-sm text-red-500">{WORKSPACE_CREATION_MESSAGES.URL_TAKEN}</p>

Also applies to: 243-243, 253-253, 266-266

apiserver/plane/license/management/commands/configure_instance.py (2)

Line range hint 158-164: Fix incorrect category for GPT_ENGINE configuration.

The GPT_ENGINE configuration is currently categorized as "SMTP" but should be under "OPENAI" category since it's related to OpenAI settings.

Apply this fix:

             {
                 "key": "GPT_ENGINE",
                 "value": os.environ.get("GPT_ENGINE", "gpt-3.5-turbo"),
-                "category": "SMTP",
+                "category": "OPENAI",
                 "is_encrypted": False,
             },

Line range hint 165-171: Fix typo in UNSPLASH_ACCESS_KEY environment variable.

There's a typo in the environment variable name: "UNSPLASH_ACESS_KEY" is missing a "C".

Apply this fix:

             {
                 "key": "UNSPLASH_ACCESS_KEY",
-                "value": os.environ.get("UNSPLASH_ACESS_KEY", ""),
+                "value": os.environ.get("UNSPLASH_ACCESS_KEY", ""),
                 "category": "UNSPLASH",
                 "is_encrypted": True,
             },
apiserver/plane/app/views/workspace/base.py (2)

94-97: Enhance error message for better user experience

The current error message could be more descriptive to help users understand why they can't create workspaces.

Consider providing a more informative message:

             return Response(
-                {"error": "Workspace creation is not allowed"},
+                {
+                    "error": "Workspace creation has been disabled by the instance administrator. Please contact your administrator for assistance."
+                },
                 status=status.HTTP_403_FORBIDDEN,
             )

84-98: Consider caching the configuration value

The configuration value is retrieved on every workspace creation request, which could be inefficient if there are many requests.

Consider implementing caching for the configuration value:

  1. Use Django's caching framework to cache the configuration value
  2. Implement a configuration refresh mechanism
  3. Add a cache invalidation strategy when the configuration is updated

Would you like me to provide an example implementation?

web/core/components/workspace/sidebar/dropdown.tsx (1)

59-60: Consider simplifying the boolean expression

The double negation pattern can be simplified for better readability.

- const isWorkspaceCreationEnabled = getIsWorkspaceCreationDisabled() === false;
+ const isWorkspaceCreationEnabled = !getIsWorkspaceCreationDisabled();
apiserver/plane/license/api/views/workspace.py (4)

46-46: Remove trailing whitespace

There is trailing whitespace on line 46. Removing it will maintain code cleanliness and adhere to PEP 8 styling guidelines.

🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis

[notice] 46-46: apiserver/plane/license/api/views/workspace.py#L46
Trailing whitespace


78-78: Fix unnecessary whitespace in the serializer initialization

There is an extra whitespace character (a tab) between WorkspaceSerializer and (data=request.data) on line 78. Removing the unnecessary whitespace improves code readability.

Apply this diff to fix the issue:

-            serializer = WorkspaceSerializer	(data=request.data)
+            serializer = WorkspaceSerializer(data=request.data)

40-45: Simplify project count annotation using Count aggregate

The current approach to annotate project_count is unnecessarily complex. You can simplify it by using the Count aggregate function directly, which improves readability and performance.

Suggested changes:

  • Import the Count function:

    from django.db.models import Count
  • Modify the workspaces queryset to annotate the total number of projects:

            workspaces = Workspace.objects.annotate(
    -           total_projects=project_count,
    +           total_projects=Count('project', distinct=True),
                total_members=member_count,
            )
  • Ensure that the related_name for projects in the Workspace model is set to 'project' or adjust accordingly.


47-54: Simplify member count annotation using Count aggregate

Similar to the project count, you can simplify the member_count annotation by using the Count function directly.

Suggested changes:

  • Modify the workspaces queryset to annotate the total number of members:

            workspaces = Workspace.objects.annotate(
                total_projects=total_projects,
    -           total_members=member_count,
    +           total_members=Count(
    +               'workspacemember',
    +               filter=Q(workspacemember__member__is_bot=False, workspacemember__is_active=True),
    +               distinct=True
    +           ),
            )
  • Ensure that the related_name for workspace members in the Workspace model is set to 'workspacemember' or adjust accordingly.

  • Import Q for the filter:

    from django.db.models import Q
admin/core/store/workspace.store.ts (5)

109-109: Simplify the conditional check for pagination

You can simplify the condition by using optional chaining and a direct falsy check, which improves readability.

Apply this diff:

-if (!this.paginationInfo || this.paginationInfo.next_page_results === false) return [];
+if (!this.paginationInfo?.next_page_results) return [];

34-34: Remove unused store parameter from constructor

The store parameter in the constructor is not used within the class. Removing it can clean up the code and avoid confusion.

Apply this diff:

-export class WorkspaceStore implements IWorkspaceStore {
-  constructor(private store: CoreRootStore) {
+export class WorkspaceStore implements IWorkspaceStore {
+  constructor() {

81-83: Implement centralized error handling instead of console logs

Logging errors to the console is not ideal for production applications. Consider using a centralized error handling or logging service to capture and manage errors effectively.

Also applies to: 110-112, 136-138


80-102: Refactor common logic to reduce duplication

The methods fetchWorkspaces and fetchNextWorkspaces share similar code for fetching and processing workspace data. Extract the shared logic into a helper method to adhere to the DRY principle.

Also applies to: 108-127


91-91: Use direct assignment instead of set from lodash

Since this.workspaces is a flat object with workspace IDs as keys, you can assign directly instead of using set, reducing dependencies and enhancing performance.

Apply this diff:

-set(this.workspaces, [workspace.id], workspace);
+this.workspaces[workspace.id] = workspace;

Also, remove the unnecessary import:

-import set from "lodash/set";

Also applies to: 116-116, 140-140

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7469e67 and 9721c03.

⛔ Files ignored due to path filters (1)
  • web/public/workspace/workspace-creation-disabled.png is excluded by !**/*.png
📒 Files selected for processing (52)
  • admin/app/ai/form.tsx (1 hunks)
  • admin/app/authentication/github/form.tsx (1 hunks)
  • admin/app/authentication/gitlab/form.tsx (1 hunks)
  • admin/app/authentication/google/form.tsx (1 hunks)
  • admin/app/authentication/page.tsx (2 hunks)
  • admin/app/email/email-config-form.tsx (2 hunks)
  • admin/app/general/form.tsx (1 hunks)
  • admin/app/general/intercom.tsx (1 hunks)
  • admin/app/workspace/create/form.tsx (1 hunks)
  • admin/app/workspace/create/page.tsx (1 hunks)
  • admin/app/workspace/layout.tsx (1 hunks)
  • admin/app/workspace/page.tsx (1 hunks)
  • admin/ce/components/common/upgrade-button.tsx (1 hunks)
  • admin/core/components/admin-sidebar/help-section.tsx (1 hunks)
  • admin/core/components/admin-sidebar/sidebar-menu.tsx (2 hunks)
  • admin/core/components/auth-header.tsx (1 hunks)
  • admin/core/components/new-user-popup.tsx (2 hunks)
  • admin/core/components/workspace/index.ts (1 hunks)
  • admin/core/components/workspace/list-item.tsx (1 hunks)
  • admin/core/hooks/store/index.ts (1 hunks)
  • admin/core/hooks/store/use-workspace.tsx (1 hunks)
  • admin/core/services/workspace.service.ts (1 hunks)
  • admin/core/store/root.store.ts (1 hunks)
  • admin/core/store/workspace.store.ts (1 hunks)
  • apiserver/plane/app/views/workspace/base.py (3 hunks)
  • apiserver/plane/license/api/serializers/__init__.py (1 hunks)
  • apiserver/plane/license/api/serializers/user.py (1 hunks)
  • apiserver/plane/license/api/serializers/workspace.py (1 hunks)
  • apiserver/plane/license/api/views/__init__.py (1 hunks)
  • apiserver/plane/license/api/views/instance.py (3 hunks)
  • apiserver/plane/license/api/views/workspace.py (1 hunks)
  • apiserver/plane/license/management/commands/configure_instance.py (1 hunks)
  • apiserver/plane/license/urls.py (2 hunks)
  • packages/constants/index.ts (1 hunks)
  • packages/constants/workspace.ts (1 hunks)
  • packages/types/src/instance/base.d.ts (3 hunks)
  • packages/types/src/instance/index.d.ts (1 hunks)
  • packages/types/src/instance/workspace.d.ts (1 hunks)
  • packages/types/src/workspace.d.ts (2 hunks)
  • packages/ui/src/icons/index.ts (1 hunks)
  • packages/ui/src/icons/workspace-icon.tsx (1 hunks)
  • web/app/create-workspace/page.tsx (3 hunks)
  • web/ce/helpers/instance.helper.ts (1 hunks)
  • web/core/components/account/auth-forms/auth-header.tsx (1 hunks)
  • web/core/components/account/auth-forms/email.tsx (1 hunks)
  • web/core/components/onboarding/create-or-join-workspaces.tsx (3 hunks)
  • web/core/components/onboarding/create-workspace.tsx (6 hunks)
  • web/core/components/workspace/create-workspace-form.tsx (7 hunks)
  • web/core/components/workspace/settings/workspace-details.tsx (1 hunks)
  • web/core/components/workspace/sidebar/dropdown.tsx (3 hunks)
  • web/core/constants/workspace.ts (0 hunks)
  • web/ee/helpers/instance.helper.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • web/core/constants/workspace.ts
✅ Files skipped from review due to trivial changes (8)
  • admin/app/authentication/gitlab/form.tsx
  • admin/app/authentication/google/form.tsx
  • admin/app/general/intercom.tsx
  • admin/core/components/admin-sidebar/help-section.tsx
  • admin/core/components/workspace/index.ts
  • packages/constants/workspace.ts
  • web/core/components/account/auth-forms/email.tsx
  • web/ee/helpers/instance.helper.ts
🧰 Additional context used
🪛 GitHub Check: Codacy Static Code Analysis
apiserver/plane/license/api/serializers/__init__.py

[notice] 5-5: apiserver/plane/license/api/serializers/init.py#L5
'.workspace.WorkspaceSerializer' imported but unused (F401)

apiserver/plane/license/api/views/__init__.py

[notice] 18-18: apiserver/plane/license/api/views/init.py#L18
'.workspace.InstanceWorkSpaceAvailabilityCheckEndpoint' imported but unused (F401)

apiserver/plane/license/api/views/workspace.py

[notice] 46-46: apiserver/plane/license/api/views/workspace.py#L46
Trailing whitespace

🪛 Ruff (0.8.0)
apiserver/plane/license/api/views/__init__.py

18-18: Line too long (92 > 88)

(E501)

🔇 Additional comments (60)
packages/types/src/instance/workspace.d.ts (1)

1-1: Verify the integration with instance configuration.

The type appears to be correctly defined for workspace configuration. Let's verify its integration with the rest of the codebase.

✅ Verification successful

Type is properly integrated and used across the codebase

The verification shows that the DISABLE_WORKSPACE_CREATION configuration key is well-integrated:

  • It's correctly defined in the type system and imported in base.d.ts
  • The backend properly implements the configuration in workspace creation logic
  • The admin UI correctly uses this configuration for toggling workspace creation
  • The instance configuration API properly handles this setting
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration of the new configuration key

# Check if the type is properly imported and used in instance configuration
echo "Checking usage in instance configuration..."
ast-grep --pattern 'interface IInstanceConfig {
  $$$
  is_workspace_creation_disabled: boolean;
  $$$
}'

# Check for components using this configuration
echo "Checking usage in components..."
rg -l "DISABLE_WORKSPACE_CREATION"

# Check for any potential type imports
echo "Checking type imports..."
rg -l "TInstanceWorkspaceConfigurationKeys"

Length of output: 2359


Script:

#!/bin/bash
# Let's check how the configuration is being used in the components

# Check workspace creation logic in app/views/workspace/base.py
echo "Checking workspace creation logic..."
rg -A 5 "DISABLE_WORKSPACE_CREATION" "apiserver/plane/app/views/workspace/base.py"

# Check instance configuration in license views
echo "Checking instance configuration..."
rg -A 5 "DISABLE_WORKSPACE_CREATION" "apiserver/plane/license/api/views/instance.py"

# Check admin workspace page usage
echo "Checking admin workspace page usage..."
rg -A 5 "DISABLE_WORKSPACE_CREATION" "admin/app/workspace/page.tsx"

# Check the type import and usage in base.d.ts
echo "Checking type usage in base.d.ts..."
rg -A 5 "TInstanceWorkspaceConfigurationKeys" "packages/types/src/instance/base.d.ts"

Length of output: 3036

packages/constants/index.ts (1)

2-3: Verify the workspace constants implementation

The changes look good and align with the PR objectives. Let's verify the implementation of the workspace constants that will be used for the new workspace management features.

✅ Verification successful

Workspace constants are properly implemented and used consistently

The workspace constants (ORGANIZATION_SIZE and RESTRICTED_URLS) are correctly defined in packages/constants/workspace.ts and are being used appropriately across the codebase in workspace creation and management components:

  • Used in workspace creation forms (create-workspace-form.tsx, create-workspace.tsx)
  • Used in workspace settings (workspace-details.tsx)
  • Used in admin workspace management (form.tsx)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the workspace constants implementation and usage

# Check if workspace.ts exists and view its contents
echo "Checking workspace constants implementation:"
fd -t f "workspace.ts" -x cat {}

# Check where these constants are being used
echo -e "\nChecking workspace constants usage:"
rg -l "ORGANIZATION_SIZE|RESTRICTED_URLS"

Length of output: 22271

admin/core/hooks/store/index.ts (1)

4-4: LGTM! The export follows consistent patterns.

The new export statement maintains the established pattern and naming convention, properly integrating the workspace management functionality into the admin app's hook system.

Let's verify the existence of the referenced module:

✅ Verification successful

The export is correctly implemented and the module exists

The use-workspace module exists in the correct location (admin/core/hooks/store/use-workspace.tsx) and properly exports the useWorkspace hook. The implementation follows React's context pattern and includes appropriate error handling. While a similar hook exists in the web directory, they are properly separated and serve different contexts with distinct store types (IWorkspaceStore vs IWorkspaceRootStore).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the use-workspace module exists and exports expected hook
# Expected: Find the useWorkspace hook definition

# Check if the use-workspace file exists
fd "use-workspace.ts" --type f

# Verify the hook implementation
ast-grep --pattern 'export const useWorkspace = () => {
  $$$
}'

Length of output: 176


Script:

#!/bin/bash
# Let's verify the content of both use-workspace files to ensure correct implementation
# and check if they might conflict

# Check admin implementation
echo "=== Admin Implementation ==="
cat admin/core/hooks/store/use-workspace.tsx

# Check web implementation
echo "=== Web Implementation ==="
cat web/core/hooks/store/use-workspace.ts

Length of output: 1003

packages/types/src/instance/index.d.ts (1)

6-6: LGTM! Verify the workspace module exports.

The new export follows the established pattern and aligns with the workspace management feature objectives.

Let's verify the workspace module being exported:

✅ Verification successful

Workspace module export verified and properly integrated

The workspace module export is valid and well-integrated:

  • Contains the TInstanceWorkspaceConfigurationKeys type with "DISABLE_WORKSPACE_CREATION" value
  • The type is properly imported and used in base.d.ts as part of the TInstanceConfigurationKeys union type
  • The integration follows the established pattern of configuration key types in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the workspace module exists and contains expected types

# Check if the workspace.d.ts file exists in the same directory
fd -t f "workspace.d.ts" "packages/types/src/instance"

# Check the contents of workspace-related type definitions
ast-grep --pattern 'interface $interface {
  $$$
}'  "packages/types/src/instance/workspace.d.ts"

# Verify the TInstanceWorkspaceConfigurationKeys type mentioned in the summary
ast-grep --pattern 'type TInstanceWorkspaceConfigurationKeys = $value'

Length of output: 265


Script:

#!/bin/bash
# Let's check the actual content of the workspace.d.ts file
cat packages/types/src/instance/workspace.d.ts

# Also check if there are any references to workspace types in other files
rg -l "workspace" packages/types/src/instance/

Length of output: 252


Script:

#!/bin/bash
# Let's check the content of base.d.ts to see how workspace types are used
cat packages/types/src/instance/base.d.ts

Length of output: 2676

apiserver/plane/license/api/serializers/__init__.py (1)

5-5: LGTM! Let's verify the serializer usage.

The import follows the established pattern of re-exporting serializers and aligns with the workspace management feature.

Let's verify the usage of this serializer in the codebase:

✅ Verification successful

Import is correctly used and integrated in the workspace management feature

The WorkspaceSerializer import is actively used in multiple places within the workspace management implementation:

  • Used in InstanceWorkSpaceAvailabilityCheckEndpoint for workspace data serialization
  • Handles workspace creation with proper validation of slugs
  • Integrates with the workspace model and includes essential fields like owner, logo_url, and project counts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that WorkspaceSerializer is being used in the workspace management feature

# Check for WorkspaceSerializer usage in views and other components
rg -l "WorkspaceSerializer" apiserver/plane/license/api/

# Check for workspace-related API endpoints that might use this serializer
ast-grep --pattern 'class $_(ViewSet|APIView) {
  $$$
  serializer_class = WorkspaceSerializer
  $$$
}'

Length of output: 314


Script:

#!/bin/bash
# Let's check the actual implementation and usage
# First, check the view implementation
rg -A 5 "WorkspaceSerializer" apiserver/plane/license/api/views/workspace.py

# Then check the actual serializer definition
cat apiserver/plane/license/api/serializers/workspace.py

Length of output: 1997

🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis

[notice] 5-5: apiserver/plane/license/api/serializers/init.py#L5
'.workspace.WorkspaceSerializer' imported but unused (F401)

apiserver/plane/license/api/serializers/user.py (2)

1-2: LGTM! Clean and minimal imports.

The imports are appropriately scoped and follow good practices.


3-6: Verify integration with workspace management views.

Let's ensure this serializer is properly integrated with the workspace management functionality.

✅ Verification successful

Integration with workspace management is properly implemented

The UserLiteSerializer is correctly integrated with workspace management functionality:

  • Used in workspace.py serializers to represent workspace owners
  • Properly integrated in workspace member management through WorkspaceMemberInvite and member listings
  • Used consistently across workspace-related features for user representation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how UserLiteSerializer is used in workspace management context

# Look for workspace-related views that might use this serializer
rg -l "UserLiteSerializer" apiserver/plane/license/api/views/
rg -l "workspace.*view" apiserver/plane/license/api/views/

# Check for workspace-related API endpoints
rg -l "workspace" apiserver/plane/license/api/urls.py

Length of output: 252


Script:

#!/bin/bash
# Let's broaden our search to find where UserLiteSerializer is used across the codebase
rg "UserLiteSerializer" -A 3

# Also search for workspace-related views and URLs in the entire codebase
fd "urls.py|views.py" --exec rg -l "workspace" {}

# Check if there are any workspace-related models that might use this serializer
fd "models.py" --exec rg -l "workspace" {}

Length of output: 22977

web/ce/helpers/instance.helper.ts (2)

3-7: LGTM! The implementation is clean and follows good practices.

The function correctly implements the workspace creation check using optional chaining for safe property access.


3-7: Verify the integration with dependent components.

Let's confirm that this helper function is properly integrated with the components mentioned in the summary.

✅ Verification successful

Helper function is properly integrated across components

The verification confirms that getIsWorkspaceCreationDisabled is correctly integrated in all mentioned components:

  • web/app/create-workspace/page.tsx: Used directly as isWorkspaceCreationDisabled
  • web/core/components/onboarding/create-or-join-workspaces.tsx: Used with logical negation as isWorkspaceCreationEnabled
  • web/core/components/workspace/sidebar/dropdown.tsx: Used with logical negation as isWorkspaceCreationEnabled

All components properly import the helper from the correct path and use it consistently to control workspace creation functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of getIsWorkspaceCreationDisabled across components

echo "Checking usage of getIsWorkspaceCreationDisabled in components..."
rg -l "getIsWorkspaceCreationDisabled" --type ts --type tsx

echo "\nChecking the implementation context in each file..."
rg -B 2 -A 2 "getIsWorkspaceCreationDisabled" --type ts --type tsx

Length of output: 440


Script:

#!/bin/bash
# Let's try a different approach using just the file extension patterns
echo "Checking usage of getIsWorkspaceCreationDisabled..."
rg -l "getIsWorkspaceCreationDisabled" "*.ts" "*.tsx"

echo "\nChecking implementation context..."
rg -B 2 -A 2 "getIsWorkspaceCreationDisabled" "*.ts" "*.tsx"

Length of output: 492


Script:

#!/bin/bash
# Let's try using fd to find files first, then pipe to ripgrep
echo "Finding TypeScript files that use getIsWorkspaceCreationDisabled..."
fd -e ts -e tsx | xargs rg -l "getIsWorkspaceCreationDisabled"

echo "\nChecking implementation context in found files..."
fd -e ts -e tsx | xargs rg -B 2 -A 2 "getIsWorkspaceCreationDisabled"

Length of output: 3682

admin/app/workspace/layout.tsx (1)

10-12: Verify admin access control implementation.

The component looks well-structured, but we should ensure that the AdminLayout component properly restricts access to admin users only.

✅ Verification successful

Let me generate the final response based on the gathered information.

Access control is properly implemented in the admin layout

The admin section has a comprehensive authentication system with multiple security layers:

  • Server-side authentication checks through /api/instances/admins/me/ endpoint
  • CSRF token protection for form submissions
  • Admin-specific user session validation
  • Multiple authentication modes (Email, Google, GitHub, GitLab) with proper OAuth configurations

The AdminLayout component is used within a protected admin route structure that ensures only authenticated admin users can access these sections. The implementation follows security best practices with proper session management and access control.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if AdminLayout implements proper access control

# Look for auth/admin check implementation in AdminLayout
ast-grep --pattern 'export function AdminLayout' -A 10
rg -A 10 "isAdmin|adminAuth|adminAccess" "admin/layouts/admin-layout*"

# Check for any auth middleware or guards
fd -e ts -e tsx "middleware" "admin/" --exec rg -l "admin|auth"

Length of output: 259


Script:

#!/bin/bash
# Let's try different approaches to locate AdminLayout and auth checks

# Find AdminLayout component
fd -e tsx -e ts "AdminLayout" --exec rg -l "AdminLayout"

# Search for the actual implementation
ast-grep --pattern 'function AdminLayout'

# Look for auth-related implementations
rg -A 5 "useAuth|isAdmin|adminAuth|requireAuth|authenticate"

# Check for middleware or guards in the entire codebase
fd "middleware" --exec rg -l "admin|auth"

Length of output: 70857


Script:

#!/bin/bash
# Let's search for AdminLayout implementation and auth checks in the admin directory

# Find AdminLayout component in admin directory
fd -e tsx -e ts -d 3 . admin/ --exec rg -l "AdminLayout"

# Search for auth middleware or guards specifically in admin routes
fd -e tsx -e ts -d 4 . admin/ --exec rg -A 5 "middleware|guard|auth|isAuthenticated|protect"

# Look for any auth hooks or context usage
rg -A 5 "useAuth|AuthContext|isAuthenticated" "admin/"

Length of output: 17467

admin/core/hooks/store/use-workspace.tsx (2)

1-4: LGTM! Well-organized imports with clear categorization.

The imports are properly structured, using path aliases and including all necessary dependencies for the hook's functionality.


3-4: Verify store integration and interface implementation.

Let's ensure the store context and workspace interface are properly implemented.

✅ Verification successful

Let me verify the hook's implementation to complete the analysis.


Store integration is properly implemented and type-safe

The verification shows:

  • StoreContext is correctly defined and exported with proper typing
  • IWorkspaceStore interface is well-defined with all required observables, computed properties, and actions
  • WorkspaceStore class fully implements the IWorkspaceStore interface with MobX decorators
  • The useWorkspace hook correctly:
    • Consumes the StoreContext
    • Includes proper type safety checks
    • Returns the workspace store instance
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify store context structure and workspace interface implementation

# Check StoreContext implementation
echo "Checking StoreContext implementation..."
ast-grep --pattern 'export const StoreContext = createContext<$_>($_)'

# Check IWorkspaceStore interface
echo "Checking IWorkspaceStore interface..."
ast-grep --pattern 'interface IWorkspaceStore {
  $$$
}'

# Check workspace store implementation
echo "Checking workspace store implementation..."
ast-grep --pattern 'class WorkspaceStore implements IWorkspaceStore {
  $$$
}'

Length of output: 10236


Script:

#!/bin/bash
# Check the hook implementation
echo "Checking useWorkspace hook implementation..."
ast-grep --pattern 'export const useWorkspace = () => {
  $$$
}'

# Check StoreContext usage in the hook
echo "Checking StoreContext usage in the hook..."
rg -A 5 "useContext\(StoreContext\)" admin/core/hooks/store/use-workspace.tsx

Length of output: 511

admin/app/workspace/create/page.tsx (2)

21-21: LGTM!

The export statement follows React component export conventions.


1-6: Verify the WorkspaceCreateForm implementation

The form component is imported but its implementation needs verification to ensure proper validation and error handling for workspace creation.

✅ Verification successful

Based on the shell script results, I can now generate the final response as the verification is complete. The results show proper form implementation with validation and error handling in place.

Form implementation verified successfully

The WorkspaceCreateForm has comprehensive validation and error handling:

  • Uses React Hook Form with onChange validation mode
  • Implements error handling for workspace creation and slug checking
  • Displays validation errors for name, slug, and organization size fields
  • Includes proper error toast notifications for API failures
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the form implementation for proper validation and error handling
# Expected: Find validation rules and error handling in the form component

# Search for form validation rules
ast-grep --pattern 'const $_ = useForm({
  $$$
})'

# Search for error handling patterns
rg -A 5 'catch|error|handleError' ./admin/app/workspace/create/form.tsx

Length of output: 6485

apiserver/plane/license/api/serializers/workspace.py (2)

1-9: LGTM! Imports are well-organized and complete.

The imports follow proper convention with third-party imports first, followed by local imports. All necessary dependencies are included.


11-15: Verify the implementation of computed fields.

The total_projects and total_members fields are marked as read-only, but we should verify their computation in the queryset or model.

✅ Verification successful

Let me gather more information to verify the total_projects field since it wasn't found in the current results.


Computed fields are properly implemented in the view layer

The total_projects and total_members fields are correctly handled through queryset annotations:

  • total_projects is computed using a subquery in license/api/views/workspace.py that counts related projects using Project.objects.filter(workspace_id=OuterRef("id"))
  • total_members is annotated using member_count in multiple views including app/views/workspace/base.py
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the implementation of total_projects and total_members

# Look for property methods or annotations in the Workspace model
ast-grep --pattern 'class Workspace$$$:
  $$$
  @property
  def total_projects($$$):
    $$$'

ast-grep --pattern 'class Workspace$$$:
  $$$
  @property
  def total_members($$$):
    $$$'

# Look for queryset annotations
rg -A 5 "annotate.*total_(projects|members)" 

Length of output: 1715


Script:

#!/bin/bash
# Check for project count annotations and related fields
rg -A 5 "projects.*count|count.*projects" 

# Look for workspace model definition to see all fields
ast-grep --pattern 'class Workspace($$$):
  $$$'

# Check the view that uses this serializer
rg -A 10 "WorkspaceSerializer"

Length of output: 11306

admin/core/store/root.store.ts (1)

6-6: LGTM: Workspace store integration is well-implemented

The workspace store integration follows the established patterns for store management, with proper typing and initialization.

Also applies to: 14-14, 20-20, 27-27

admin/core/services/workspace.service.ts (2)

1-11: LGTM! Clean imports and class structure.

The imports are well-organized, and the class properly extends APIService with appropriate initialization.


45-51: Consider rate limiting and input validation.

While the basic implementation is functional, consider these improvements:

  1. Add input validation
  2. Implement rate limiting protection
  3. Improve error handling

Let's verify if rate limiting is implemented in the API:

Consider implementing the following improvements:

   async createWorkspace(data: IWorkspace): Promise<IWorkspace> {
+    // Basic validation
+    const requiredFields = ['name', 'slug'] as const;
+    for (const field of requiredFields) {
+      if (!data[field]) throw new Error(`Missing required field: ${field}`);
+    }
+
+    // Add retry logic with exponential backoff
+    const maxRetries = 3;
+    let attempt = 0;
+
+    const attemptCreate = async (): Promise<IWorkspace> => {
+      try {
+        const response = await this.post<IWorkspace, IWorkspace>(
+          "/api/instances/workspaces/",
+          data
+        );
+        return response.data;
+      } catch (error: unknown) {
+        const errorResponse = error?.response?.data as WorkspaceError;
+        
+        if (errorResponse?.message?.includes('rate limit') && attempt < maxRetries) {
+          attempt++;
+          await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
+          return attemptCreate();
+        }
+        
+        throw errorResponse ?? new Error('Failed to create workspace');
+      }
+    };
+
+    return attemptCreate();
admin/core/components/new-user-popup.tsx (3)

4-4: LGTM: Import changes are appropriate

The new imports support the component's functionality - resolveGeneralTheme for theme resolution and Link for client-side navigation.

Also applies to: 7-7


31-31: LGTM: Text content is more concise

The simplified message provides clearer instructions without unnecessary details about re-login requirements.


34-34: Verify workspace creation route exists

Let's ensure the /workspace/create route is properly configured.

✅ Verification successful

Route exists and is properly implemented

The /workspace/create route is correctly configured and implemented:

  • The page component exists at admin/app/workspace/create/page.tsx
  • The form component is properly implemented with workspace creation functionality
  • The route is referenced and linked from the workspace management page
  • Next.js file-based routing handles the route configuration automatically
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the workspace creation page component exists
fd -t f "page.tsx" admin/app/workspace/create

# Check for any references to this route in the routing configuration
rg -l "workspace/create" admin/app

Length of output: 145


Script:

#!/bin/bash
# Let's verify the content of the create page component to ensure it's properly implemented
cat admin/app/workspace/create/page.tsx

# Also check the parent workspace page for any route configurations
cat admin/app/workspace/page.tsx

Length of output: 7522


Script:

#!/bin/bash
# Let's verify the WorkspaceCreateForm component implementation
cat admin/app/workspace/create/form.tsx

# Also check if there are any route configurations in the app directory
fd -t f "route.ts" admin/app/workspace/create

Length of output: 8067

apiserver/plane/license/urls.py (2)

15-16: LGTM! Import changes follow conventions.

The new imports maintain consistency with existing naming patterns and are properly grouped with related admin endpoints.


60-69: Verify security measures and HTTP methods for workspace endpoints.

The URL patterns follow RESTful conventions, but please ensure:

  1. These endpoints are properly protected with admin-only authentication middleware
  2. The appropriate HTTP methods are implemented (GET for slug check, GET/POST for workspace management)

Let's verify the security implementation:

✅ Verification successful

Security measures and HTTP methods are properly implemented

Both endpoints are correctly secured and implemented:

  1. Both views have permission_classes = [InstanceAdminPermission] ensuring admin-only access
  2. HTTP methods are appropriately defined:
    • InstanceWorkSpaceAvailabilityCheckEndpoint implements GET for slug checking
    • InstanceWorkSpaceEndpoint implements GET for workspace management
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for authentication/permission decorators and HTTP method definitions

# Check for authentication/permission decorators in the view
ast-grep --pattern 'class InstanceWorkSpace$_Endpoint:
  $$$
  @$_
  $$$
'

# Check HTTP method definitions
ast-grep --pattern 'class InstanceWorkSpace$_Endpoint:
  $$$
  def $_(self, request, $$$):
    $$$
'

Length of output: 179


Script:

#!/bin/bash
# Let's try a different approach to find the view implementations

# Search for the view class definitions
rg -A 10 "class InstanceWorkSpace.*Endpoint" --type py

# Also check for any imports of authentication/permission classes
rg "from rest_framework\.(permissions|authentication)" --type py

Length of output: 4715

packages/ui/src/icons/workspace-icon.tsx (1)

1-14: Verify the icon's integration in the admin sidebar.

The icon component looks well-implemented. Let's verify its integration in the admin sidebar menu.

✅ Verification successful

WorkspaceIcon is properly integrated in the admin sidebar

The icon is correctly imported and used in the admin sidebar menu as part of the workspace navigation item, with proper integration including:

  • Imported from "@plane/ui" package
  • Used as the Icon component for the "Workspaces" menu item
  • Links to the /workspace/ route
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the WorkspaceIcon usage in the admin sidebar menu

# Search for WorkspaceIcon usage in sidebar-menu.tsx
rg -l "WorkspaceIcon" "admin/core/components/sidebar-menu.tsx"

# Check if the icon is properly imported and used in INSTANCE_ADMIN_LINKS
ast-grep --pattern 'import { WorkspaceIcon } from "$_"'

Length of output: 197


Script:

#!/bin/bash
# Let's first find where the sidebar menu component might be located
fd -t f "sidebar" -e tsx -e ts

# Then search for WorkspaceIcon usage across the codebase
rg -l "WorkspaceIcon"

# Search for any menu or navigation related files that might use this icon
fd -t f "menu|nav" -e tsx -e ts

Length of output: 2882


Script:

#!/bin/bash
# Let's check how WorkspaceIcon is used in the admin sidebar menu
rg -A 5 "WorkspaceIcon" "admin/core/components/admin-sidebar/sidebar-menu.tsx"

# Also check the structure of the admin sidebar menu component
ast-grep --pattern 'const $_: React.FC = () => {
  $$$
}'  "admin/core/components/admin-sidebar/sidebar-menu.tsx"

Length of output: 496

packages/types/src/instance/base.d.ts (2)

7-7: LGTM! Type definitions are well-structured.

The addition of workspace configuration types follows the existing pattern and maintains type consistency.

Also applies to: 83-84


7-7: Verify type consistency across the codebase.

Let's ensure the new types and configuration are properly implemented.

Also applies to: 40-40, 83-84

✅ Verification successful

Based on the search results, I can now generate the final response:

Type definition is properly implemented and consistently used

The type TInstanceWorkspaceConfigurationKeys is well-defined in packages/types/src/instance/workspace.d.ts as:

export type TInstanceWorkspaceConfigurationKeys = "DISABLE_WORKSPACE_CREATION";

It's correctly imported and used in packages/types/src/instance/base.d.ts as part of the type system. The type changes are properly structured and don't introduce any inconsistencies in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify type definitions and usage

# Check if TInstanceWorkspaceConfigurationKeys is defined
echo "Checking for workspace configuration keys type definition..."
ast-grep --pattern 'type TInstanceWorkspaceConfigurationKeys ='

# Check usage of the new configuration flag
echo "Checking usage of workspace creation configuration..."
rg "is_workspace_creation_disabled" --type ts --type tsx -A 2

Length of output: 403


Script:

#!/bin/bash
# Let's try a different approach to find type definitions and usage

# Search for workspace configuration type definitions
echo "Searching for workspace configuration type definitions..."
rg "TInstanceWorkspaceConfigurationKeys" --type ts -A 3

# Search for any workspace configuration related code
echo "Searching for workspace configuration usage..."
rg "workspace.*config" --type ts -A 3

# Look for files that might contain workspace configuration
echo "Looking for workspace configuration files..."
fd -e ts -e d.ts . | grep -i "workspace\|config"

Length of output: 8024

admin/core/components/auth-header.tsx (1)

Line range hint 1-95: Verify integration with workspace management feature

While the changes support basic workspace navigation, let's verify the complete integration with the workspace management feature.

✅ Verification successful

Workspace navigation integration is properly implemented

The component's integration with workspace management is verified and properly implemented:

  • Workspace routes are correctly defined in admin/app/workspace/ directory
  • The header title handling is consistent with the workspace navigation structure
  • Proper integration with workspace-related components and services exists through:
    • Workspace store (admin/core/store/workspace.store.ts)
    • Workspace service (admin/core/services/workspace.service.ts)
    • Workspace hooks (admin/core/hooks/store/use-workspace.tsx)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the component's integration with workspace management

# Check for workspace-related route definitions
echo "Checking workspace route definitions..."
rg -l "workspace" --type tsx --glob "admin/app/**"

# Check for consistency in header title usage
echo "Checking header title usage..."
ast-grep --pattern 'title={getHeaderTitle($_)}' 

# Look for related workspace components
echo "Checking workspace component references..."
rg -l "WorkspaceCreate|WorkspaceManagement" --type tsx

Length of output: 468


Script:

#!/bin/bash
# Let's try a different approach without file type restrictions

# Check for workspace-related route definitions
echo "Checking workspace route definitions..."
rg -l "workspace" --glob "admin/app/**/*"

# Check for header title usage across the codebase
echo "Checking header title usage..."
rg "getHeaderTitle" -A 2 -B 2

# Look for related workspace components
echo "Checking workspace component references..."
rg -l "WorkspaceCreate|WorkspaceManagement"

# Check for any workspace-related components or routes
echo "Checking workspace-related files..."
fd -t f workspace admin/

Length of output: 1547

web/core/components/account/auth-forms/auth-header.tsx (2)

38-38: LGTM! Text changes improve clarity

The updated text for the sign-up flow:

  • Simplifies the header to a clear "Sign up"
  • Provides more descriptive instructions in the subheaders
  • Maintains consistency across different authentication steps

Also applies to: 42-43, 46-47


Line range hint 53-102: LGTM! Well-structured component implementation

The component demonstrates good practices:

  • Proper error handling with SWR
  • Clear loading state management
  • Clean conditional rendering for invitation flows
  • Type-safe implementation with TypeScript
admin/core/components/admin-sidebar/sidebar-menu.tsx (4)

7-7: LGTM: Import statement is properly placed

The WorkspaceIcon import is correctly added alongside other UI components.


20-25: LGTM: Well-structured workspace management menu item

The new workspace management menu item is properly integrated with appropriate icon, name, and routing path. The description clearly communicates its purpose to administrators.


17-17: LGTM: Improved description consistency

The descriptions have been standardized to end with periods, enhancing the overall consistency of the menu items.

Also applies to: 29-29, 35-35, 41-41, 47-47


24-24: Verify workspace route implementation

Let's ensure that the /workspace/ route is properly implemented and the necessary components are in place.

✅ Verification successful

Workspace route and components are properly implemented

The /workspace/ route is correctly implemented with all necessary components in place:

  • The workspace page component (admin/app/workspace/page.tsx) is fully functional with workspace listing and creation capabilities
  • Workspace management is supported by a dedicated service (workspace.service.ts) handling API operations
  • State management is properly implemented through workspace.store.ts with all required CRUD operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify workspace route implementation and related components

# Check for workspace route definition
echo "Checking for workspace route definition..."
rg -t tsx -t ts "workspace.*route|route.*workspace" admin/

# Check for workspace-related components
echo "Checking for workspace management components..."
fd -e tsx -e ts . admin/ --exec grep -l "workspace"

Length of output: 911


Script:

#!/bin/bash
# Let's verify the workspace route implementation and its components more thoroughly

# Check the workspace page implementation
echo "Checking workspace page implementation..."
cat admin/app/workspace/page.tsx

# Check the workspace service implementation
echo -e "\nChecking workspace service..."
cat admin/core/services/workspace.service.ts

# Check workspace store implementation
echo -e "\nChecking workspace store..."
cat admin/core/store/workspace.store.ts

Length of output: 12890

admin/app/ai/form.tsx (1)

Line range hint 1-123: LGTM! The implementation is secure and well-structured.

The form handles sensitive API configuration with proper security measures, good UX patterns, and clear documentation links.

admin/app/authentication/page.tsx (3)

63-63: LGTM! Clear and concise description text.

The updated text effectively communicates the purpose of the authentication configuration.


95-95: LGTM! Clear section heading.

The heading text "Available authentication modes" clearly describes the section content.


83-87: Verify integration with workspace management features.

Since this toggle affects sign-ups and potentially workspace creation, we should verify the interaction with the new workspace management features.

✅ Verification successful

Based on the search results, I can now generate a final response as we have sufficient information about the integration between signup settings and workspace management.

Integration with workspace management is properly handled

The ENABLE_SIGNUP setting is correctly integrated with workspace management:

  • It's coupled with workspace creation controls in the backend (DISABLE_WORKSPACE_CREATION)
  • The authentication adapter validates signup permissions against workspace invites
  • The setting is properly synchronized between frontend and backend configurations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check integration between authentication and workspace management

# Look for workspace creation permission checks
rg -A 5 "ENABLE_SIGNUP" --type typescript

# Check for related workspace management components
ast-grep --pattern 'const WorkspaceCreate = () => {
  $$$
}'

Length of output: 139


Script:

#!/bin/bash
# Search for ENABLE_SIGNUP usage across all files
rg -A 5 "ENABLE_SIGNUP"

# Look for workspace-related components and configurations
rg -A 5 "workspace|Workspace" --type ts --type tsx

# Search for signup-related components
rg -A 5 "signup|signUp|SignUp" --type ts --type tsx

Length of output: 5730

web/core/components/onboarding/create-or-join-workspaces.tsx (2)

7-7: LGTM! Import changes are well-organized.

The new imports are properly organized within their respective categories (icons and helpers).

Also applies to: 13-14


74-92: LGTM! Well-implemented conditional rendering with clear user feedback.

The implementation properly handles the workspace creation permission state and provides clear guidance to users when creation is disabled.

packages/types/src/workspace.d.ts (2)

24-24: LGTM! Well-structured property addition

The optional total_projects property is a good addition that maintains backward compatibility while supporting the new workspace management features.


227-229: LGTM! Well-designed pagination type

The TWorkspacePaginationInfo type follows TypeScript best practices by extending the base pagination type and properly typing the results array.

web/app/create-workspace/page.tsx (2)

38-39: LGTM! Clean implementation of workspace creation control

The derived value is well-placed and follows React best practices by calculating it within the component body.


65-85: LGTM! Well-implemented disabled state UI

The disabled state provides clear feedback and appropriate actions for users. The implementation is clean, responsive, and user-friendly.

admin/app/general/form.tsx (1)

Line range hint 1-150: Verify relationship with workspace management feature

The changes in this file appear to be text improvements unrelated to the main PR objective of workspace management. Could you clarify how these telemetry text updates relate to the workspace management feature being implemented?

admin/app/authentication/github/form.tsx (1)

198-198: LGTM! Consistent styling update across authentication forms.

The change from "link-neutral" to "neutral-primary" aligns with similar updates in other authentication forms (gitlab and google), maintaining styling consistency across the admin interface while preserving the existing functionality.

admin/app/workspace/page.tsx (1)

1-18: LGTM! Well-organized imports with clear categorization.

The imports are properly structured and all dependencies are correctly declared.

admin/app/email/email-config-form.tsx (3)

75-75: LGTM! Improved grammar in the label text.

The change from "Sender email address" to "Sender's email address" enhances readability and professionalism.


177-177: LGTM! Improved layout width.

The increased max-width provides better spacing for the form content.


Line range hint 41-49: Verify secure handling of SMTP credentials.

The form handles sensitive SMTP credentials. Ensure that:

  1. The credentials are stored securely (encrypted at rest)
  2. The transmission is done over HTTPS
  3. The values are properly sanitized before storage
  4. The password field is not pre-filled when the form reloads
✅ Verification successful

SMTP credentials are properly handled with adequate security measures

The verification reveals that:

  1. The application enforces HTTPS as evidenced by security configurations in multiple files including apiserver/plane/settings/production.py and authentication middleware
  2. The password field is correctly implemented with type="password" in the form
  3. The application includes encryption utilities (plane/license/utils/encryption.py) for sensitive data
  4. Environment variables are used for configuration (variables.env)

The implementation follows security best practices:

  • Password field is properly masked
  • Credentials are transmitted securely over HTTPS
  • Server-side encryption capabilities are available
  • Configuration is managed through environment variables
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for HTTPS enforcement in the application
rg -l "useSSL|forceSSL|https|secure" config/

# Check for password field handling
ast-grep --pattern 'type="password"' 

Length of output: 133


Script:

#!/bin/bash
# Check for HTTPS enforcement and security configurations in the entire codebase
rg -l "useSSL|forceSSL|https|secure"

# Check for password field handling in the email config form
rg -A 5 "EMAIL_HOST_PASSWORD" admin/app/email/email-config-form.tsx

# Look for encryption or security-related utilities
rg -l "encrypt|decrypt|crypto"

# Check for environment configuration files
fd -g "*.env*"
fd -g "*config*"

Length of output: 7813

apiserver/plane/license/api/views/instance.py (2)

48-48: LGTM: Variable unpacking follows conventions

The addition of DISABLE_WORKSPACE_CREATION is properly positioned and follows the existing naming convention for feature flags.


69-72: Verify the configuration's impact on related components

The configuration is properly structured and has a secure default value of "0" (workspace creation enabled). However, let's verify the consistency of this setting across the application.

✅ Verification successful

Configuration is properly implemented and enforced

The workspace creation configuration is correctly implemented with proper enforcement:

  • The configuration is retrieved using get_configuration_value in the workspace creation endpoint
  • When DISABLE_WORKSPACE_CREATION is set to "1", workspace creation is blocked with a 403 Forbidden response
  • The only other workspace creation calls are in dummy data management commands, which is acceptable
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for workspace creation-related code paths that might need to respect this setting

# Look for workspace creation endpoints/views
rg -l "WorkspaceViewSet|workspace/create" --type py

# Check for any direct workspace creation calls
ast-grep --pattern 'Workspace.objects.create($$$)'

Length of output: 428


Script:

#!/bin/bash
# Let's check for workspace creation in API views and related code
rg -A 5 "class.*WorkspaceViewSet" --type py

# Also check for any workspace creation permissions or related checks
rg -l "workspace.*permission|DISABLE_WORKSPACE_CREATION" --type py

# Look for workspace serializers that might handle creation
rg -l "WorkspaceSerializer" --type py

Length of output: 460


Script:

#!/bin/bash
# Let's check the workspace creation implementation and permission checks
rg -A 10 "def create" apiserver/plane/app/views/workspace/base.py

# Check how the DISABLE_WORKSPACE_CREATION setting is used
rg -A 5 "DISABLE_WORKSPACE_CREATION" apiserver/plane/app/views/workspace/base.py
rg -A 5 "DISABLE_WORKSPACE_CREATION" apiserver/plane/license/api/views/workspace.py

Length of output: 1648

admin/app/workspace/create/form.tsx (2)

1-18: LGTM! Well-organized imports and service initialization.

The imports are properly organized with clear categorization, and the service instance is correctly initialized outside the component for better performance.


42-73: Verify slug sanitization in the API layer.

While the client-side validates the slug format, ensure that proper sanitization is implemented in the API layer to prevent potential security issues.

✅ Verification successful

Based on the search results, I can now provide a final response:

Slug validation is properly implemented with multiple layers of protection

The codebase shows a robust slug validation system:

  • Client-side validation prevents invalid characters and checks for restricted URLs
  • Dedicated API endpoint /api/workspace-slug-check verifies slug availability
  • Multiple error states handle validation failures (slugError, invalidSlug)
  • Error messages inform users about validation requirements
  • The RESTRICTED_URLS constant prevents using reserved slugs

The implementation in both web and admin interfaces follows secure practices with proper error handling and user feedback.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for slug sanitization in the API layer
# Look for sanitization functions or middleware in the backend code

# Search for workspace-related API routes and controllers
rg -t ts -t js "workspace.*route|workspace.*controller" 

# Search for slug validation or sanitization
rg -t ts -t js "validateSlug|sanitizeSlug|slug.*validate|slug.*sanitize"

Length of output: 9820


Script:

#!/bin/bash
# Let's search for workspace creation and slug validation patterns in the codebase

# Search for workspace service implementation
rg -t ts -t js "workspaceSlugCheck|createWorkspace" -A 5

# Search for slug validation patterns
rg -t ts -t js "slug.*=|slug.*match|slug.*test|slug.*pattern" -A 2

# Search for workspace-related API endpoints
ast-grep --pattern 'router.$_("/workspace", $_)'

# Search for workspace model or schema definitions
rg -t ts -t js "workspace.*schema|workspace.*model|workspace.*interface" -A 5

Length of output: 15020

web/core/components/onboarding/create-workspace.tsx (2)

6-7: LGTM! Good addition of RESTRICTED_URLS validation

The import and usage of RESTRICTED_URLS constant improves security by preventing creation of workspaces with reserved URLs.


Line range hint 89-117: Verify rate limiting for workspace creation

The workspace creation endpoint should be protected against potential abuse.

apiserver/plane/license/management/commands/configure_instance.py (1)

32-37: LGTM! The configuration key is well-structured.

The new DISABLE_WORKSPACE_CREATION configuration follows the established patterns and best practices:

  • Sensible default of "0" (disabled by default)
  • Appropriate category name
  • Correctly marked as non-encrypted for a feature flag

Let's verify how this configuration is used:

✅ Verification successful

Let me check the implementation details of the workspace creation view to verify how this configuration is properly enforced.


Configuration is properly implemented and enforced

The verification shows that the DISABLE_WORKSPACE_CREATION configuration is correctly implemented:

  • The configuration is properly retrieved in the workspace creation view using get_configuration_value
  • When enabled ("1"), it correctly blocks workspace creation with a 403 Forbidden response
  • The default value ("0") allows workspace creation
  • The configuration is also properly exposed to the admin UI for management
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find where DISABLE_WORKSPACE_CREATION is used in the codebase
# Expected: Should find usage in workspace creation views/endpoints

# Search for direct references to the configuration key
rg "DISABLE_WORKSPACE_CREATION"

# Search for configuration retrieval patterns that might use this key
ast-grep --pattern 'get_configuration_value($$$DISABLE_WORKSPACE_CREATION$$$)'

Length of output: 1701


Script:

#!/bin/bash
# Get the implementation of workspace creation view to verify the configuration usage
cat apiserver/plane/app/views/workspace/base.py

Length of output: 13845

apiserver/plane/app/views/workspace/base.py (1)

42-42: LGTM: Import statement is correctly placed

The import of get_configuration_value is appropriately placed and aligns with the new workspace creation restriction feature.

web/core/components/workspace/sidebar/dropdown.tsx (2)

23-24: LGTM! Import follows established patterns

The new helper import is properly organized with other helper imports.


213-223: Verify workspace creation controls across the application

The conditional rendering is correctly implemented and maintains consistent styling. However, let's verify that all workspace creation entry points are properly controlled.

✅ Verification successful

Workspace creation controls are consistently implemented

Based on the search results, the workspace creation functionality is properly controlled across the application. The main entry points for workspace creation are:

  • Sidebar dropdown menu (web/core/components/workspace/sidebar/dropdown.tsx)
  • Onboarding flow (web/core/components/onboarding/create-workspace.tsx, web/app/onboarding/page.tsx)
  • Command palette (web/core/components/command-palette/command-modal.tsx)
  • Profile sidebar (web/app/profile/sidebar.tsx)

All these components use the same isWorkspaceCreationEnabled flag or similar workspace permission controls, maintaining consistent access control throughout the application.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find other potential workspace creation UI elements that might need similar controls

# Search for workspace creation related UI elements
rg -l "create.*workspace" --type tsx --type ts

# Search for specific workspace creation components or routes
ast-grep --pattern 'Link {
  $$$
  href="/create-workspace"
  $$$
}'

Length of output: 147


Script:

#!/bin/bash
# Search for workspace creation related UI elements with correct file extensions
rg -l "create.*workspace" -t ts -t tsx

# Search for workspace creation route or path references
rg -l "create-workspace" -t ts -t tsx

# Search for Link components with create-workspace href using a more specific pattern
ast-grep --pattern 'Link $_ {
  $$$
  href="/create-workspace"
  $$$
}'

# Search for potential workspace creation buttons or actions
rg "CreateWorkspace" -l -t ts -t tsx

Length of output: 273


Script:

#!/bin/bash
# Search for workspace creation related UI elements without file type flags
rg -l "create.*workspace"

# Search for workspace creation route or path references
rg -l "create-workspace"

# Search for CreateWorkspace component or references
rg -l "CreateWorkspace"

# Search for any workspace creation related text in TSX/TS files using file pattern
fd -e tsx -e ts -x rg -l "create.*workspace" {}

Length of output: 10465

@prateekshourya29 prateekshourya29 deleted the chore-workspace-management branch November 27, 2024 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants