improvement: enhance workspace invitation modularity#6594
improvement: enhance workspace invitation modularity#6594sriramveeraghanta merged 1 commit intopreviewfrom
Conversation
WalkthroughThis pull request integrates updates in the workspace settings and invitation flow. It adds a new Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant WM as Workspace Members Page
participant IM as Invite Modal
participant UH as UseWorkspaceInvitationActions
participant BE as Backend
U->>WM: Click "Invite"
WM->>IM: Open Invitation Modal
IM->>UH: Initialize form state
U->>IM: Enter invitation details
U->>IM: Submit form
IM->>UH: Process submission
UH->>BE: Validate and process invitations
BE-->>UH: Return response
UH-->>IM: Update state
IM-->>U: Display success/error message
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
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: 2
🔭 Outside diff range comments (1)
web/app/[workspaceSlug]/(projects)/settings/members/page.tsx (1)
49-91: 🛠️ Refactor suggestionImprove error handling in workspace invitation.
The error handling in
handleWorkspaceInvitecould be more robust with better error types and user feedback.const handleWorkspaceInvite = (data: IWorkspaceBulkInviteFormData) => { - if (!workspaceSlug) return; + if (!workspaceSlug) { + setToast({ + type: TOAST_TYPE.ERROR, + title: "Error!", + message: t("workspace_settings.settings.members.invalid_workspace"), + }); + return; + } return inviteMembersToWorkspace(workspaceSlug.toString(), data) .then(() => { setInviteModal(false); captureEvent(MEMBER_INVITED, { emails: [ ...data.emails.map((email) => ({ email: email.email, role: getUserRole(email.role as unknown as EUserPermissions), })), ], project_id: undefined, state: "SUCCESS", element: "Workspace settings member page", }); setToast({ type: TOAST_TYPE.SUCCESS, title: "Success!", message: t("workspace_settings.settings.members.invitations_sent_successfully"), }); }) .catch((err) => { + const errorMessage = err.error ?? t("something_went_wrong_please_try_again"); + console.error("Workspace invitation failed:", errorMessage); captureEvent(MEMBER_INVITED, { emails: [ ...data.emails.map((email) => ({ email: email.email, role: getUserRole(email.role as unknown as EUserPermissions), })), ], project_id: undefined, state: "FAILED", element: "Workspace settings member page", }); setToast({ type: TOAST_TYPE.ERROR, title: "Error!", - message: `${err.error ?? t("something_went_wrong_please_try_again")}`, + message: errorMessage, }); throw err; }); };
🧹 Nitpick comments (6)
web/core/components/workspace/invite-modal/form.tsx (1)
6-13: Consider adding prop types validation.The component's props are well-typed, but consider adding runtime validation for better error handling.
Consider using a validation library like
zodorprop-types:import { z } from 'zod'; const invitationFormSchema = z.object({ title: z.string(), description: z.any(), children: z.any(), onSubmit: z.function(), actions: z.any(), className: z.string().optional(), });web/ce/components/workspace/members/invite-modal.tsx (1)
23-34: Consider adding error boundary and loading state.The component could benefit from error handling and loading state management.
Consider wrapping the component with an error boundary and adding loading state:
+import { ErrorBoundary } from '@/components/error-boundary'; + export const SendWorkspaceInvitationModal: React.FC<TSendWorkspaceInvitationModalProps> = observer((props) => { const { isOpen, onClose, onSubmit } = props; + const [isLoading, setIsLoading] = React.useState(false); // store hooks const { t } = useTranslation(); // router const { workspaceSlug } = useParams(); // derived values const { control, fields, formState, remove, onFormSubmit, handleClose, appendField } = useWorkspaceInvitationActions({ onSubmit, onClose, }); return ( + <ErrorBoundary> <ModalCore isOpen={isOpen} position={EModalPosition.TOP} width={EModalWidth.XXL}>web/core/components/workspace/invite-modal/actions.tsx (1)
38-51: Enhance accessibility of the "Add More" button.The button could benefit from improved accessibility attributes and consistent styling with other buttons.
<button type="button" + aria-label={addMoreButtonText || t("common.add_more")} className={cn( - "flex items-center gap-1 bg-transparent py-2 pr-3 text-xs font-medium text-custom-primary outline-custom-primary", + "flex items-center gap-1 bg-transparent py-2 px-3 text-xs font-medium text-custom-primary outline-none focus:ring-2 focus:ring-custom-primary/20", { "cursor-not-allowed opacity-60": isInviteDisabled, } )} onClick={appendField} disabled={isInviteDisabled} > <Plus className="h-3.5 w-3.5" /> {addMoreButtonText || t("common.add_more")} </button>web/core/hooks/use-workspace-invitation.tsx (1)
70-72: Add cleanup to useEffect.The effect should clean up any pending operations when the component unmounts.
useEffect(() => { if (fields.length === 0) append([{ email: "", role: EUserPermissions.MEMBER }]); + return () => { + // Clean up any pending operations + reset(SEND_WORKSPACE_INVITATION_MODAL_DEFAULT_VALUES); + }; }, [fields, append]);web/core/components/workspace/invite-modal/fields.tsx (1)
90-98: Optimize role options rendering.The role options mapping could be memoized to prevent unnecessary re-renders.
+const getRoleOptions = (currentWorkspaceRole: number) => + Object.entries(ROLE).filter(([key]) => currentWorkspaceRole && currentWorkspaceRole >= parseInt(key)) + .map(([key, value]) => ( + <CustomSelect.Option key={key} value={parseInt(key)}> + {value} + </CustomSelect.Option> + )); -{Object.entries(ROLE).map(([key, value]) => { - if (currentWorkspaceRole && currentWorkspaceRole >= parseInt(key)) - return ( - <CustomSelect.Option key={key} value={parseInt(key)}> - {value} - </CustomSelect.Option> - ); -})} +{getRoleOptions(currentWorkspaceRole ?? 0)}web/app/[workspaceSlug]/(projects)/settings/members/page.tsx (1)
121-130: Enhance search input accessibility.The search input could benefit from improved accessibility attributes and better ARIA support.
<div className="ml-auto flex items-center gap-1.5 rounded-md border border-custom-border-200 bg-custom-background-100 px-2.5 py-1.5"> - <Search className="h-3.5 w-3.5 text-custom-text-400" /> + <Search className="h-3.5 w-3.5 text-custom-text-400" aria-hidden="true" /> <input + role="searchbox" + aria-label={`${t("search")}...`} className="w-full max-w-[234px] border-none bg-transparent text-sm outline-none placeholder:text-custom-text-400" placeholder={`${t("search")}...`} value={searchQuery} autoFocus onChange={(e) => setSearchQuery(e.target.value)} /> </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
web/app/[workspaceSlug]/(projects)/settings/members/page.tsx(5 hunks)web/ce/components/workspace/billing/billing-actions-button.tsx(1 hunks)web/ce/components/workspace/billing/index.ts(1 hunks)web/ce/components/workspace/index.ts(1 hunks)web/ce/components/workspace/members/index.ts(1 hunks)web/ce/components/workspace/members/invite-modal.tsx(1 hunks)web/core/components/workspace/index.ts(1 hunks)web/core/components/workspace/invite-modal/actions.tsx(1 hunks)web/core/components/workspace/invite-modal/fields.tsx(1 hunks)web/core/components/workspace/invite-modal/form.tsx(1 hunks)web/core/components/workspace/invite-modal/index.ts(1 hunks)web/core/components/workspace/send-workspace-invitation-modal.tsx(0 hunks)web/core/hooks/use-workspace-invitation.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- web/core/components/workspace/send-workspace-invitation-modal.tsx
✅ Files skipped from review due to trivial changes (4)
- web/ce/components/workspace/members/index.ts
- web/ce/components/workspace/index.ts
- web/core/components/workspace/invite-modal/index.ts
- web/ce/components/workspace/billing/index.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Analyze (javascript)
- GitHub Check: Analyze (python)
🔇 Additional comments (4)
web/core/components/workspace/index.ts (1)
8-8: LGTM! Export change aligns with modular design.The change from
send-workspace-invitation-modaltoinvite-modalreflects the refactoring of the invitation system into a more modular structure.web/core/components/workspace/invite-modal/form.tsx (1)
15-36: LGTM! Well-structured form component.The component follows React best practices:
- Uses MobX observer pattern correctly
- Prevents Enter key submission for better UX
- Properly structured layout with title and description
- Well-organized props destructuring
web/ce/components/workspace/members/invite-modal.tsx (2)
17-21: LGTM! Well-defined props interface.The props interface is comprehensive and properly typed with the correct Promise return type for the onSubmit handler.
35-60: LGTM! Well-structured modal component.The component follows best practices:
- Uses MobX observer pattern correctly
- Proper integration with i18n
- Good separation of concerns with custom hook
- Clean component composition
Description
Type of Change
Summary by CodeRabbit