Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions apps/web/src/components/LabelForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ import { Fragment, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { HiChevronUpDown, HiXMark } from "react-icons/hi2";

import type { Colour } from "@kan/shared/constants";
import { colours } from "@kan/shared/constants";

import Button from "~/components/Button";
import Input from "~/components/Input";
import Toggle from "~/components/Toggle";
import { useModal } from "~/providers/modal";
import { api } from "~/utils/api";
import { resolveLabelColour } from "~/utils/labelColours";

interface LabelFormInput {
name: string;
colour: Colour;
isCreateAnotherEnabled?: boolean;
}

interface Colour {
name: string;
code: string;
}

export function LabelForm({
boardPublicId,
refetch,
Expand All @@ -47,9 +44,7 @@ export function LabelForm({
useForm<LabelFormInput>({
values: {
name: isEdit && label.data?.name ? label.data.name : "",
colour: (isEdit && label.data?.colourCode
? colours.find((c) => c.code === label.data?.colourCode)
: colours[0]) as Colour,
colour: resolveLabelColour(isEdit ? label.data?.colourCode : undefined),
isCreateAnotherEnabled: false,
},
});
Expand Down
23 changes: 23 additions & 0 deletions apps/web/src/utils/labelColours.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";

import { colours } from "@kan/shared/constants";

import { resolveLabelColour } from "./labelColours";

describe("resolveLabelColour", () => {
it("returns the matching palette colour", () => {
expect(resolveLabelColour(colours[1]?.code)).toEqual(colours[1]);
});

it("preserves a custom colour", () => {
expect(resolveLabelColour("#4bce97")).toEqual({
name: "#4bce97",
code: "#4bce97",
});
});

it("uses the default colour when no colour is stored", () => {
expect(resolveLabelColour(null)).toEqual(colours[0]);
expect(resolveLabelColour(undefined)).toEqual(colours[0]);
});
});
18 changes: 18 additions & 0 deletions apps/web/src/utils/labelColours.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Colour } from "@kan/shared/constants";
import { colours } from "@kan/shared/constants";

export const resolveLabelColour = (
colourCode: string | null | undefined,
): Colour => {
const defaultColour = colours[0];

if (!defaultColour) throw new Error("Label colour palette is empty");
if (!colourCode) return defaultColour;

return (
colours.find((colour) => colour.code === colourCode) ?? {
name: colourCode,
code: colourCode,
}
);
};
29 changes: 27 additions & 2 deletions packages/e2e/tests/self-hosted/card-labels.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { CardPage } from "../support/pages/card-page";
import { DashboardPage } from "../support/pages/dashboard-page";
import { SelfHostedOnboardingPage } from "../support/pages/self-hosted-onboarding-page";
import { createTestUser } from "../support/test-user";
import { waitForTrpcMutation } from "../support/wait-for-trpc";

test(
"a label can be created and assigned to a card, and the assignment persists",
"a label can be created, assigned, and edited with a custom colour",
{ tag: "@self-hosted" },
async ({ page }) => {
const user = createTestUser();
Expand All @@ -27,11 +28,35 @@ test(
await board.createCard("Label test card");
await board.openCard("Label test card");

await card.createAndAssignLabel("Urgent");
const labelPublicId = await card.createAndAssignLabel("Urgent");

await expect(card.assignedLabelBadge("Urgent")).toBeVisible();

await page.reload();
await expect(card.assignedLabelBadge("Urgent")).toBeVisible();

const response = await page.request.post("/api/trpc/label.update?batch=1", {
data: {
"0": {
json: {
labelPublicId,
name: "Urgent",
colourCode: "#4bce97",
},
},
},
});
expect(response.ok()).toBe(true);

await page.reload();
await card.openLabelEditor("Urgent");

const dialog = page.getByRole("dialog");
await expect(dialog.getByRole("button", { name: "#4bce97" })).toBeVisible();

const updated = waitForTrpcMutation(page, "label.update");
await dialog.getByRole("button", { name: "Update label" }).click();
const updatedResponse = await updated;
expect(updatedResponse.ok()).toBe(true);
},
);
20 changes: 19 additions & 1 deletion packages/e2e/tests/support/pages/card-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,26 @@ export class CardPage {
const created = waitForTrpcMutation(this.page, "label.create");
const assigned = waitForTrpcMutation(this.page, "card.addOrRemoveLabel");
await dialog.getByRole("button", { name: "Create label" }).click();
await created;
const createdResponse = await created;
await assigned;

const body = (await createdResponse.json()) as [
{ result: { data: { json: { publicId: string } } } },
];

return body[0].result.data.json.publicId;
}

async openLabelEditor(name: string) {
await this.labelSelectorTrigger().click();

const checkbox = this.page
.getByRole("checkbox", { name })
.filter({ visible: true });
const row = checkbox.locator("..");

await row.hover();
await row.getByRole("button").click();
}

async uploadAttachment(filePath: string) {
Expand Down
Loading