feat: workspace management from admin app#6093
Conversation
WalkthroughThis 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
Possibly related PRs
Suggested labels
Suggested reviewers
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 createdlast_active_at: To track user activityis_active: To know if the user account is activeclass 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 environmentThe 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 analyticsTo 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 suggestionThe 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 experienceThe 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 statesAs this is a critical admin functionality for workspace management, consider these architectural improvements:
- Wrap the component with an error boundary to gracefully handle runtime errors
- Add loading states during workspace creation
- 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 orderThe order of store resets in
resetOnSignOutdiffers 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 exportsWhile 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:
- Add proper error typing and handling
- Type the cursor parameter
- 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 accessibilityThe 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:
- Why these endpoints belong in the license module
- How they relate to other workspace management features
- 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_disabledproperty 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 specificWhile the added cases support the new workspace management functionality, there are a few concerns:
- The "create" case is very generic and might conflict with other create routes in the future. Consider making it more specific, like "workspace-create".
- 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 routesThe 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 textThe 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
ExternalLinkimport to the UI imports section since it's a UI component- Add JSDoc documentation for the
TWorkspaceListItemPropstype to describe its purpose and usageimport { 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 linkWhile 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 stateThe 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 configurableThe 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 textThe 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 featuresadmin/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 documentationThe response field
is_workspace_creation_disabledis 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 workspacesWhen deploying this feature, consider:
- Communication strategy for informing users about the new restriction
- Handling of existing workspace creation requests in the pipeline
- 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:
- Combining related state variables
- 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:
- react-hook-form already manages form state
- 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 messagesThe 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 feedbackThe error messages could be more specific to help users better understand and resolve issues. Consider:
- Including the workspace name in success messages
- 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 improvementsThe 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 togetherThe 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 configurableThe 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
- The setTimeout for loading state is unnecessary and could lead to race conditions.
- 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 validationConsider 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 functionThe 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 rolesThe 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 constantsThe 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 logicThe 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 internationalizationThe 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 experienceThe 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 valueThe 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:
- Use Django's caching framework to cache the configuration value
- Implement a configuration refresh mechanism
- 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 expressionThe 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 whitespaceThere 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 initializationThere is an extra whitespace character (a tab) between
WorkspaceSerializerand(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 usingCountaggregateThe current approach to annotate
project_countis unnecessarily complex. You can simplify it by using theCountaggregate function directly, which improves readability and performance.Suggested changes:
Import the
Countfunction:from django.db.models import CountModify the
workspacesqueryset 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_namefor projects in theWorkspacemodel is set to'project'or adjust accordingly.
47-54: Simplify member count annotation usingCountaggregateSimilar to the project count, you can simplify the
member_countannotation by using theCountfunction directly.Suggested changes:
Modify the
workspacesqueryset 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_namefor workspace members in theWorkspacemodel is set to'workspacemember'or adjust accordingly.Import
Qfor the filter:from django.db.models import Qadmin/core/store/workspace.store.ts (5)
109-109: Simplify the conditional check for paginationYou 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 unusedstoreparameter from constructorThe
storeparameter 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 logsLogging 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 duplicationThe methods
fetchWorkspacesandfetchNextWorkspacesshare 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 ofsetfromlodashSince
this.workspacesis a flat object with workspace IDs as keys, you can assign directly instead of usingset, 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
⛔ Files ignored due to path filters (1)
web/public/workspace/workspace-creation-disabled.pngis 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
TInstanceWorkspaceConfigurationKeystype with "DISABLE_WORKSPACE_CREATION" value - The type is properly imported and used in
base.d.tsas part of theTInstanceConfigurationKeysunion 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
InstanceWorkSpaceAvailabilityCheckEndpointfor 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.pyserializers to represent workspace owners - Properly integrated in workspace member management through
WorkspaceMemberInviteand 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 asisWorkspaceCreationDisabledweb/core/components/onboarding/create-or-join-workspaces.tsx: Used with logical negation asisWorkspaceCreationEnabledweb/core/components/workspace/sidebar/dropdown.tsx: Used with logical negation asisWorkspaceCreationEnabled
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_projectsis computed using a subquery inlicense/api/views/workspace.pythat counts related projects usingProject.objects.filter(workspace_id=OuterRef("id"))total_membersis annotated usingmember_countin multiple views includingapp/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:
- Add input validation
- Implement rate limiting protection
- 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:
- These endpoints are properly protected with admin-only authentication middleware
- 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:
- Both views have
permission_classes = [InstanceAdminPermission]ensuring admin-only access - HTTP methods are appropriately defined:
InstanceWorkSpaceAvailabilityCheckEndpointimplements GET for slug checkingInstanceWorkSpaceEndpointimplements 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)
- Workspace store (
🏁 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.tswith 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:
- The credentials are stored securely (encrypted at rest)
- The transmission is done over HTTPS
- The values are properly sanitized before storage
- 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:
- The application enforces HTTPS as evidenced by security configurations in multiple files including
apiserver/plane/settings/production.pyand authentication middleware - The password field is correctly implemented with
type="password"in the form - The application includes encryption utilities (
plane/license/utils/encryption.py) for sensitive data - 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_valuein the workspace creation endpoint - When
DISABLE_WORKSPACE_CREATIONis 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-checkverifies slug availability - Multiple error states handle validation failures (
slugError,invalidSlug) - Error messages inform users about validation requirements
- The
RESTRICTED_URLSconstant 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
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
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes
Chores