feat(base): add conversion-warning lookup with unit tests

This commit is contained in:
Philipinho
2026-05-24 02:29:52 +01:00
parent e1f862967a
commit c2dac69e70
2 changed files with 169 additions and 0 deletions
@@ -0,0 +1,104 @@
import {
conversionWarning,
NON_USER_TARGET_TYPES,
} from "../conversion-warning";
describe("conversionWarning", () => {
it("returns the choice-name copy for select → text", () => {
expect(conversionWarning("select", "text")).toBe(
"Cells will be replaced with the option name.",
);
});
it("returns the same copy for status → text", () => {
expect(conversionWarning("status", "text")).toBe(
"Cells will be replaced with the option name.",
);
});
it("returns comma-list copy for multiSelect → text", () => {
expect(conversionWarning("multiSelect", "text")).toBe(
"Cells will be replaced with a comma-separated list of option names.",
);
});
it("returns person-name copy for person → text", () => {
expect(conversionWarning("person", "text")).toBe(
"Cells will be replaced with the person's name.",
);
});
it("returns file-name list copy for file → text", () => {
expect(conversionWarning("file", "text")).toBe(
"Cells will be replaced with a comma-separated list of file names.",
);
});
it("returns page-title copy for page → text", () => {
expect(conversionWarning("page", "text")).toBe(
"Cells will be replaced with the page title.",
);
});
it("returns first-item-kept copy for multiSelect → select", () => {
expect(conversionWarning("multiSelect", "select")).toBe(
"Only the first selected item per row will be kept; the rest will be discarded.",
);
});
it("returns single-item-list copy for select → multiSelect", () => {
expect(conversionWarning("select", "multiSelect")).toBe(
"Existing values become single-item lists. No data is lost.",
);
});
it("returns page-cleared copy when target is page from non-page", () => {
expect(conversionWarning("text", "page")).toBe(
"Cells that aren't already a page reference will be cleared.",
);
expect(conversionWarning("number", "page")).toBe(
"Cells that aren't already a page reference will be cleared.",
);
});
it("returns number-parse-cleared copy when target is number from non-numeric", () => {
expect(conversionWarning("select", "number")).toBe(
"Cells that can't be parsed as a number will be cleared.",
);
});
it("returns date-parse-cleared copy when target is date", () => {
expect(conversionWarning("text", "date")).toBe(
"Cells that can't be parsed as a date will be cleared.",
);
});
it("returns checkbox-coercion copy when target is checkbox", () => {
expect(conversionWarning("text", "checkbox")).toBe(
"Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).",
);
});
it("returns the default safe copy for text → url", () => {
expect(conversionWarning("text", "url")).toBe(
"Cells will be reinterpreted under the new type.",
);
});
it("returns the default safe copy for number → text", () => {
expect(conversionWarning("number", "text")).toBe(
"Cells will be reinterpreted under the new type.",
);
});
describe("NON_USER_TARGET_TYPES", () => {
it("contains exactly the 4 non-user types", () => {
expect(Array.from(NON_USER_TARGET_TYPES).sort()).toEqual([
"createdAt",
"formula",
"lastEditedAt",
"lastEditedBy",
]);
});
});
});
@@ -0,0 +1,65 @@
import type { BasePropertyType } from "@/features/base/types/base.types";
export const NON_USER_TARGET_TYPES = new Set<BasePropertyType>([
"createdAt",
"lastEditedAt",
"lastEditedBy",
"formula",
]);
/*
* Returns the warning copy shown in the property-menu's
* `confirmTypeChange` panel before the user applies a type change.
* Strings are i18n source keys (translation files key them by their
* exact text). Buckets are ordered most-specific first; the default
* branch covers safe reinterpretations like text ↔ number, text → url,
* text → email.
*/
export function conversionWarning(
from: BasePropertyType,
to: BasePropertyType,
): string {
if (to === "text") {
if (from === "select" || from === "status") {
return "Cells will be replaced with the option name.";
}
if (from === "multiSelect") {
return "Cells will be replaced with a comma-separated list of option names.";
}
if (from === "person") {
return "Cells will be replaced with the person's name.";
}
if (from === "file") {
return "Cells will be replaced with a comma-separated list of file names.";
}
if (from === "page") {
return "Cells will be replaced with the page title.";
}
}
if (to === "select" && from === "multiSelect") {
return "Only the first selected item per row will be kept; the rest will be discarded.";
}
if (to === "multiSelect" && from === "select") {
return "Existing values become single-item lists. No data is lost.";
}
if (to === "page") {
return "Cells that aren't already a page reference will be cleared.";
}
if (to === "number" && from !== "number") {
return "Cells that can't be parsed as a number will be cleared.";
}
if (to === "date" && from !== "date") {
return "Cells that can't be parsed as a date will be cleared.";
}
if (to === "checkbox" && from !== "checkbox") {
return "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).";
}
return "Cells will be reinterpreted under the new type.";
}