refactor: streamline member handling and improve type usage

- Updated the ReplaceMembersRequest import in preload to use a local type definition for consistency.
- Refactored MemberDraftRow and MembersEditorSection components to utilize InlineChip type directly, enhancing type clarity.
- Improved performance by using useMemo for workflow chips in MemberDraftRow, optimizing re-renders.
- Adjusted the JSON text setting in MembersEditorSection to use queueMicrotask for better asynchronous handling.
- Added TEAM_REPLACE_MEMBERS to IPC mock definitions for improved testing coverage.
This commit is contained in:
iliya 2026-03-03 01:12:28 +02:00
parent 59c5ee3836
commit 1100d8fa3d
5 changed files with 13 additions and 22 deletions

View file

@ -174,6 +174,7 @@ import type {
MemberLogSummary, MemberLogSummary,
NotificationTrigger, NotificationTrigger,
RejectResult, RejectResult,
ReplaceMembersRequest,
SendMessageRequest, SendMessageRequest,
SendMessageResult, SendMessageResult,
SessionsByIdsOptions, SessionsByIdsOptions,
@ -742,10 +743,7 @@ const electronAPI: ElectronAPI = {
addMember: async (teamName: string, request: AddMemberRequest) => { addMember: async (teamName: string, request: AddMemberRequest) => {
return invokeIpcWithResult<void>(TEAM_ADD_MEMBER, teamName, request); return invokeIpcWithResult<void>(TEAM_ADD_MEMBER, teamName, request);
}, },
replaceMembers: async ( replaceMembers: async (teamName: string, request: ReplaceMembersRequest) => {
teamName: string,
request: import('@shared/types').ReplaceMembersRequest
) => {
return invokeIpcWithResult<void>(TEAM_REPLACE_MEMBERS, teamName, request); return invokeIpcWithResult<void>(TEAM_REPLACE_MEMBERS, teamName, request);
}, },
removeMember: async (teamName: string, memberName: string) => { removeMember: async (teamName: string, memberName: string) => {

View file

@ -17,7 +17,7 @@ import {
DialogTitle, DialogTitle,
} from '@renderer/components/ui/dialog'; } from '@renderer/components/ui/dialog';
import { getTeamColorSet } from '@renderer/constants/teamColors'; import { getTeamColorSet } from '@renderer/constants/teamColors';
import { CUSTOM_ROLE, NO_ROLE, PRESET_ROLES } from '@renderer/constants/teamRoles'; import { CUSTOM_ROLE, PRESET_ROLES } from '@renderer/constants/teamRoles';
import { useFileListCacheWarmer } from '@renderer/hooks/useFileListCacheWarmer'; import { useFileListCacheWarmer } from '@renderer/hooks/useFileListCacheWarmer';
import { cn } from '@renderer/lib/utils'; import { cn } from '@renderer/lib/utils';
import { Loader2 } from 'lucide-react'; import { Loader2 } from 'lucide-react';

View file

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Button } from '@renderer/components/ui/button'; import { Button } from '@renderer/components/ui/button';
import { Input } from '@renderer/components/ui/input'; import { Input } from '@renderer/components/ui/input';
@ -18,6 +18,7 @@ import { getMemberColor } from '@shared/constants/memberColors';
import { ChevronDown, ChevronRight } from 'lucide-react'; import { ChevronDown, ChevronRight } from 'lucide-react';
import type { MemberDraft } from './membersEditorTypes'; import type { MemberDraft } from './membersEditorTypes';
import type { InlineChip } from '@renderer/types/inlineChip';
import type { MentionSuggestion } from '@renderer/types/mention'; import type { MentionSuggestion } from '@renderer/types/mention';
interface MemberDraftRowProps { interface MemberDraftRowProps {
@ -30,10 +31,7 @@ interface MemberDraftRowProps {
onRemove: (id: string) => void; onRemove: (id: string) => void;
showWorkflow?: boolean; showWorkflow?: boolean;
onWorkflowChange?: (id: string, workflow: string) => void; onWorkflowChange?: (id: string, workflow: string) => void;
onWorkflowChipsChange?: ( onWorkflowChipsChange?: (id: string, chips: InlineChip[]) => void;
id: string,
chips: import('@renderer/types/inlineChip').InlineChip[]
) => void;
draftKeyPrefix?: string; draftKeyPrefix?: string;
projectPath?: string | null; projectPath?: string | null;
mentionSuggestions?: MentionSuggestion[]; mentionSuggestions?: MentionSuggestion[];
@ -68,7 +66,7 @@ export const MemberDraftRow = ({
enabled: !!draftKey, enabled: !!draftKey,
}); });
const chips = member.workflowChips ?? []; const chips = useMemo(() => member.workflowChips ?? [], [member.workflowChips]);
const handleWorkflowChange = useCallback( const handleWorkflowChange = useCallback(
(v: string) => { (v: string) => {
@ -83,7 +81,7 @@ export const MemberDraftRow = ({
); );
const handleFileChipInsert = useCallback( const handleFileChipInsert = useCallback(
(chip: import('@renderer/types/inlineChip').InlineChip) => { (chip: InlineChip) => {
onWorkflowChipsChange?.(member.id, [...chips, chip]); onWorkflowChipsChange?.(member.id, [...chips, chip]);
}, },
[member.id, chips, onWorkflowChipsChange] [member.id, chips, onWorkflowChipsChange]

View file

@ -8,13 +8,10 @@ import { getMemberColor } from '@shared/constants/memberColors';
import { MembersJsonEditor } from '../dialogs/MembersJsonEditor'; import { MembersJsonEditor } from '../dialogs/MembersJsonEditor';
import { MemberDraftRow } from './MemberDraftRow'; import { MemberDraftRow } from './MemberDraftRow';
import { import { createMemberDraft, getWorkflowForExport } from './membersEditorUtils';
buildMembersFromDrafts,
createMemberDraft,
getWorkflowForExport,
} from './membersEditorUtils';
import type { MemberDraft } from './membersEditorTypes'; import type { MemberDraft } from './membersEditorTypes';
import type { InlineChip } from '@renderer/types/inlineChip';
import type { MentionSuggestion } from '@renderer/types/mention'; import type { MentionSuggestion } from '@renderer/types/mention';
function membersToJsonText(drafts: MemberDraft[]): string { function membersToJsonText(drafts: MemberDraft[]): string {
@ -91,7 +88,7 @@ export const MembersEditorSection = ({
useEffect(() => { useEffect(() => {
if (!jsonEditorOpen || jsonError !== null) return; if (!jsonEditorOpen || jsonError !== null) return;
setJsonText(membersToJsonText(members)); queueMicrotask(() => setJsonText(membersToJsonText(members)));
}, [members, jsonEditorOpen, jsonError]); }, [members, jsonEditorOpen, jsonError]);
const handleJsonChange = (text: string): void => { const handleJsonChange = (text: string): void => {
@ -132,10 +129,7 @@ export const MembersEditorSection = ({
onChange(members.map((c) => (c.id === memberId ? { ...c, workflow } : c))); onChange(members.map((c) => (c.id === memberId ? { ...c, workflow } : c)));
}; };
const updateMemberWorkflowChips = ( const updateMemberWorkflowChips = (memberId: string, workflowChips: InlineChip[]): void => {
memberId: string,
workflowChips: import('@renderer/types/inlineChip').InlineChip[]
): void => {
onChange(members.map((c) => (c.id === memberId ? { ...c, workflowChips } : c))); onChange(members.map((c) => (c.id === memberId ? { ...c, workflowChips } : c)));
}; };

View file

@ -39,6 +39,7 @@ vi.mock('@preload/constants/ipcChannels', () => ({
TEAM_GET_ALL_TASKS: 'team:getAllTasks', TEAM_GET_ALL_TASKS: 'team:getAllTasks',
TEAM_ADD_TASK_COMMENT: 'team:addTaskComment', TEAM_ADD_TASK_COMMENT: 'team:addTaskComment',
TEAM_ADD_MEMBER: 'team:addMember', TEAM_ADD_MEMBER: 'team:addMember',
TEAM_REPLACE_MEMBERS: 'team:replaceMembers',
TEAM_REMOVE_MEMBER: 'team:removeMember', TEAM_REMOVE_MEMBER: 'team:removeMember',
TEAM_UPDATE_MEMBER_ROLE: 'team:updateMemberRole', TEAM_UPDATE_MEMBER_ROLE: 'team:updateMemberRole',
TEAM_GET_PROJECT_BRANCH: 'team:getProjectBranch', TEAM_GET_PROJECT_BRANCH: 'team:getProjectBranch',