This commit is contained in:
rizrmd 2024-05-29 00:43:59 -07:00
parent 8d716531be
commit 13bd7e3858
13 changed files with 586 additions and 417 deletions

View File

@ -1,13 +1,21 @@
import { useLocal } from "@/utils/use-local";
import get from "lodash.get";
import { FC, useEffect, useRef } from "react";
import { FC, ReactNode, useEffect, useRef } from "react";
import { FMLocal } from "../form/Form";
import { createPortal, render } from "react-dom";
import { Label } from "@/comps/ui/label";
import { Input } from "@/comps/ui/input";
type FilterPosition = 'regular' | 'inline' | 'popup';
type FilterForm = {
gen_fields: GenField[];
gen_table: string;
name: string;
value: any;
child: any;
position: FilterPosition;
children?: ReactNode;
onClose?: () => void;
};
type GenField = {
@ -17,13 +25,23 @@ type GenField = {
optional: boolean
};
export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, value, child }) => {
export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, value, position, children, onClose }): ReactNode => {
const local = useLocal({
data: [] as any[],
columns: [] as string[],
fields: [] as GenField[],
tableName: "",
isGenerated: false,
// fm: {} as FMLocal,
argInit: {} as { fm: FMLocal; submit: any; reload: any },
argOnLoad: {} as { arg: { fm: FMLocal } },
argOnSubmit: {} as {
arg: {
fm: FMLocal;
form: any;
error: any;
}
}
});
useEffect(() => {
if (!isEditor) {
@ -40,6 +58,30 @@ export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, valu
}
}, [])
const renderContent = (): ReactNode => (
<div className={`filter-content filter-${position}`}>
<h3>Filter</h3>
<form>
{local.fields.map((field) => (
<div>
{field.type === 'varchar' && (
<div className="grid w-full max-w-sm items-center gap-1.5" >
<Label htmlFor={field.name}>{field.name}</Label>
<Input id={field.name} type="text" />
</div>
)}
{field.type === "number" && (
<div className="grid w-full max-w-sm items-center gap-1.5" >
<Label htmlFor={field.name}>{field.name}</Label>
<Input id={field.name} type="number" />
</div>
)}
</div>
))}
</form >
</div >
);
const generateFilter = () => {
local.isGenerated = true;
local.tableName = gen_table;
@ -51,10 +93,48 @@ export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, valu
console.log('fields', local.fields);
};
// return <div>{child}</div>;
if (position === 'popup') {
let popup = document.querySelector(".main-content-preview > .portal");
if (!popup) {
popup = document.createElement("div");
popup.classList.add("portal");
const main = document.querySelector(".main-content-preview");
if (main) {
main.appendChild(popup);
}
}
return (
<>
{createPortal(
<div
onClick={onClose}
className={cx(
css`
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: white;
z-index: 100;
`,
"c-flex c-flex-col"
)}
>
{renderContent()}
</div>,
popup
)}
</>
);
}
if (local.isGenerated) {
return renderContent();
} else {
return (
<div>
{!local.isGenerated && (
<button
onClick={generateFilter}
style={{
@ -73,7 +153,7 @@ export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, valu
>
Generate
</button>
)}
</div>
</div >
)
}
};

29
comps/filter/Label.tsx Executable file
View File

@ -0,0 +1,29 @@
import { FC, ReactNode } from "react";
export const Label: FC<{ children: ReactNode; text: string }> = ({
children,
text,
}) => {
return (
<label className="field c-flex c-w-full c-flex-col c-space-y-1 c-px-2">
<div className="label c-text-sm c-flex c-items-center c-mt-3 c-capitalize">
{text}
</div>
<div className="field-inner c-flex c-flex-1 c-flex-col">
<div
className={cx(
"field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm c-flex-wrap",
css`
> * {
width: 100%;
padding: 5px;
}
`
)}
>
{children}
</div>
</div>
</label>
);
};

26
comps/filter/filter.css Executable file
View File

@ -0,0 +1,26 @@
.filter-content {
padding: 1rem;
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
}
.filter-regular {
width: 250px;
/* Styles specific to sidebar */
}
.filter-inline {
display: flex;
align-items: center;
/* Styles specific to topbar */
}
.filter-popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
/* Styles specific to popup */
}

View File

@ -16,8 +16,7 @@ export const generateMasterDetail: GenFn<{ item: PrasiItem, table: string, field
master_detail: true,
};
await generateList(arg, data);
await generateList(arg, data, false);
// const childs = item.edit.childs[0].edit.childs;
// const master = childs.find(
@ -31,6 +30,8 @@ export const generateMasterDetail: GenFn<{ item: PrasiItem, table: string, field
// }`,
// });
// await master.edit.commit();
//
// }
await item.edit.commit();
console.log({item})
};

View File

@ -1,21 +1,21 @@
import { createItem } from "lib/gen/utils";
import get from "lodash.get";
import { generateTableList } from "./md-table-list";
export const generateList = async (
arg: { item: PrasiItem; table: string; fields: any },
data: any
data: any,
commit: boolean
) => {
const item = arg.item;
const tab_master = item.edit.childs[0].edit.childs.find(
(e) => get(e, "component.id") === "c68415ca-dac5-44fe-aeb6-936caf8cc491"
);
tab_master?.edit.setChilds([
{
type: "item",
name: "item",
component: {
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
props: {
const props: Record<string, PropVal> = {
gen_table: {
mode: "string",
value: arg.table,
},
name: {
mode: "string",
value: arg.table,
@ -32,218 +32,97 @@ export const generateList = async (
mode: "raw",
value: `\
({ row, rows, idx, event }: OnRowClick) => {
md.selected = row;
md.internal.action_should_refresh = true;
md.params.apply();
md.render();
md.selected = row;
md.internal.action_should_refresh = true;
md.params.apply();
md.render();
};
type OnRowClick = {
row: any;
rows: any[];
idx: any;
event: React.MouseEvent<HTMLDivElement, MouseEvent>;
row: any;
rows: any[];
idx: any;
event: React.MouseEvent<HTMLDivElement, MouseEvent>;
}
`,
`,
},
selected: {
mode: "raw",
value: `\
({ row, rows, idx }: SelectedRow) => {
try {
if (typeof md === "object") {
if (Array.isArray(md.selected)) {
if (md.selected.length) {
try {
if (typeof md === "object") {
if (Array.isArray(md.selected)) {
if (md.selected.length) {
let select = md.selected.find((e) => e === row)
if(select) return true
}
} else {
if (md.selected === row) {
}
} else {
if (md.selected === row) {
return true;
}
}
}
} catch (e) {
}
}
}
} catch (e) {
}
return false;
}
return false;
};
type SelectedRow = {
row: any;
rows: any[];
idx: any;
row: any;
rows: any[];
idx: any;
}`,
},
gen_fields: {
mode: "raw",
value: `${JSON.stringify(arg.fields)}`,
},
},
},
]);
await item.edit.commit();
// childs.edit.childs[0].edit.setProp("selected", {
// mode: "raw",
// value: `\
// ({ row, rows, idx }: SelectedRow) => {
// try {
// if (typeof md === "object") {
// if (Array.isArray(md.selected)) {
// if (md.selected.length) {
// let select = md.selected.find((e) => e === row)
// if(select) return true
child: {
mode: "jsx",
value: createItem({
name: "halo"
})
}
};
// console.log(true);
console.log({ tab_master });
const tablelist = tab_master?.childs[0];
// generateTableList(
// async (props: any) => {},
// props,
// tablelist,
// { mode: "table" },
// false
// );
// // console.log({modify: async (props: any) => {}, data, item, arg: { mode: "table" }});
// const tablelist: PrasiItem= get(item,"edit.childs[0].edit.childs[0].edit.childs[0]");
// const data_tbl = get(tablelist, "component.props")
// console.log({tablelist, data_tbl})
// if(typeof tab_master === "object"){
// // const master_child: PrasiItem= tab_master;
// // const prop_tablelist = get(tablelist, "component.props")
// // console.log({tablelist})
// //
// }
// } else {
// if (md.selected === row) {
// return true;
// }
// }
// }
// } catch (e) {
// }
// return false;
// };
// type SelectedRow = {
// row: any;
// rows: any[];
// idx: any;
// }`,
// });
// childs.edit.childs[0].edit.setProp("row_click", {
// mode: "raw",
// value: `\
// ({ row, rows, idx, event }: OnRowClick) => {
// md.selected = row;
// md.internal.action_should_refresh = true;
// md.params.apply();
// md.render();
// };
// type OnRowClick = {
// row: any;
// rows: any[];
// idx: any;
// event: React.MouseEvent<HTMLDivElement, MouseEvent>;
// }
// `,
// });
// await item.edit.commit();
// console.log("halo");
// console.log({tab_master})
// // for (const c of get(data, "child.content.childs") || []) {
// // if (c.component?.id === "c68415ca-dac5-44fe-aeb6-936caf8cc491") {
// const res = await codeBuild({
// row_click: `\
// ({ row, rows, idx, event }: OnRowClick) => {
// md.selected = row;
// md.internal.action_should_refresh = true;
// md.params.apply();
// md.render();
// };
// type OnRowClick = {
// row: any;
// rows: any[];
// idx: any;
// event: React.MouseEvent<HTMLDivElement, MouseEvent>;
// }
// `,
// selected: `\
// ({ row, rows, idx }: SelectedRow) => {
// try {
// if (typeof md === "object") {
// if (Array.isArray(md.selected)) {
// if (md.selected.length) {
// let select = md.selected.find((e) => e === row)
// if(select) return true
// }
// } else {
// if (md.selected === row) {
// return true;
// }
// }
// }
// } catch (e) {
// }
// return false;
// };
// type SelectedRow = {
// row: any;
// rows: any[];
// idx: any;
// }`,
// breadcrumb: `\
// async () => {
// return [{ label: "List ${formatName(arg.gen_table)}" }] as BreadItem[];
// };
// type BreadItem = {
// label: React.ReactNode;
// url?: string;
// onClick?: () => void;
// }`,
// actions: `\
// async () => {
// return [
// tab_master?.edit.setChilds([
// {
// label: "Add ${formatName(arg.gen_table)}",
// onClick: async () => {
// md.selected = {};
// md.render();
// },
// },
// ] as ActionItem[];
// };
// type ActionItem =
// | {
// action?: string;
// label: React.ReactNode;
// onClick?: (e: any) => Promise<void>;
// }
// | React.ReactNode`,
// });
// const comp = createItem({
// component: {
// id: "c68415ca-dac5-44fe-aeb6-936caf8cc491",
// props: {
// breadcrumb: res.breadcrumb,
// actions: res.actions,
// },
// },
// });
// for (const [k, v] of Object.entries(comp.component.props)) {
// c.component.props[k] = v;
// }
// const childs = get(c, "component.props.child.content.childs") || [];
// childs.length = 0;
// childs.push(
// createItem({
// type: "item",
// name: "item",
// component: {
// id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
// props: {
// name: arg.gen_table,
// gen_table: arg.gen_table,
// generate: "y",
// on_load: "",
// row_click: res.row_click,
// selected: res.selected,
// gen_fields: [JSON.stringify(arg.gen_fields)],
// child: {
// childs: [],
// props,
// },
// },
// },
// })
// );
// const data = childs[0].component.props;
// const modify = async (props: any) => {};
// gen_table_list(modify, data, { mode: "table" });
// }
// }
// ]);
console.log({
type: "item",
name: "item",
component: {
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
props,
},
})
};

22
comps/md/gen/md-select.ts Executable file
View File

@ -0,0 +1,22 @@
export const generateSelect = (data: Array<any>) => {
const select = {} as any;
let pk = "";
for (const f of data) {
select[f.name] = true;
if (f.relation) {
select[f.name] = {
select: {},
};
for (const r of f.relation.fields) {
select[f.name].select[r.name] = true;
}
}
if (f.is_pk) {
pk = f.name;
}
}
return {
pk,
select,
};
};

241
comps/md/gen/md-table-list.ts Executable file
View File

@ -0,0 +1,241 @@
import capitalize from "lodash.capitalize";
import { GFCol, createItem, parseGenField } from "../../../gen/utils";
import { generateSelect } from "./md-select";
import { on_load } from "./tbl-list/on_load";
import { modeTableList } from "./mode-table-list";
import get from "lodash.get";
import set from "lodash.set";
export const generateTableList = async (
modify: (data: any) => void,
data: any,
item: PrasiItem,
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string },
commit: boolean
) => {
item.edit.setChilds([
{
type: "item",
name: "1",
},
{
type: "item",
name: "2",
},
]);
await item.edit.commit();
// console.log({ data, item, arg });
// const table = data.gen_table.value as string;
// const raw_fields = JSON.parse(data.gen_fields.value) as (
// | string
// | { value: string; checked: string[] }
// )[];
// let pk = "";
// let pks: Record<string, string> = {};
// const fields = parseGenField(raw_fields);
// // const result = {} as any;
// // generate value dari raw_field array string convert ke value selected prisma
// const res = generateSelect(fields);
// pk = res.pk;
// const select = res.select as any;
// const result: Record<string, PropVal> = {};
// if (arg.id_parent) {
// select[arg.id_parent] = true;
// }
// if (!pk) {
// alert("Failed to generate! Primary Key not found. ");
// return;
// }
// let childs = [] as any;
// if (pk) {
// let sub_name = modeTableList(arg.mode);
// let rows = Array.isArray(get(data, "child.content.childs"))
// ? get(data, "child.content.childs")
// : Array.isArray(get(data, "child.childs"))
// ? get(data, "child.childs")
// : [];
// rows = rows.filter((e: PrasiItem) => e.name !== sub_name);
// childs = childs.concat(rows);
// if (data["on_load"]) {
// result.on_load = {
// mode: "raw",
// value: on_load({ pk, table, select, pks }),
// };
// }
// let first = true;
// const child_sub_name = createItem({
// name: sub_name,
// childs: fields
// .map((e, idx) => {
// if (idx >= 1 && arg.mode === "list") {
// return;
// }
// if (e.is_pk && arg.mode === "table") return;
// let tree_depth = "";
// let tree_depth_built = "";
// if (first) {
// tree_depth = `tree_depth={col.depth}`;
// tree_depth_built = `tree_depth:col.depth`;
// first = false;
// }
// return {
// component: {
// id: "297023a4-d552-464a-971d-f40dcd940b77",
// props: {
// name: e.name,
// title: formatName(e.name),
// child: createItem({
// childs: [
// createItem({
// name: "cell",
// padding: {
// l: 8,
// b: 0,
// t: 0,
// r: 8,
// },
// adv: {
// js: `\
// <div {...props} className={cx(props.className, "")}>
// <FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
// </div>`,
// jsBuilt: `\
// render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
// `,
// },
// }),
// ],
// }),
// },
// },
// };
// })
// .filter((e) => e) as any,
// });
// childs.push(child_sub_name);
// // result.child = {
// // mode: "jsx",
// // value: createItem({ name: "child", childs: [child] }),
// // };
// // item.edit.setChilds([child]);
// if (commit) {
// Object.keys(result).map((e) => {
// item.edit.setProp(e, result[e]);
// });
// console.log({ childs });
// item.edit.setChilds([
// {
// name: sub_name,
// },
// {
// name: "123",
// },
// ]);
// await item.edit.commit();
// } else {
// set(item, "childs", childs);
// Object.keys(result).map((e) => {
// set(data, e, result[e]);
// });
// }
// console.log({ res, item });
// console.log({ data });
// console.log({ result });
// }
// return;
// if (pk) {
// console.log("pk");
// const code = {} as any;
// if (data["on_load"]) {
// result["on_load"] = data["on_load"];
// result["on_load"].value = on_load({ pk, table, select, pks });
// delete result["on_load"].valueBuilt;
// code.on_load = result["on_load"].value;
// }
// let sub_name = "fields";
// switch (arg.mode) {
// case "table":
// sub_name = "tbl-col";
// break;
// case "list":
// sub_name = "md-list";
// break;
// }
// let first = true;
// console.log(sub_name);
// const child = {
// name: sub_name,
// childs: fields
// .map((e, idx) => {
// if (idx >= 1 && arg.mode === "list") {
// return;
// }
// if (e.is_pk && arg.mode === "table") return;
// let tree_depth = "";
// let tree_depth_built = "";
// if (first) {
// tree_depth = `tree_depth={col.depth}`;
// tree_depth_built = `tree_depth:col.depth`;
// first = false;
// }
// return {
// component: {
// id: "297023a4-d552-464a-971d-f40dcd940b77",
// props: {
// name: {
// mode: "string",
// value: e.name
// },
// title: {
// mode: "string",
// value: formatName(e.name)
// },
// child: createItem({
// childs: [
// createItem({
// name: "cell",
// padding: {
// l: 8,
// b: 0,
// t: 0,
// r: 8,
// },
// adv: {
// js: `\
// <div {...props} className={cx(props.className, "")}>
// <FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
// </div>`,
// jsBuilt: `\
// render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
// `,
// },
// }),
// ],
// }),
// },
// },
// };
// })
// .filter((e) => e) as any,
// };
// data.child.value = child;
// result["child"] = data.child
// }
// modify(result);
// console.log({ child: data["child"] });
};
const formatName = (name: string) => {
return name
.split("_")
.filter((e) => e.length > 1)
.map((e) => capitalize(e))
.join(" ");
};

12
comps/md/gen/mode-table-list.ts Executable file
View File

@ -0,0 +1,12 @@
export const modeTableList = (mode: string) => {
let sub_name = "fields";
switch (mode) {
case "table":
sub_name = "tbl-col";
break;
case "list":
sub_name = "md-list";
break;
}
return sub_name;
};

View File

@ -0,0 +1,57 @@
export const on_load = ({
pk,
table,
select,
pks,
}: {
pk: string;
table: string;
select: any;
pks: Record<string, string>;
}) => {
const sample = {} as any;
for (const [k, v] of Object.entries(select) as any) {
if (typeof v === "object") {
sample[k] = {};
Object.keys(v.select)
.filter((e) => e !== pks[k])
.map((e) => {
sample[k][e] = "sample";
});
} else {
sample[k] = "sample";
}
}
return `\
(arg: TableOnLoad) => {
if (isEditor) return [${JSON.stringify(sample)}];
return new Promise(async (done) => {
if (arg.mode === 'count') {
return await db.${table}.count();
}
const items = await db.${table}.findMany({
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
orderBy: arg.orderBy || {
${pk}: "desc"
},
...arg.paging,
});
done(items);
})
}
type TableOnLoad = {
reload: () => Promise<void>;
orderBy?: Record<string, "asc" | "desc">;
paging: { take: number; skip: number };
mode: 'count' | 'query'
}
`;
};

View File

@ -54,6 +54,7 @@ export { TableListType } from "lib/comps/list/utils/typings";
export { Button, FloatButton } from "@/comps/ui/button";
export { prasi_gen } from "@/gen/prasi_gen";
export { password } from "@/utils/password";
export {generateTableList} from "@/comps/md/gen/md-table-list"
/** Session */
export {

View File

@ -6,7 +6,7 @@ import { codeBuild } from "../master_detail/utils";
export const gen_table_list = async (
modify: (data: any) => void,
data: any,
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string }
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string}
) => {
const table = JSON.parse(data.gen_table.value) as string;
const raw_fields = JSON.parse(data.gen_fields.value) as (
@ -53,7 +53,6 @@ export const gen_table_list = async (
if (data["child"]) {
result["child"] = data["child"];
let sub_name = "fields";
switch (arg.mode) {
case "table":

View File

@ -1,176 +0,0 @@
import capitalize from "lodash.capitalize";
import { GFCol, createItem, parseGenField } from "../utils";
import { on_load } from "./on_load";
import { codeBuild } from "../master_detail/utils";
export const generateTableList = async (
modify: (data: any) => void,
data: any,
item: PrasiItem,
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string }
) => {
const table = JSON.parse(data.gen_table.value) as string;
const raw_fields = JSON.parse(data.gen_fields.value) as (
| string
| { value: string; checked: string[] }
)[];
const select = {} as any;
let pk = "";
let pks: Record<string, string> = {};
const fields = parseGenField(raw_fields);
const result = {} as any;
for (const f of fields) {
select[f.name] = true;
if (f.relation) {
select[f.name] = {
select: {},
};
for (const r of f.relation.fields) {
select[f.name].select[r.name] = true;
}
}
if (f.is_pk) {
pk = f.name;
}
}
if (arg.id_parent) {
select[arg.id_parent] = true;
}
if (!pk) {
alert("Failed to generate! Primary Key not found. ");
return;
}
if (pk) {
const code = {} as any;
if (data["on_load"]) {
result["on_load"] = data["on_load"];
result["on_load"].value = on_load({ pk, table, select, pks });
delete result["on_load"].valueBuilt;
code.on_load = result["on_load"].value;
}
if (data["child"]) {
result["child"] = data["child"];
let sub_name = "fields";
switch (arg.mode) {
case "table":
sub_name = "tbl-col";
break;
case "list":
sub_name = "md-list";
break;
}
result["child"].content.childs = result["child"].content.childs.filter(
(e: any) => {
return e.name !== sub_name;
}
);
let first = true;
const child = createItem({
name: sub_name,
childs: fields
.map((e, idx) => {
if (idx >= 1 && arg.mode === "list") {
return;
}
if (e.is_pk && arg.mode === "table") return;
let tree_depth = "";
let tree_depth_built = "";
if (first) {
tree_depth = `tree_depth={col.depth}`;
tree_depth_built = `tree_depth:col.depth`;
first = false;
}
return {
component: {
id: "297023a4-d552-464a-971d-f40dcd940b77",
props: {
name: e.name,
title: formatName(e.name),
child: createItem({
childs: [
createItem({
name: "cell",
padding: {
l: 8,
b: 0,
t: 0,
r: 8,
},
adv: {
js: `\
<div {...props} className={cx(props.className, "")}>
<FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
</div>`,
jsBuilt: `\
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
`,
},
}),
],
}),
},
},
};
})
.filter((e) => e) as any,
});
result["child"].content.childs = [
child,
...result["child"].content.childs,
];
}
// detect row yang aktif
if (data["selected"]) {
result["selected"] = data["selected"];
result["selected"].value = `\
({ row, rows, idx }: SelectedRow) => {
try {
if (typeof md === "object") {
if (Array.isArray(md.selected)) {
if (md.selected.length) {
let select = md.selected.find((e) => e === row)
if(select) return true
}
} else {
if (md.selected === row) {
return true;
}
}
}
} catch (e) {
}
return false;
};
type SelectedRow = {
row: any;
rows: any[];
idx: any;
}`;
delete result["selected"].valueBuilt;
code.selected = result["selected"].value;
}
const res = await codeBuild(code);
for (const [k, v] of Object.entries(res)) {
result[k].valueBuilt = v[1];
}
}
modify(result);
};
const formatName = (name: string) => {
return name
.split("_")
.filter((e) => e.length > 1)
.map((e) => capitalize(e))
.join(" ");
};

View File

@ -1,5 +1,3 @@
import { GFCol } from "../utils";
export const on_load = ({
pk,
table,