- Added a new handler for replacing team members, allowing bulk updates to team member roles and workflows. - Enhanced the FileSearchService to include caching for file listings, improving performance by reducing redundant file system scans. - Updated editor and team-related services to support the new member replacement feature, ensuring proper validation and error handling. - Improved UI components to accommodate workflow input for team members, enhancing user experience during team management.
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
import { CUSTOM_ROLE, NO_ROLE } from '@renderer/constants/teamRoles';
|
|
import { serializeChipsWithText } from '@renderer/types/inlineChip';
|
|
|
|
import type { MemberDraft } from './membersEditorTypes';
|
|
import type { TeamProvisioningMemberInput } from '@shared/types';
|
|
|
|
function isValidMemberName(name: string): boolean {
|
|
if (name.length < 1 || name.length > 128) return false;
|
|
if (!/^[a-zA-Z0-9]/.test(name)) return false;
|
|
return /^[a-zA-Z0-9._-]+$/.test(name);
|
|
}
|
|
|
|
export function validateMemberNameInline(name: string): string | null {
|
|
const trimmed = name.trim();
|
|
if (!trimmed) return null;
|
|
if (!isValidMemberName(trimmed)) {
|
|
return 'Start with alphanumeric, use only [a-zA-Z0-9._-], max 128 chars';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function newDraftId(): string {
|
|
// eslint-disable-next-line sonarjs/pseudo-random -- Used for generating unique UI keys, not security
|
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
}
|
|
|
|
export function createMemberDraft(initial?: Partial<MemberDraft>): MemberDraft {
|
|
return {
|
|
id: initial?.id ?? newDraftId(),
|
|
name: initial?.name ?? '',
|
|
roleSelection: initial?.roleSelection ?? '',
|
|
customRole: initial?.customRole ?? '',
|
|
workflow: initial?.workflow,
|
|
};
|
|
}
|
|
|
|
/** Resolves workflow for export (JSON or API): serializes chips when present. */
|
|
export function getWorkflowForExport(member: MemberDraft): string | undefined {
|
|
const workflowRaw = member.workflow?.trim();
|
|
if (!workflowRaw) return undefined;
|
|
const chips = member.workflowChips ?? [];
|
|
return chips.length > 0 ? serializeChipsWithText(workflowRaw, chips) : workflowRaw;
|
|
}
|
|
|
|
export function buildMembersFromDrafts(members: MemberDraft[]): TeamProvisioningMemberInput[] {
|
|
return members
|
|
.map((member) => {
|
|
const name = member.name.trim();
|
|
if (!name) {
|
|
return null;
|
|
}
|
|
|
|
const role =
|
|
member.roleSelection === CUSTOM_ROLE
|
|
? member.customRole.trim() || undefined
|
|
: member.roleSelection === NO_ROLE
|
|
? undefined
|
|
: member.roleSelection.trim() || undefined;
|
|
|
|
const result: TeamProvisioningMemberInput = { name, role };
|
|
const workflow = getWorkflowForExport(member);
|
|
if (workflow) result.workflow = workflow;
|
|
return result;
|
|
})
|
|
.filter((member): member is NonNullable<typeof member> => member !== null);
|
|
}
|