From 9957e9d626b78824c316f1c99a306ed269342323 Mon Sep 17 00:00:00 2001 From: rizky Date: Mon, 25 Mar 2024 22:38:27 -0700 Subject: [PATCH] wip fix --- comps/form/Field.tsx | 1 - comps/mst/MasterDetail.tsx | 79 +++++++++++++++++++++++++++------- comps/mst/type.ts | 6 +++ comps/mst/utils.ts | 33 ++++++++++++++ gen/gen_form/on_load.ts | 30 ++++++++----- gen/gen_md/form_before_load.ts | 17 ++++++-- gen/gen_md/gen_md.ts | 15 +++++-- 7 files changed, 146 insertions(+), 35 deletions(-) create mode 100755 comps/mst/utils.ts diff --git a/comps/form/Field.tsx b/comps/form/Field.tsx index 2f48759..f9dd7da 100755 --- a/comps/form/Field.tsx +++ b/comps/form/Field.tsx @@ -93,7 +93,6 @@ export const Field: FC<{ }, modify: null as any, }); - const textAreaRef = useRef(); useEffect(() => { autosize(textAreaRef.current); diff --git a/comps/mst/MasterDetail.tsx b/comps/mst/MasterDetail.tsx index 2449af5..788a6bb 100755 --- a/comps/mst/MasterDetail.tsx +++ b/comps/mst/MasterDetail.tsx @@ -1,30 +1,54 @@ import { useLocal } from "@/utils/use-local"; import get from "lodash.get"; import { FC, useEffect } from "react"; +import { Tabs, TabsList, TabsTrigger } from "../ui/tabs"; import { MasterDetailConfig, MasterDetailLocal, MasterDetailProp, } from "./type"; -import { Tab } from "../custom/Tab"; -import { Tabs, TabsList, TabsTrigger } from "../ui/tabs"; +import { GFCol } from "@/gen/utils"; +import { master_detail_gen_hash, master_detail_params } from "./utils"; export const MasterDetail: FC = (props) => { - const { header, PassProp, master, detail, mode, title, actions } = props; - const md = useLocal({ - mode, - selected: null, - active_tab: "", - ui: { - back: false, - title: title, - breadcrumb: [], - default_actions: null as any, - actions: null as any, + const { header, name, mode, title, actions, gen_fields } = props; + const md = useLocal( + { + name, + mode, + selected: null, + active_tab: "", + ui: { + back: false, + title: title, + breadcrumb: [], + default_actions: null as any, + actions: null as any, + }, + cache_internal: {}, + cache: null as any, + pk: null as null | GFCol, }, - cache_internal: {}, - cache: null as any, - }); + () => { + if (!isEditor) { + const hash = master_detail_params(md); + if (hash && hash[name] && md.pk) { + if (md.pk.type === "int") { + md.selected = { [md.pk.name]: parseInt(hash[name]) }; + } else { + md.selected = { [md.pk.name]: hash[name] }; + } + md.render(); + } + } + } + ); + if (!md.pk && gen_fields) { + for (const str of gen_fields) { + const f = JSON.parse(str) as GFCol; + if (f.is_pk) md.pk = f; + } + } if (!md.ui.actions) { md.ui.actions = actions(md); @@ -72,6 +96,24 @@ const BreadcrumbMode: FC<{ props: MasterDetailProp; md: MasterDetailConfig; }> = ({ props, md }) => { + const local = useLocal({ init: false }, () => { + local.init = true; + local.render(); + }); + + if (local.init) { + const hash = master_detail_params(md); + delete hash.parent_id; + + if (!md.selected) { + delete hash[md.name]; + location.hash = master_detail_gen_hash(hash); + } else if (md.pk) { + hash[md.name] = md.selected[md.pk.name]; + location.hash = master_detail_gen_hash(hash); + } + } + return (
{props.master}
{md.selected && } + {isEditor && !local.init && ( +
+ +
+ )}
); }; diff --git a/comps/mst/type.ts b/comps/mst/type.ts index f981f45..cdfda30 100755 --- a/comps/mst/type.ts +++ b/comps/mst/type.ts @@ -1,3 +1,4 @@ +import { GFCol } from "@/gen/utils"; import { ReactElement, ReactNode } from "react"; export type MasterDetailProp = { @@ -8,6 +9,8 @@ export type MasterDetailProp = { mode: "breadcrumb" | "vertical" | "horizontal"; title: string; actions: (md: any) => MasterDetailAction[]; + gen_fields: any; + name: string; }; type MasterDetailAction = { @@ -18,6 +21,7 @@ type MasterDetailAction = { }; export type MasterDetailLocal = { + name: string; mode: MasterDetailProp["mode"]; selected: null | Record; active_tab: string; @@ -29,6 +33,7 @@ export type MasterDetailLocal = { actions: MasterDetailAction[]; }; cache: (name: string, opt?: { reset: boolean }) => any; + pk: null | GFCol; }; export type MasterDetailConfig = MasterDetailLocal & { render: () => void }; @@ -54,6 +59,7 @@ export const master_detail_typings = { actions: ${action_type}[]; }; cache: (name: string, opt?: { reset: boolean }) => any; + pk: null | any }`, action_type, }; diff --git a/comps/mst/utils.ts b/comps/mst/utils.ts new file mode 100755 index 0000000..b00e773 --- /dev/null +++ b/comps/mst/utils.ts @@ -0,0 +1,33 @@ +import { MasterDetailConfig } from "./type"; + +export const master_detail_params = (md: MasterDetailConfig) => { + let parent_id = + md.pk?.type === "int" + ? parseInt(md.selected?.[md.pk?.name || ""]) + : md.selected?.[md.pk?.name || ""]; + + const hash: any = {}; + for (const h of location.hash.split("#")) { + if (h) { + const [tab_name, tab_val] = h.split("="); + if (tab_name && tab_val) { + hash[tab_name] = tab_val; + } + } + } + + if (parent_id) { + return { ...hash, parent_id }; + } + return hash; +}; + +export const master_detail_gen_hash = ( + obj: Record +) => { + let hash = ""; + for (const [k, v] of Object.entries(obj)) { + hash += `#${k}=${v}`; + } + return hash; +}; diff --git a/gen/gen_form/on_load.ts b/gen/gen_form/on_load.ts index f919bec..c5ebe73 100755 --- a/gen/gen_form/on_load.ts +++ b/gen/gen_form/on_load.ts @@ -20,8 +20,13 @@ export const on_load = ({ async (opt) => { if (isEditor) return {}; + ${ + opt?.before_load + ? opt.before_load + : ` let id = ${pk.type === "int" ? "parseInt(params.id)" : "params.id"}; - ${opt?.before_load} + ` + } let item = {}; if (id){ @@ -32,16 +37,19 @@ async (opt) => { select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")}, }); - for (const [k, v] of Object.entries(item)) { - ${Object.entries(pks) - .map(([k, v]) => { - return `\ - if (k === "${k}") { - if (v?.["${v}"]) item[k] = { connect: { ${v}: v?.["${v}"] } } as any; - else delete item[k]; - }`; - }) - .join("\n")} + if (item){ + for (const [k, v] of Object.entries(item)) { + ${Object.entries(pks) + .map(([k, v]) => { + return `\ + if (k === "${k}") { + if (v?.["${v}"]) item[k] = { connect: { ${v}: v?.["${v}"] } } as any; + else delete item[k]; + }`; + }) + .join("\n")} + } + } ${opt?.after_load} diff --git a/gen/gen_md/form_before_load.ts b/gen/gen_md/form_before_load.ts index 8371859..44983a7 100755 --- a/gen/gen_md/form_before_load.ts +++ b/gen/gen_md/form_before_load.ts @@ -1,10 +1,15 @@ +import { GFCol } from "../utils"; + export const form_before_load = ( table: string, - pk: string, + pk: GFCol, title: string, label: string ) => { return ` + + const id = master_detail_params(md).parent_id; + const after_load = (item: any) => { const set_actions = () => (md.ui.actions = [ @@ -16,7 +21,9 @@ export const form_before_load = ( md.ui.actions = [{ label: "Deleting...", type: "ghost" }]; md.render(); - await db.${table}.delete({ where: { ${pk}: item.${pk} } }); + await db.${table}.delete({ where: { ${pk.name}: item.${ + pk.name + } } }); setTimeout(() => { md.ui.actions = [...md.ui.default_actions]; @@ -44,10 +51,12 @@ export const form_before_load = ( }, ]); set_actions(); - md.ui.breadcrumb = [["${title}", ""]${label ? `, item?.["${label}"]` : ""}]; + md.ui.breadcrumb = [[md.ui.title, ""]${ + label ? `, item?.["${label}"]` : "" + }]; md.render(); }; - md.ui.breadcrumb = [["${title}", ""], "..."]; + md.ui.breadcrumb = [[md.ui.title, ""], "..."]; md.render(); `; diff --git a/gen/gen_md/gen_md.ts b/gen/gen_md/gen_md.ts index f2629f9..05aa42e 100755 --- a/gen/gen_md/gen_md.ts +++ b/gen/gen_md/gen_md.ts @@ -11,6 +11,7 @@ import { gen_columns } from "../gen_table/columns"; import { newField as table_new_field } from "../gen_table/new_field"; import { gen_detail } from "./gen_detail"; import { form_before_load } from "./form_before_load"; +import { createId } from "@paralleldrive/cuid2"; export const gen_md = (modify: (data: any) => void, data: any) => { const table = JSON.parse(data.gen_table.value); @@ -86,7 +87,7 @@ export const gen_md = (modify: (data: any) => void, data: any) => { const detail = gen_detail(); const title = parse(get(data, "title.value")); const label = parse(get(data, "gen_label.value")); - const before_load = form_before_load(table, pk.name, title, label); + const before_load = form_before_load(table, pk, title, label); detail.props["on_load"].value = form_on_load({ pk, @@ -105,9 +106,17 @@ export const gen_md = (modify: (data: any) => void, data: any) => { const childs = get(detail.props, "body.content.childs"); if (Array.isArray(childs)) { detail.props.body.content.childs = new_fields.map(form_new_field) as any; - console.log(detail.props.body.content.childs); } - result["detail"].content = detail.content; + result["detail"].content = { + id: createId(), + name: "Detail", + type: "item", + dim: { + w: "full", + h: "full", + }, + childs: [detail.content], + }; } modify(result);