Files
task-stream/libs/api/tracker/presenters/src/lib/common/settings.ts
Josep Piguillem 869acd3f1f feat: teams within a project
Projects keep teams of members in their settings (settings.teams; people
outside the project are dropped, teams are archived, not removed; absent
when saving means unchanged). Tickets go to a team (`team`, also filtered
in the list and in MCP search_issues), and a comment mentioning
@[Frontend](team-FRONT) tells each of its members. Settings has the teams
with their members, the ticket a «Equipo» select, the list a team filter,
and «@» offers the teams after the people.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:20:35 +02:00

101 lines
2.6 KiB
TypeScript

import {
CustomFieldType,
ProjectSettings,
SettingColor,
StatusCategory,
TypeIcon,
} from '@task-stream/api/tracker/domain';
/** Settings as the APIs carry them: transitions as a list instead of a map. */
export interface SettingsPayload {
statuses: {
id: string;
name: string;
category: StatusCategory;
color: string;
requiresReason: boolean;
archived: boolean;
wipLimit?: number | null;
}[];
transitions: { from: string; to: string[] }[];
issueTypes: {
id: string;
name: string;
icon: string;
color: string;
archived: boolean;
template?: { description?: string | null; checklist?: string[] } | null;
}[];
areas: { id: string; name: string; archived: boolean }[];
/** Absent when saving: unchanged. */
teams?: {
id: string;
name: string;
memberIds: string[];
archived: boolean;
}[];
/** Definition of done. Absent when saving: unchanged. */
checklistBeforeDone?: boolean;
/** Absent when saving: unchanged. */
customFields?: {
id: string;
name: string;
type: string;
options?: string[];
archived: boolean;
}[];
}
export function toSettingsPayload(settings: ProjectSettings): SettingsPayload {
return {
...settings,
customFields: settings.customFields ?? [],
checklistBeforeDone: !!settings.checklistBeforeDone,
teams: settings.teams ?? [],
transitions: settings.statuses.map((s) => ({
from: s.id,
to: settings.transitions[s.id] ?? [],
})),
};
}
/** Colours and icons are checked by the domain (validateProjectSettings). */
export function fromSettingsPayload(payload: SettingsPayload): ProjectSettings {
return {
statuses: payload.statuses.map((s) => ({
...s,
color: s.color as SettingColor,
})),
transitions: Object.fromEntries(
payload.transitions.map((t) => [t.from, t.to]),
),
issueTypes: payload.issueTypes.map(({ template, ...t }) => ({
...t,
icon: t.icon as TypeIcon,
color: t.color as SettingColor,
...(template
? {
template: {
description: template.description ?? null,
checklist: template.checklist ?? [],
},
}
: {}),
})),
areas: payload.areas,
...(payload.teams ? { teams: payload.teams } : {}),
...(payload.checklistBeforeDone != null
? { checklistBeforeDone: payload.checklistBeforeDone }
: {}),
...(payload.customFields
? {
customFields: payload.customFields.map((f) => ({
...f,
type: f.type as CustomFieldType,
options: f.options ?? [],
})),
}
: {}),
};
}