1
13
14import type { ViewType } from "@factory/shared/dto";
15
16import { groupRecords, type GroupMeta } from "../query/group.js";
17import { propertiesMap } from "../filter/index.js";
18import type { RecordRow, PropertyInfo } from "../values/types.js";
19import * as buttons from "./buttons.js";
20
21export * from "./buttons.js";
22
23export interface ViewDefaultsInput {
24 properties: PropertyInfo[];
25}
26
27
28export function defaultViewConfig(
29 type: ViewType,
30 input: ViewDefaultsInput,
31): Record<string, unknown> {
32 const props = input.properties;
33 const visiblePropertyIds = props.map((p) => p.id);
34 const firstOf = (...types: string[]) => props.find((p) => types.includes(p.type))?.id;
35 const base: Record<string, unknown> = {
36 visiblePropertyIds,
37 color: "default",
38 density: "default",
39 pageSize: 50,
40 };
41 switch (type) {
42 case "table":
43 return { ...base, density: "default", pageSize: 100 };
44 case "list":
45 return { ...base, cardLayout: { properties: [] } };
46 case "board": {
47 const group = firstOf("status", "select");
48 return {
49 ...base,
50 group: group ? [{ propertyId: group, direction: "asc" }] : [],
51 cardLayout: { showCover: true, properties: [], showAvatar: true },
52 };
53 }
54 case "gallery":
55 return { ...base, cardLayout: { cover: true, size: "M", properties: [] } };
56 case "calendar": {
57 const group = firstOf("date", "date_range");
58 return { ...base, group: group ? [{ propertyId: group, direction: "asc" }] : [] };
59 }
60 case "timeline": {
61 const group = firstOf("date", "date_range");
62 return { ...base, group: group ? [{ propertyId: group, direction: "asc" }] : [] };
63 }
64 case "chart":
65 return { ...base, chartId: null };
66 case "dashboard":
67 return { ...base, dashboardId: null };
68 case "form":
69
70 return { ...base };
71 }
72}
73
74
80export interface ViewData {
81 type: ViewType;
82 table?: { rows: RecordRow[] };
83 list?: { rows: RecordRow[] };
84 board?: { groups: GroupMeta[] };
85 gallery?: { items: RecordRow[] };
86 calendar?: { events: Array<{ record: RecordRow; date: string }> };
87 timeline?: { events: Array<{ record: RecordRow; date: string }> };
88 chart?: { chartId: string | null };
89 dashboard?: { dashboardId: string | null };
90 form?: { disabled: boolean; reason: string };
91}
92
93export function viewData(
94 type: ViewType,
95 records: RecordRow[],
96 config: Record<string, unknown>,
97 properties: PropertyInfo[],
98): ViewData {
99 const props = propertiesMap(properties);
100 const groupSpecs: Array<{ propertyId: string; direction: "asc" | "desc" }> = Array.isArray(
101 config["group"],
102 )
103 ? (config["group"] as Array<Record<string, unknown>>).flatMap((g) =>
104 typeof g?.["propertyId"] === "string"
105 ? [
106 {
107 propertyId: g["propertyId"] as string,
108 direction: g["direction"] === "desc" ? "desc" : "asc",
109 },
110 ]
111 : [],
112 )
113 : [];
114 const dateOf = (r: RecordRow): string | null => {
115 for (const g of groupSpecs) {
116 const p = props.get(g.propertyId);
117 if (!p) continue;
118 const v = r.values[g.propertyId];
119 if (p.type === "date" && typeof v === "string") return v;
120 if (
121 p.type === "date_range" &&
122 v &&
123 typeof v === "object" &&
124 typeof (v as { start?: unknown }).start === "string"
125 ) {
126 return (v as { start: string }).start;
127 }
128 }
129 return null;
130 };
131 switch (type) {
132 case "table":
133 return { type, table: { rows: records } };
134 case "list":
135 return { type, list: { rows: records } };
136 case "board":
137 return { type, board: { groups: groupRecords(records, groupSpecs, props) } };
138 case "gallery":
139 return { type, gallery: { items: records } };
140 case "calendar":
141 return {
142 type,
143 calendar: {
144 events: records
145 .map((r) => ({ record: r, date: dateOf(r) ?? "" }))
146 .filter((e) => e.date !== ""),
147 },
148 };
149 case "timeline":
150 return {
151 type,
152 timeline: {
153 events: records
154 .map((r) => ({ record: r, date: dateOf(r) ?? "" }))
155 .filter((e) => e.date !== ""),
156 },
157 };
158 case "chart":
159 return {
160 type,
161 chart: { chartId: typeof config["chartId"] === "string" ? config["chartId"] : null },
162 };
163 case "dashboard":
164 return {
165 type,
166 dashboard: {
167 dashboardId: typeof config["dashboardId"] === "string" ? config["dashboardId"] : null,
168 },
169 };
170 case "form":
171 return { type, form: { disabled: true, reason: "form_view_phase_10" } };
172 }
173}
174
175
176export const VIEW_TYPES: readonly ViewType[] = [
177 "table",
178 "list",
179 "board",
180 "gallery",
181 "calendar",
182 "timeline",
183 "chart",
184 "dashboard",
185 "form",
186];
187
188export const buttonsModule = buttons;
189