import { Badge, Tooltip } from "frappe-ui"; import { h } from "vue"; import { dayjsLocal } from "./timezone"; import { __ } from "./translation"; import { isSlaMissed, serverInstant, shortDuration } from "./utils"; /** Tallest bars faded per level: High is fully solid, Low nearly empty. */ const FADED_BARS: Record = { High: 0, Medium: 1, Low: 2 }; // Shortest first; fading counts from the tallest. const BARS = [ { x: 0, y: 8, height: 4 }, { x: 4, y: 4, height: 8 }, { x: 8, y: 0, height: 12 }, ]; export function PriorityIcon({ level }: { level: string }) { return level === "Urgent" ? urgentIcon() : levelBars(level); } PriorityIcon.props = ["level"]; // No SLA: nothing promised. export function responseBadge(row: any, due?: string) { if (!row.sla) return null; return slaBadge(row.first_responded_on, due, "amber"); } export function resolutionBadge(row: any, due: string | undefined, paused: boolean) { if (!row.sla) return null; if (paused) return badge(__("Paused"), "blue"); return slaBadge(row.resolution_date, due, "violet"); } function urgentIcon() { const glyph = "fill-surface-gray-1"; // Fills its slot, so callers set the size. return h("svg", { class: "size-full", viewBox: "0 0 14 14", fill: "none" }, [ h("rect", { width: 14, height: 14, rx: 4, class: "fill-ink-gray-6" }), h("rect", { x: 6.25, y: 3, width: 1.5, height: 4.75, rx: 0.75, class: glyph }), h("circle", { cx: 7, cy: 10, r: 0.9, class: glyph }), ]); } function levelBars(level: string) { const faded = FADED_BARS[level] ?? 0; const bars = BARS.map(({ x, y, height }, index) => h("rect", { x, y, width: 2.5, height, rx: 0.5, class: BARS.length - 1 - index < faded ? "fill-ink-gray-3" : "fill-ink-gray-6", }) ); return h("svg", { class: "h-3 w-3", viewBox: "0 0 10 12", fill: "none" }, bars); } function slaBadge(metOn: string | undefined, due: string | undefined, countdownTheme: string) { // No due date: any met time counts as fulfilled. if (metOn) return outcomeBadge(!isSlaMissed(metOn, due)); if (!due) return null; if (serverInstant(due).isBefore()) return outcomeBadge(false); return h(Tooltip, { text: dayjsLocal(due).format("LLLL") }, () => badge(shortDuration(due), countdownTheme) ); } function outcomeBadge(fulfilled: boolean) { return fulfilled ? badge(__("Fulfilled"), "gray") : badge(__("Failed"), "red"); } function badge(label: string, theme: string) { return h(Badge, { label, theme, variant: "subtle" }); }