feat(PROJ-9): implement labels frontend - LabelList, LabelPicker, search integration, admin UI

This commit is contained in:
sysops
2026-03-18 09:51:10 +01:00
parent 2e9f1f0471
commit cee75094ad
7 changed files with 923 additions and 1 deletions
+95
View File
@@ -175,6 +175,7 @@ export async function searchEmails(params: {
date_to?: string;
sort?: string;
has_attachment?: boolean;
label_id?: number;
page?: number;
page_size?: number;
}): Promise<SearchResponse> {
@@ -186,6 +187,7 @@ export async function searchEmails(params: {
if (params.date_to) sp.set("date_to", params.date_to);
if (params.sort) sp.set("sort", params.sort);
if (params.has_attachment !== undefined) sp.set("has_attachment", String(params.has_attachment));
if (params.label_id !== undefined) sp.set("label_id", String(params.label_id));
if (params.page) sp.set("page", String(params.page));
if (params.page_size) sp.set("page_size", String(params.page_size));
return request<SearchResponse>(`/api/search?${sp.toString()}`);
@@ -840,3 +842,96 @@ export async function disableTOTP(code: string): Promise<{ ok: boolean }> {
body: JSON.stringify({ code }),
});
}
// ── Labels ──────────────────────────────────────────────────────────────────
export interface MailLabel {
id: number;
name: string;
color: string;
owner_id?: number;
tenant_id: number;
is_global: boolean;
created_at: string;
}
export interface LabelRule {
id: number;
condition_field: "from_domain" | "source" | "subject_contains";
condition_value: string;
label_id: number;
tenant_id: number;
}
export async function getLabels(): Promise<MailLabel[]> {
return request<MailLabel[]>("/api/labels");
}
export async function createLabel(name: string, color: string): Promise<MailLabel> {
return request<MailLabel>("/api/labels", {
method: "POST",
body: JSON.stringify({ name, color }),
});
}
export async function updateLabel(id: number, name: string, color: string): Promise<void> {
return request<void>(`/api/labels/${id}`, {
method: "PATCH",
body: JSON.stringify({ name, color }),
});
}
export async function deleteLabel(id: number): Promise<void> {
return request<void>(`/api/labels/${id}`, { method: "DELETE" });
}
export async function assignLabel(emailId: string, labelId: number): Promise<void> {
return request<void>(`/api/mails/${emailId}/labels`, {
method: "POST",
body: JSON.stringify({ label_id: labelId }),
});
}
export async function removeLabelFromEmail(emailId: string, labelId: number): Promise<void> {
return request<void>(`/api/mails/${emailId}/labels/${labelId}`, {
method: "DELETE",
});
}
export async function getMailLabelIds(emailId: string): Promise<number[]> {
return request<number[]>(`/api/mails/${emailId}/labels`);
}
export async function createAdminLabel(name: string, color: string): Promise<MailLabel> {
return request<MailLabel>("/api/admin/labels", {
method: "POST",
body: JSON.stringify({ name, color }),
});
}
export async function getAdminLabels(): Promise<MailLabel[]> {
return request<MailLabel[]>("/api/admin/labels");
}
export async function deleteAdminLabel(id: number): Promise<void> {
return request<void>(`/api/admin/labels/${id}`, { method: "DELETE" });
}
export async function getLabelRules(): Promise<LabelRule[]> {
return request<LabelRule[]>("/api/admin/label-rules");
}
export async function createLabelRule(
condition_field: string,
condition_value: string,
label_id: number
): Promise<LabelRule> {
return request<LabelRule>("/api/admin/label-rules", {
method: "POST",
body: JSON.stringify({ condition_field, condition_value, label_id }),
});
}
export async function deleteLabelRule(id: number): Promise<void> {
return request<void>(`/api/admin/label-rules/${id}`, { method: "DELETE" });
}