fix
This commit is contained in:
parent
a07251c76e
commit
fff9049ff6
|
|
@ -2,6 +2,7 @@ import { useLocal } from "@/utils/use-local";
|
||||||
import { FC, ReactNode, useEffect } from "react";
|
import { FC, ReactNode, useEffect } from "react";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
|
import { FieldLoading } from "../ui/field-loading";
|
||||||
|
|
||||||
export type BreadItem = {
|
export type BreadItem = {
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
|
|
@ -16,43 +17,7 @@ type BreadcrumbProps = {
|
||||||
item?: PrasiItem;
|
item?: PrasiItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Breadcrumb: FC<BreadcrumbProps> = ({
|
export const Breadcrumb: FC<BreadcrumbProps> = ({ value, className }) => {
|
||||||
value,
|
|
||||||
className,
|
|
||||||
on_load,
|
|
||||||
item,
|
|
||||||
}) => {
|
|
||||||
const local = useLocal({
|
|
||||||
list: [] as BreadItem[],
|
|
||||||
status: "init" as "init" | "loading" | "ready",
|
|
||||||
params: {},
|
|
||||||
reload: () => {
|
|
||||||
if (typeof on_load === "function") {
|
|
||||||
local.status = "loading";
|
|
||||||
on_load(local).then((res: any) => {
|
|
||||||
if (typeof res === "object") {
|
|
||||||
if (!Array.isArray(res)) {
|
|
||||||
local.list = get(res, "list") || [];
|
|
||||||
} else {
|
|
||||||
local.list = res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local.status = "ready";
|
|
||||||
local.render();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
local.render();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (value) {
|
|
||||||
local.list = value;
|
|
||||||
local.status = "ready";
|
|
||||||
}
|
|
||||||
local.reload();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
|
|
@ -60,29 +25,25 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{local.status !== "ready" ? (
|
{(value || []).map((cur, index): ReactNode => {
|
||||||
<Skeleton className="c-h-4 c-w-[80%]" />
|
const lastIndex = (value || []).length - 1;
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{local.list &&
|
|
||||||
(local.list || []).map((item, index): ReactNode => {
|
|
||||||
const lastIndex = local.list.length - 1;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{index === lastIndex ? (
|
{index === lastIndex ? (
|
||||||
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
||||||
{item?.label}
|
{cur?.label}
|
||||||
</h1>
|
</h1>
|
||||||
) : (
|
) : (
|
||||||
<h1
|
<h1
|
||||||
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer hover:c-underline"
|
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer hover:c-underline"
|
||||||
onClick={(ev) => {
|
onClick={(ev) => {
|
||||||
if (item.url) navigate(item.url || "");
|
if (isEditor) return;
|
||||||
if (item.onClick) item.onClick(ev);
|
if (cur.url) navigate(cur.url || "");
|
||||||
|
if (cur.onClick) cur.onClick(ev);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item?.label}
|
{cur?.label}
|
||||||
</h1>
|
</h1>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -107,8 +68,6 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,14 @@ import { editorFormData } from "./utils/ed-data";
|
||||||
import { formInit } from "./utils/init";
|
import { formInit } from "./utils/init";
|
||||||
import { formReload } from "./utils/reload";
|
import { formReload } from "./utils/reload";
|
||||||
import { getPathname } from "lib/utils/pathname";
|
import { getPathname } from "lib/utils/pathname";
|
||||||
|
import { sofDeleteField } from "lib/utils/soft-del-rel";
|
||||||
|
|
||||||
const editorFormWidth = {} as Record<string, { w: number; f: any }>;
|
const editorFormWidth = {} as Record<string, { w: number; f: any }>;
|
||||||
|
|
||||||
export { FMLocal } from "./typings";
|
export { FMLocal } from "./typings";
|
||||||
|
|
||||||
export const Form: FC<FMProps> = (props) => {
|
export const Form: FC<FMProps> = (props) => {
|
||||||
const { PassProp, body } = props;
|
const { PassProp, body, feature, sfd_field } = props;
|
||||||
const fm = useLocal<FMInternal>({
|
const fm = useLocal<FMInternal>({
|
||||||
data: editorFormData[props.item.id]
|
data: editorFormData[props.item.id]
|
||||||
? editorFormData[props.item.id].data
|
? editorFormData[props.item.id].data
|
||||||
|
|
@ -51,8 +52,30 @@ export const Form: FC<FMProps> = (props) => {
|
||||||
? editorFormWidth[props.item.id].f
|
? editorFormWidth[props.item.id].f
|
||||||
: "full",
|
: "full",
|
||||||
},
|
},
|
||||||
|
soft_delete: {
|
||||||
|
field: null
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
// deteksi jika ada softdelete
|
||||||
|
if(Array.isArray(props.feature)){
|
||||||
|
if(props.feature?.find((e) => e === "soft_delete")){
|
||||||
|
const result = sofDeleteField(props.gen_table, sfd_field)
|
||||||
|
if (result instanceof Promise) {
|
||||||
|
result.then((e) => {
|
||||||
|
// simpan fields yang berisi name dan type fields soft delete
|
||||||
|
fm.soft_delete.field = e;
|
||||||
|
if(!isEditor){
|
||||||
|
fm.render();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
fm.soft_delete.field = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [])
|
||||||
const ref = useRef({
|
const ref = useRef({
|
||||||
el: null as null | HTMLFormElement,
|
el: null as null | HTMLFormElement,
|
||||||
rob: new ResizeObserver(([e]) => {
|
rob: new ResizeObserver(([e]) => {
|
||||||
|
|
|
||||||
|
|
@ -31,45 +31,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
||||||
const errors = fm.error.get(name);
|
const errors = fm.error.get(name);
|
||||||
const props = { ...arg.props };
|
const props = { ...arg.props };
|
||||||
delete props.className;
|
delete props.className;
|
||||||
if (type === "-" || !type || sub_type === "-" || !sub_type) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="c-p-4">
|
|
||||||
⚠️ Field {arg.label} is not ready
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: normal;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{arg.msg_error}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
(type === "multi-option" && sub_type === "-") ||
|
|
||||||
(type === "multi-option" && sub_type === "table-edit" && (!arg.gen_table || arg.gen_table === ""))
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="c-p-4">
|
|
||||||
⚠️ Table Edit {arg.label} is not ready
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: normal;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{arg.msg_error}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
|
|
@ -79,8 +41,8 @@ export const Field: FC<FieldProp> = (arg) => {
|
||||||
css`
|
css`
|
||||||
padding: 5px 0px 0px 10px;
|
padding: 5px 0px 0px 10px;
|
||||||
`,
|
`,
|
||||||
|
|
||||||
w === "auto" && fm.size.field === "full" && "c-w-full",
|
w === "auto" && fm.size.field === "full" && "c-w-full",
|
||||||
|
w === "auto" && fm.size.field === "half" && "c-w-1/2",
|
||||||
w === "full" && "c-w-full",
|
w === "full" && "c-w-full",
|
||||||
w === "¾" && "c-w-3/4",
|
w === "¾" && "c-w-3/4",
|
||||||
w === "½" && "c-w-1/2",
|
w === "½" && "c-w-1/2",
|
||||||
|
|
@ -111,7 +73,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
||||||
{errors.length > 0 && (
|
{errors.length > 0 && (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
"c-p-2 c-text-xs c-text-red-600",
|
"field-error c-p-2 c-text-xs c-text-red-600",
|
||||||
field.desc && "c-pt-0"
|
field.desc && "c-pt-0"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export const FieldInput: FC<{
|
||||||
child: any;
|
child: any;
|
||||||
_item: PrasiItem;
|
_item: PrasiItem;
|
||||||
arg: FieldProp;
|
arg: FieldProp;
|
||||||
}> = ({ field, fm, arg, _item, PassProp, child}) => {
|
}> = ({ field, fm, arg, _item, PassProp, child }) => {
|
||||||
// return <></>
|
// return <></>
|
||||||
const prefix =
|
const prefix =
|
||||||
typeof field.prefix === "function"
|
typeof field.prefix === "function"
|
||||||
|
|
@ -48,6 +48,8 @@ export const FieldInput: FC<{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let table_edit = null;
|
||||||
if (type_field === "multi-option" && arg.sub_type === "table-edit") {
|
if (type_field === "multi-option" && arg.sub_type === "table-edit") {
|
||||||
const childsTableEdit = get(
|
const childsTableEdit = get(
|
||||||
_item,
|
_item,
|
||||||
|
|
@ -57,7 +59,7 @@ export const FieldInput: FC<{
|
||||||
child: get(_item, "edit.props.child.value") as PrasiItem,
|
child: get(_item, "edit.props.child.value") as PrasiItem,
|
||||||
bottom: childsTableEdit.find((e) => e.name === "bottom") as PrasiItem,
|
bottom: childsTableEdit.find((e) => e.name === "bottom") as PrasiItem,
|
||||||
};
|
};
|
||||||
return (
|
table_edit = (
|
||||||
<TableEdit
|
<TableEdit
|
||||||
on_init={() => {
|
on_init={() => {
|
||||||
return fm;
|
return fm;
|
||||||
|
|
@ -70,13 +72,38 @@ export const FieldInput: FC<{
|
||||||
body={tableEdit.child}
|
body={tableEdit.child}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return <>{arg.child}</>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let not_ready: any = false;
|
||||||
|
if (
|
||||||
|
arg.type === "multi-option" &&
|
||||||
|
arg.sub_type === "table-edit" &&
|
||||||
|
(!arg.gen_fields?.length || arg.gen_fields?.length === 1)
|
||||||
|
) {
|
||||||
|
not_ready = (
|
||||||
|
<>
|
||||||
|
<div className="c-m-1 c-p-2 c-border c-border-red-500">
|
||||||
|
⚠️ Field: {arg.label} is not ready
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: normal;
|
||||||
|
white-space: pre;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Please select fields in relation and click generate.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
!["toogle", "button", "radio", "checkbox"].includes(arg.sub_type)
|
!["toogle", "button", "radio", "checkbox"].includes(arg.sub_type)
|
||||||
? "field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm"
|
? "field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm c-bg-white"
|
||||||
: "",
|
: "",
|
||||||
fm.status === "loading"
|
fm.status === "loading"
|
||||||
? css`
|
? css`
|
||||||
|
|
@ -115,6 +142,10 @@ export const FieldInput: FC<{
|
||||||
field.disabled && "c-pointer-events-none"
|
field.disabled && "c-pointer-events-none"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
{not_ready ? (
|
||||||
|
not_ready
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
{type_field === "custom" && arg.custom ? (
|
{type_field === "custom" && arg.custom ? (
|
||||||
<>{custom}</>
|
<>{custom}</>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -136,12 +167,18 @@ export const FieldInput: FC<{
|
||||||
) : ["single-option"].includes(type_field) ? (
|
) : ["single-option"].includes(type_field) ? (
|
||||||
<SingleOption arg={arg} field={field} fm={fm} />
|
<SingleOption arg={arg} field={field} fm={fm} />
|
||||||
) : ["multi-option"].includes(type_field) ? (
|
) : ["multi-option"].includes(type_field) ? (
|
||||||
|
arg.sub_type === "table-edit" ? (
|
||||||
|
table_edit
|
||||||
|
) : (
|
||||||
<MultiOption arg={arg} field={field} fm={fm} />
|
<MultiOption arg={arg} field={field} fm={fm} />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<>{isValidElement(type_field) && type_field}</>
|
<>{isValidElement(type_field) && type_field}</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{suffix && suffix !== "" ? (
|
{suffix && suffix !== "" ? (
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import { TableList } from "lib/comps/list/TableList";
|
import { TableList } from "lib/comps/list/TableList";
|
||||||
import { useLocal } from "lib/utils/use-local";
|
import { useLocal } from "lib/utils/use-local";
|
||||||
import { FC } from "react";
|
import { FC, ReactElement, useEffect, useRef } from "react";
|
||||||
import { BaseForm } from "../../base/BaseForm";
|
import { BaseForm } from "../../base/BaseForm";
|
||||||
import { FMLocal } from "../../typings";
|
import { FMLocal } from "../../typings";
|
||||||
import get from "lodash.get";
|
|
||||||
|
|
||||||
export const TableEdit: FC<{
|
export const TableEdit: FC<{
|
||||||
on_init: () => FMLocal;
|
on_init: () => FMLocal;
|
||||||
|
|
@ -21,7 +20,17 @@ export const TableEdit: FC<{
|
||||||
},
|
},
|
||||||
() => {}
|
() => {}
|
||||||
);
|
);
|
||||||
const value = isEditor ? [{}] :Array.isArray(fm.data[name]) ? fm.data[name] : [];
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
if (!Array.isArray(fm.data[name])) {
|
||||||
|
if (typeof fm.data[name] === "object") {
|
||||||
|
fm.data[name] = [JSON.parse(JSON.stringify(fm.data[name]))];
|
||||||
|
} else {
|
||||||
|
fm.data[name] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const value = fm.data[name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="c-w-full c-h-full c-flex c-flex-col">
|
<div className="c-w-full c-h-full c-flex c-flex-col">
|
||||||
|
|
@ -32,6 +41,18 @@ export const TableEdit: FC<{
|
||||||
> .rdg {
|
> .rdg {
|
||||||
overflow-y: hidden !important;
|
overflow-y: hidden !important;
|
||||||
}
|
}
|
||||||
|
.rdg-cell > div {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 5px;
|
||||||
|
.field {
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.field-error {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -41,57 +62,82 @@ export const TableEdit: FC<{
|
||||||
? 50
|
? 50
|
||||||
: value.length * 50 + 50,
|
: value.length * 50 + 50,
|
||||||
}}
|
}}
|
||||||
|
ref={ref}
|
||||||
>
|
>
|
||||||
|
{/* <button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
db.milestone.create({
|
||||||
|
data: {
|
||||||
|
goal_setting: {
|
||||||
|
connect: {
|
||||||
|
id: "456222b4-4c0c-4f53-b62e-3e1f685f9c4a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "124124",
|
||||||
|
goal: {
|
||||||
|
connect: {
|
||||||
|
id: "9fa14b83-2d8b-4c3d-a18c-c17d99a37813",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
COBA
|
||||||
|
</button> */}
|
||||||
<TableList
|
<TableList
|
||||||
rowHeight={50}
|
row_height={50}
|
||||||
feature={[]}
|
feature={[]}
|
||||||
child={child}
|
child={child}
|
||||||
PassProp={PassProp}
|
PassProp={PassProp}
|
||||||
name={""}
|
name={""}
|
||||||
value={value}
|
value={value}
|
||||||
on_init={() => {}}
|
on_init={(tbl) => {
|
||||||
|
local.tbl = tbl;
|
||||||
|
local.render();
|
||||||
|
}}
|
||||||
mode={"table"}
|
mode={"table"}
|
||||||
_item={item}
|
_item={item}
|
||||||
gen_fields={[]}
|
gen_fields={[]}
|
||||||
row_click={() => {}}
|
row_click={({ event }) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
selected={() => {
|
selected={() => {
|
||||||
return false;
|
return false;
|
||||||
}}
|
}}
|
||||||
filter_name={""}
|
filter_name={""}
|
||||||
render_col={(arg: any) => {
|
render_col={(arg) => {
|
||||||
const { props, tbl, child } = arg;
|
const { props, tbl, child } = arg;
|
||||||
const fm_row = { ...fm };
|
const fm_row = { ...fm, render: local.render };
|
||||||
fm_row.data = props.row;
|
fm_row.data = props.row;
|
||||||
fm_row.render = fm.render;
|
|
||||||
local.tbl = tbl;
|
local.tbl = tbl;
|
||||||
|
|
||||||
|
const key = props.column.key;
|
||||||
return (
|
return (
|
||||||
<PassProp
|
<PassProp
|
||||||
idx={props.rowIdx}
|
idx={props.rowIdx}
|
||||||
row={props.row}
|
row={props.row}
|
||||||
col={{
|
col={{
|
||||||
name: props.column.key,
|
name: key,
|
||||||
value: props.row[props.column.key],
|
value: props.row[props.column.key],
|
||||||
depth: props.row.__depth || 0,
|
depth: props.row.__depth || 0,
|
||||||
}}
|
}}
|
||||||
rows={tbl.data}
|
rows={tbl.data}
|
||||||
fm={fm_row}
|
fm={fm_row}
|
||||||
ext_fm={{
|
ext_fm={{
|
||||||
|
change: () => {},
|
||||||
remove: () => {
|
remove: () => {
|
||||||
if (Array.isArray(fm.data[name])) {
|
fm.data[name] = tbl.data.filter(
|
||||||
fm.data[name] = value.filter(
|
|
||||||
(e: any) => e !== props.row
|
(e: any) => e !== props.row
|
||||||
);
|
);
|
||||||
fm.render();
|
fm.render();
|
||||||
tbl.data = fm.data[name];
|
|
||||||
tbl.render();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
add: () => {
|
add: () => {
|
||||||
if (Array.isArray(value)) {
|
tbl.data.push({});
|
||||||
value.push({});
|
fm.render();
|
||||||
} else {
|
|
||||||
alert("value bukan array");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -99,35 +145,23 @@ export const TableEdit: FC<{
|
||||||
</PassProp>
|
</PassProp>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
render_row={(child, data) => {
|
|
||||||
return (
|
|
||||||
<div className="c-contents">
|
|
||||||
<BaseForm
|
|
||||||
is_form={false}
|
|
||||||
data={data}
|
|
||||||
on_submit={(form) => {}}
|
|
||||||
render={fm.render}
|
|
||||||
>
|
|
||||||
{(form) => {
|
|
||||||
return <>{child}</>;
|
|
||||||
}}
|
|
||||||
</BaseForm>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<PassProp
|
<PassProp
|
||||||
ext_fm={{
|
ext_fm={{
|
||||||
add: () => {
|
add: () => {
|
||||||
if (Array.isArray(value)) {
|
local.tbl.data.push({});
|
||||||
value.push({});
|
|
||||||
fm.data[name] = value;
|
|
||||||
fm.render();
|
|
||||||
} else {
|
|
||||||
fm.data[name] = [{}];
|
|
||||||
fm.render();
|
fm.render();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const last = Array.from(
|
||||||
|
ref.current?.querySelectorAll(".rdg-row") || []
|
||||||
|
).pop();
|
||||||
|
const input = last?.querySelector("input");
|
||||||
|
if (input) {
|
||||||
|
input.focus();
|
||||||
}
|
}
|
||||||
|
}, 100);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -137,39 +171,3 @@ export const TableEdit: FC<{
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Footer = (
|
|
||||||
fm: FMLocal,
|
|
||||||
name: string,
|
|
||||||
PassProp: any,
|
|
||||||
child: any,
|
|
||||||
value: Array<any>
|
|
||||||
) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* <div>
|
|
||||||
<PassProp
|
|
||||||
ext_fm={{
|
|
||||||
remove: () => {
|
|
||||||
if (Array.isArray(fm.data[name])) {
|
|
||||||
fm.data[name] = value.filter(
|
|
||||||
(e: any) => e !== props.row
|
|
||||||
);
|
|
||||||
fm.render();
|
|
||||||
tbl.data = fm.data[name];
|
|
||||||
tbl.render();
|
|
||||||
console.log(fm.data)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
add: () => {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
value.push({});
|
|
||||||
} else {
|
|
||||||
alert("value bukan array");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}}></PassProp>
|
|
||||||
</div> */}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useLocal } from "@/utils/use-local";
|
import { useLocal } from "@/utils/use-local";
|
||||||
import { FC, useEffect } from "react";
|
|
||||||
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
|
||||||
import { FieldLoading } from "lib/comps/ui/field-loading";
|
import { FieldLoading } from "lib/comps/ui/field-loading";
|
||||||
import { Typeahead } from "lib/comps/ui/typeahead";
|
import { Typeahead } from "lib/comps/ui/typeahead";
|
||||||
|
import { FC, useEffect } from "react";
|
||||||
|
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||||
|
|
||||||
export const TypeDropdown: FC<{
|
export const TypeDropdown: FC<{
|
||||||
field: FieldLocal;
|
field: FieldLocal;
|
||||||
|
|
@ -11,7 +11,7 @@ export const TypeDropdown: FC<{
|
||||||
}> = ({ field, fm, arg }) => {
|
}> = ({ field, fm, arg }) => {
|
||||||
const local = useLocal({
|
const local = useLocal({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
options: [],
|
options: [] as { value: string; label: string; data: any }[],
|
||||||
});
|
});
|
||||||
let value =
|
let value =
|
||||||
typeof arg.opt_get_value === "function"
|
typeof arg.opt_get_value === "function"
|
||||||
|
|
@ -22,6 +22,7 @@ export const TypeDropdown: FC<{
|
||||||
type: field.type,
|
type: field.type,
|
||||||
})
|
})
|
||||||
: fm.data[field.name];
|
: fm.data[field.name];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof arg.on_load === "function") {
|
if (typeof arg.on_load === "function") {
|
||||||
const options = arg.on_load({});
|
const options = arg.on_load({});
|
||||||
|
|
@ -38,6 +39,22 @@ export const TypeDropdown: FC<{
|
||||||
} else {
|
} else {
|
||||||
local.options = res;
|
local.options = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
field.type === "single-option" &&
|
||||||
|
!value &&
|
||||||
|
field.required &&
|
||||||
|
local.options.length > 0
|
||||||
|
) {
|
||||||
|
arg.opt_set_value({
|
||||||
|
fm,
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
options: local.options,
|
||||||
|
selected: [local.options[0]?.value],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
local.loaded = true;
|
local.loaded = true;
|
||||||
local.render();
|
local.render();
|
||||||
});
|
});
|
||||||
|
|
@ -48,12 +65,16 @@ export const TypeDropdown: FC<{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!local.loaded) return <FieldLoading />;
|
if (!local.loaded) return <FieldLoading />;
|
||||||
if (field.type === "single-option")
|
if (field.type === "single-option") {
|
||||||
|
if (value === null) {
|
||||||
|
fm.data[field.name] = undefined;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typeahead
|
<Typeahead
|
||||||
value={value}
|
value={Array.isArray(value) ? value : [value]}
|
||||||
onSelect={({ search, item }) => {
|
onSelect={({ search, item }) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
arg.opt_set_value({
|
arg.opt_set_value({
|
||||||
|
|
@ -77,6 +98,7 @@ export const TypeDropdown: FC<{
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ export const FieldTypeInput: FC<{
|
||||||
arg: FieldProp;
|
arg: FieldProp;
|
||||||
}> = ({ field, fm, prop, arg }) => {
|
}> = ({ field, fm, prop, arg }) => {
|
||||||
const input = useLocal({
|
const input = useLocal({
|
||||||
showHidePassword: false,
|
show_pass: false,
|
||||||
|
change_timeout: null as any,
|
||||||
});
|
});
|
||||||
let type_field = prop.sub_type;
|
let type_field = prop.sub_type;
|
||||||
switch (type_field) {
|
switch (type_field) {
|
||||||
|
|
@ -49,7 +50,7 @@ export const FieldTypeInput: FC<{
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.showHidePassword) {
|
if (input.show_pass) {
|
||||||
type_field = "text";
|
type_field = "text";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,13 +81,23 @@ export const FieldTypeInput: FC<{
|
||||||
value = Number(value) || null;
|
value = Number(value) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderOnChange = () => {
|
||||||
|
input.render();
|
||||||
|
if (field.on_change) {
|
||||||
|
field.on_change({ value: fm.data[field.name], name: field.name, fm });
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(input.change_timeout);
|
||||||
|
input.change_timeout = setTimeout(fm.render, 300);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{type_field === "textarea" ? (
|
{type_field === "textarea" ? (
|
||||||
<AutoHeightTextarea
|
<AutoHeightTextarea
|
||||||
onChange={(ev) => {
|
onChange={(ev) => {
|
||||||
fm.data[field.name] = ev.currentTarget.value;
|
fm.data[field.name] = ev.currentTarget.value;
|
||||||
fm.render();
|
renderOnChange();
|
||||||
}}
|
}}
|
||||||
value={value || ""}
|
value={value || ""}
|
||||||
disabled={field.disabled}
|
disabled={field.disabled}
|
||||||
|
|
@ -165,7 +176,7 @@ export const FieldTypeInput: FC<{
|
||||||
fm.data[field.name] = value?.startDate
|
fm.data[field.name] = value?.startDate
|
||||||
? new Date(value?.startDate)
|
? new Date(value?.startDate)
|
||||||
: null;
|
: null;
|
||||||
fm.render();
|
renderOnChange();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
@ -173,6 +184,7 @@ export const FieldTypeInput: FC<{
|
||||||
<div className="c-flex c-relative c-flex-1">
|
<div className="c-flex c-relative c-flex-1">
|
||||||
<input
|
<input
|
||||||
type={type_field}
|
type={type_field}
|
||||||
|
tabIndex={0}
|
||||||
onChange={(ev) => {
|
onChange={(ev) => {
|
||||||
if (["date", "datetime", "datetime-local"].includes(type_field)) {
|
if (["date", "datetime", "datetime-local"].includes(type_field)) {
|
||||||
let result = null;
|
let result = null;
|
||||||
|
|
@ -183,7 +195,7 @@ export const FieldTypeInput: FC<{
|
||||||
} else {
|
} else {
|
||||||
fm.data[field.name] = ev.currentTarget.value;
|
fm.data[field.name] = ev.currentTarget.value;
|
||||||
}
|
}
|
||||||
fm.render();
|
renderOnChange();
|
||||||
}}
|
}}
|
||||||
placeholder={arg.placeholder || ""}
|
placeholder={arg.placeholder || ""}
|
||||||
value={value}
|
value={value}
|
||||||
|
|
@ -195,6 +207,9 @@ export const FieldTypeInput: FC<{
|
||||||
display = "";
|
display = "";
|
||||||
field.render();
|
field.render();
|
||||||
}}
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" && fm.status === "ready") fm.submit();
|
||||||
|
}}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
field.focused = false;
|
field.focused = false;
|
||||||
field.render();
|
field.render();
|
||||||
|
|
@ -204,12 +219,12 @@ export const FieldTypeInput: FC<{
|
||||||
<div
|
<div
|
||||||
className="c-absolute c-right-0 c-h-full c-flex c-items-center c-cursor-pointer"
|
className="c-absolute c-right-0 c-h-full c-flex c-items-center c-cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
input.showHidePassword = !input.showHidePassword;
|
input.show_pass = !input.show_pass;
|
||||||
input.render();
|
input.render();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="">
|
<div className="">
|
||||||
{input.showHidePassword ? (
|
{input.show_pass ? (
|
||||||
<EyeIcon className="c-h-4" />
|
<EyeIcon className="c-h-4" />
|
||||||
) : (
|
) : (
|
||||||
<EyeOff className="c-h-4" />
|
<EyeOff className="c-h-4" />
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export const FieldMoney: FC<{
|
||||||
ref: null as any,
|
ref: null as any,
|
||||||
});
|
});
|
||||||
let display: any = null;
|
let display: any = null;
|
||||||
const money = formatMoney(Number(value) || 0)
|
const money = formatMoney(Number(value) || 0);
|
||||||
return (
|
return (
|
||||||
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
||||||
<div
|
<div
|
||||||
|
|
@ -42,6 +42,13 @@ export const FieldMoney: FC<{
|
||||||
onChange={(ev) => {
|
onChange={(ev) => {
|
||||||
fm.data[field.name] = ev.currentTarget.value;
|
fm.data[field.name] = ev.currentTarget.value;
|
||||||
fm.render();
|
fm.render();
|
||||||
|
if (field.on_change) {
|
||||||
|
field.on_change({
|
||||||
|
value: fm.data[field.name],
|
||||||
|
name: field.name,
|
||||||
|
fm,
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
value={value}
|
value={value}
|
||||||
disabled={field.disabled}
|
disabled={field.disabled}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ export const FieldRichText: FC<{
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (local.ref) {
|
if (local.ref) {
|
||||||
console.log(local.ref);
|
|
||||||
console.log(local.ref.current);
|
|
||||||
const q = new Quill(local.ref, {
|
const q = new Quill(local.ref, {
|
||||||
theme: "snow",
|
theme: "snow",
|
||||||
modules: {
|
modules: {
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,27 @@ export const FieldUpload: FC<{
|
||||||
value: 0 as any,
|
value: 0 as any,
|
||||||
display: false as any,
|
display: false as any,
|
||||||
ref: null as any,
|
ref: null as any,
|
||||||
drop: false as boolean
|
drop: false as boolean,
|
||||||
});
|
});
|
||||||
let display: any = null;
|
let display: any = null;
|
||||||
return (
|
return (
|
||||||
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
||||||
<div
|
<div
|
||||||
onDrop={(e: any) => {
|
onDrop={(e: any) => {
|
||||||
console.log({ e });
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
input.drop = false;
|
input.drop = false;
|
||||||
input.render();
|
input.render();
|
||||||
}}
|
}}
|
||||||
onDragOver={(e:any) => {
|
onDragOver={(e: any) => {
|
||||||
console.log("File(s) in drop zone");
|
|
||||||
|
|
||||||
// Prevent default behavior (Prevent file from being opened)
|
// Prevent default behavior (Prevent file from being opened)
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
input.drop = true;
|
input.drop = true;
|
||||||
input.render();
|
input.render();
|
||||||
}}
|
}}
|
||||||
className={cx(input.drop ? "c-bg-gray-100": "", "hover:c-bg-gray-100 c-m-1 c-relative c-flex-grow c-p-4 c-items-center c-flex c-flex-row c-text-gray-400 c-border c-border-gray-200 c-border-dashed c-rounded c-cursor-pointer")}
|
className={cx(
|
||||||
|
input.drop ? "c-bg-gray-100" : "",
|
||||||
|
"hover:c-bg-gray-100 c-m-1 c-relative c-flex-grow c-p-4 c-items-center c-flex c-flex-row c-text-gray-400 c-border c-border-gray-200 c-border-dashed c-rounded c-cursor-pointer"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className="c-flex-row c-flex c-flex-grow c-space-x-2">
|
<div className="c-flex-row c-flex c-flex-grow c-space-x-2">
|
||||||
<svg
|
<svg
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
import { generateSelect } from "lib/comps/md/gen/md-select";
|
import { generateSelect } from "lib/comps/md/gen/md-select";
|
||||||
import { on_load } from "lib/comps/md/gen/tbl-list/on_load";
|
|
||||||
import { createItem, parseGenField } from "lib/gen/utils";
|
import { createItem, parseGenField } from "lib/gen/utils";
|
||||||
import capitalize from "lodash.capitalize";
|
import capitalize from "lodash.capitalize";
|
||||||
import { ArrowBigDown } from "lucide-react";
|
|
||||||
import { on_load_rel } from "./on_load_rel";
|
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
|
||||||
import { gen_label } from "./gen-label";
|
import { gen_label } from "./gen-label";
|
||||||
import { get_value } from "./get-value";
|
import { generateRelation } from "./gen-rel";
|
||||||
import { set_value } from "./set-value";
|
|
||||||
import get from "lodash.get";
|
|
||||||
import { gen_rel_many } from "./gen-rel-many";
|
import { gen_rel_many } from "./gen-rel-many";
|
||||||
import { genTableEdit } from "./gen-table-edit";
|
import { get_value } from "./get-value";
|
||||||
|
import { on_load_rel } from "./on_load_rel";
|
||||||
|
import { set_value } from "./set-value";
|
||||||
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
export type GFCol = {
|
export type GFCol = {
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
|
@ -22,9 +19,9 @@ export type GFCol = {
|
||||||
fields: GFCol[];
|
fields: GFCol[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export const newField = (
|
export const newField = async (
|
||||||
arg: GFCol,
|
arg: GFCol,
|
||||||
opt: { parent_table: string; value: Array<string> },
|
opt: { parent_table: string; value: Array<string>; on_change?: string },
|
||||||
show_label: boolean
|
show_label: boolean
|
||||||
) => {
|
) => {
|
||||||
let show = typeof show_label === "boolean" ? show_label : true;
|
let show = typeof show_label === "boolean" ? show_label : true;
|
||||||
|
|
@ -43,6 +40,9 @@ export const newField = (
|
||||||
child: {
|
child: {
|
||||||
childs: [],
|
childs: [],
|
||||||
},
|
},
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -59,6 +59,9 @@ export const newField = (
|
||||||
child: {
|
child: {
|
||||||
childs: [],
|
childs: [],
|
||||||
},
|
},
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -73,6 +76,9 @@ export const newField = (
|
||||||
ext__show_label: show ? "y" : "n",
|
ext__show_label: show ? "y" : "n",
|
||||||
type: "single-option",
|
type: "single-option",
|
||||||
sub_type: "toogle",
|
sub_type: "toogle",
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -89,6 +95,9 @@ export const newField = (
|
||||||
child: {
|
child: {
|
||||||
childs: [],
|
childs: [],
|
||||||
},
|
},
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -102,6 +111,12 @@ export const newField = (
|
||||||
pks: {},
|
pks: {},
|
||||||
});
|
});
|
||||||
if (["has-one"].includes(arg.type)) {
|
if (["has-one"].includes(arg.type)) {
|
||||||
|
const rel__gen_fields = JSON.stringify(
|
||||||
|
arg.relation?.fields.map((e) => {
|
||||||
|
const v = (e as any).value;
|
||||||
|
return v;
|
||||||
|
})
|
||||||
|
);
|
||||||
return createItem({
|
return createItem({
|
||||||
component: {
|
component: {
|
||||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||||
|
|
@ -112,6 +127,7 @@ export const newField = (
|
||||||
ext__show_label: show ? "y" : "n",
|
ext__show_label: show ? "y" : "n",
|
||||||
sub_type: "dropdown",
|
sub_type: "dropdown",
|
||||||
rel__gen_table: arg.name,
|
rel__gen_table: arg.name,
|
||||||
|
rel__gen_fields: [rel__gen_fields, rel__gen_fields],
|
||||||
opt__on_load: [load],
|
opt__on_load: [load],
|
||||||
opt__label: [
|
opt__label: [
|
||||||
gen_label({
|
gen_label({
|
||||||
|
|
@ -137,6 +153,9 @@ export const newField = (
|
||||||
child: {
|
child: {
|
||||||
childs: [],
|
childs: [],
|
||||||
},
|
},
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -146,7 +165,30 @@ export const newField = (
|
||||||
arg,
|
arg,
|
||||||
rel: fields,
|
rel: fields,
|
||||||
});
|
});
|
||||||
if (result.on_load) {
|
|
||||||
|
let child: any = { childs: [] };
|
||||||
|
let rel__gen_fields: any = undefined;
|
||||||
|
let sub_type = "checkbox";
|
||||||
|
if (arg.relation?.fields?.length > 1) {
|
||||||
|
sub_type = "table-edit";
|
||||||
|
rel__gen_fields = JSON.stringify(
|
||||||
|
arg.relation?.fields.map((e) => {
|
||||||
|
const v = (e as any).value;
|
||||||
|
return v;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
child = createItem({
|
||||||
|
childs: await generateRelation(
|
||||||
|
{
|
||||||
|
rel__gen_fields: { value: rel__gen_fields },
|
||||||
|
rel__gen_table: { value: JSON.stringify(arg.name) },
|
||||||
|
sub_type: { value: "'table-edit'" },
|
||||||
|
},
|
||||||
|
createItem({}),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
return createItem({
|
return createItem({
|
||||||
component: {
|
component: {
|
||||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||||
|
|
@ -154,40 +196,23 @@ export const newField = (
|
||||||
name: arg.name,
|
name: arg.name,
|
||||||
label: formatName(arg.name),
|
label: formatName(arg.name),
|
||||||
type: "multi-option",
|
type: "multi-option",
|
||||||
sub_type: "checkbox",
|
sub_type,
|
||||||
rel__gen_table: arg.name,
|
rel__gen_table: arg.name,
|
||||||
opt__on_load: [result.on_load],
|
opt__on_load: [result.on_load],
|
||||||
ext__show_label: show ? "y" : "n",
|
ext__show_label: show ? "y" : "n",
|
||||||
opt__label: [result.get_label],
|
opt__label: [result.get_label],
|
||||||
opt__get_value: [result.get_value],
|
opt__get_value: [result.get_value],
|
||||||
opt__set_value: [result.set_value],
|
opt__set_value: [result.set_value],
|
||||||
child: {
|
rel__gen_fields: rel__gen_fields
|
||||||
childs: [],
|
? [rel__gen_fields, rel__gen_fields]
|
||||||
},
|
: undefined,
|
||||||
|
child,
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return createItem({
|
|
||||||
component: {
|
|
||||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
|
||||||
props: {
|
|
||||||
name: arg.name,
|
|
||||||
ext__show_label: show ? "y" : "n",
|
|
||||||
label: formatName(arg.name),
|
|
||||||
type: "-",
|
|
||||||
ext__width: "full",
|
|
||||||
sub_type: "-",
|
|
||||||
msg_error: `\
|
|
||||||
Select type (multi-option) and sub type (table-edit) ➡️ select table(${arg.name}) and fields ➡️ Click generate
|
|
||||||
`,
|
|
||||||
child: {
|
|
||||||
childs: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// type not found,
|
// type not found,
|
||||||
|
|
@ -203,6 +228,9 @@ export const newField = (
|
||||||
child: {
|
child: {
|
||||||
childs: [],
|
childs: [],
|
||||||
},
|
},
|
||||||
|
ext__on_change: opt.on_change
|
||||||
|
? [opt.on_change, opt.on_change]
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,15 @@ export const generateForm = async (
|
||||||
modify: (data: any) => void,
|
modify: (data: any) => void,
|
||||||
data: any,
|
data: any,
|
||||||
item: PrasiItem,
|
item: PrasiItem,
|
||||||
commit: boolean
|
commit: boolean,
|
||||||
|
is_md?: boolean
|
||||||
) => {
|
) => {
|
||||||
const table = data.gen__table.value as string;
|
let table = "" as string;
|
||||||
|
try {
|
||||||
|
table = eval(data.gen__table.value);
|
||||||
|
} catch (e) {
|
||||||
|
table = data.gen__table.value;
|
||||||
|
}
|
||||||
const raw_fields = JSON.parse(data.gen__fields.value) as (
|
const raw_fields = JSON.parse(data.gen__fields.value) as (
|
||||||
| string
|
| string
|
||||||
| { value: string; checked: string[] }
|
| { value: string; checked: string[] }
|
||||||
|
|
@ -34,21 +40,36 @@ export const generateForm = async (
|
||||||
if (data["on_load"]) {
|
if (data["on_load"]) {
|
||||||
result.on_load = {
|
result.on_load = {
|
||||||
mode: "raw",
|
mode: "raw",
|
||||||
value: on_load({ pk, table, select, pks }),
|
value: on_load({
|
||||||
|
pk,
|
||||||
|
table,
|
||||||
|
select,
|
||||||
|
pks,
|
||||||
|
opt: {
|
||||||
|
after_load: `
|
||||||
|
if (typeof md === "object") {
|
||||||
|
opt.fm.status = "ready";
|
||||||
|
md.render();
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (data["on_submit"]) {
|
if (data["on_submit"]) {
|
||||||
result.on_submit = {
|
result.on_submit = {
|
||||||
mode: "raw",
|
mode: "raw",
|
||||||
value: `\
|
value: `\
|
||||||
async ({ form, error }: IForm) => {
|
async ({ form, error, fm }: IForm) => {
|
||||||
let result = false;
|
let result = false;
|
||||||
try {
|
try {
|
||||||
|
if (typeof md !== "undefined") {
|
||||||
|
fm.status = "saving";
|
||||||
|
md.render();
|
||||||
|
}
|
||||||
|
|
||||||
const data = { ...form }; // data form
|
const data = { ...form }; // data form
|
||||||
const data_rel = ${JSON.stringify(
|
const data_rel = ${JSON.stringify(rel_many)} // list relasi has many
|
||||||
rel_many
|
|
||||||
)} // list relasi has many
|
|
||||||
const data_master = {} as Record<string, any> | any; // variabel untuk data master
|
const data_master = {} as Record<string, any> | any; // variabel untuk data master
|
||||||
const data_array = [] as Array<{
|
const data_array = [] as Array<{
|
||||||
table: string;
|
table: string;
|
||||||
|
|
@ -133,23 +154,47 @@ export const generateForm = async (
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof md !== "undefined") {
|
||||||
|
fm.status = "ready";
|
||||||
|
md.render();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IForm = { form: any; error: Record<string, string>; fm: FMLocal }
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (typeof is_md === "boolean" && is_md) {
|
||||||
|
result.on_init = {
|
||||||
|
mode: "raw",
|
||||||
|
value: `\
|
||||||
|
({ submit, reload, fm }: Init) => {
|
||||||
|
// on init
|
||||||
|
if (!isEditor) {
|
||||||
|
if (typeof md === "object") {
|
||||||
|
md.childs["form"] = {
|
||||||
|
fm: fm
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type IForm = { form: any; error: Record<string, string> }
|
type Init = { submit: () => Promise<boolean>; reload: () => void; fm: FMLocal }
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const childs = [];
|
const childs = [];
|
||||||
console.log({fields})
|
|
||||||
for (const item of fields.filter((e) => !e.is_pk)) {
|
for (const item of fields.filter((e) => !e.is_pk)) {
|
||||||
let value = [] as Array<string>;
|
let value = [] as Array<string>;
|
||||||
if (["has-one", "has-many"].includes(item.type)) {
|
if (["has-one", "has-many"].includes(item.type)) {
|
||||||
value = get(item, "value.checked") as any;
|
value = get(item, "value.checked") as any;
|
||||||
}
|
}
|
||||||
const field = newField(item, { parent_table: table, value }, true);
|
const field = await newField(item, { parent_table: table, value }, true);
|
||||||
childs.push(field);
|
childs.push(field);
|
||||||
}
|
}
|
||||||
|
if (typeof is_md === "boolean" && !is_md)
|
||||||
childs.push({
|
childs.push({
|
||||||
id: createId(),
|
id: createId(),
|
||||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||||
|
|
@ -303,11 +348,33 @@ export const generateForm = async (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
layout: { dir: "col", gap: 0, wrap: "flex-nowrap", align: "center" },
|
layout: {
|
||||||
|
dir: "col",
|
||||||
|
gap: 0,
|
||||||
|
wrap: "flex-nowrap",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
padding: { b: 10, l: 10, r: 10, t: 10 },
|
padding: { b: 10, l: 10, r: 10, t: 10 },
|
||||||
});
|
});
|
||||||
|
const body_prop = {
|
||||||
|
adv: {
|
||||||
|
js: "<div\n {...props}\n className={cx(\n props.className,\n css`\n align-content: start;`,\n )}\n>\n {children}\n</div>",
|
||||||
|
jsBuilt:
|
||||||
|
'render(/* @__PURE__ */ React.createElement(\n "div",\n {\n ...props,\n className: cx(\n props.className,\n css`\n align-content: start;`\n )\n },\n children\n));\n',
|
||||||
|
},
|
||||||
|
dim: {
|
||||||
|
h: "full",
|
||||||
|
w: "full",
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
dir: "row",
|
||||||
|
gap: 0,
|
||||||
|
wrap: "flex-wrap",
|
||||||
|
align: "top-left",
|
||||||
|
},
|
||||||
|
};
|
||||||
if (commit) {
|
if (commit) {
|
||||||
Object.keys(result).map((e) => {
|
Object.keys(result).map((e) => {
|
||||||
item.edit.setProp(e, result[e]);
|
item.edit.setProp(e, result[e]);
|
||||||
|
|
@ -316,12 +383,13 @@ export const generateForm = async (
|
||||||
mode: "jsx",
|
mode: "jsx",
|
||||||
value: createItem({
|
value: createItem({
|
||||||
name: "item",
|
name: "item",
|
||||||
|
...body_prop,
|
||||||
childs: childs,
|
childs: childs,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
await item.edit.commit();
|
await item.edit.commit();
|
||||||
} else {
|
} else {
|
||||||
console.log({ data });
|
set(data, "body.value", { ...data.body?.value, ...body_prop });
|
||||||
set(data, "body.value.childs", childs);
|
set(data, "body.value.childs", childs);
|
||||||
Object.keys(result).map((e) => {
|
Object.keys(result).map((e) => {
|
||||||
set(data, e, result[e]);
|
set(data, e, result[e]);
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,29 @@ export const gen_label = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return `\
|
return `\
|
||||||
(row: { value: string; label: string; item?: any }) => {
|
(row: { value: string; label: string; data?: any }) => {
|
||||||
const cols = ${JSON.stringify(cols)};
|
const cols = ${JSON.stringify(cols)};
|
||||||
|
|
||||||
if (isEditor) {
|
if (isEditor) {
|
||||||
return row.label;
|
return row.label;
|
||||||
}
|
}
|
||||||
const result = [];
|
const result = [];
|
||||||
if (!!row.item && !Array.isArray(row.item)) {
|
if (!!row.data && !row.label && !Array.isArray(row.data)) {
|
||||||
|
if(cols.length > 0){
|
||||||
cols.map((e) => {
|
cols.map((e) => {
|
||||||
if (row.item[e]) {
|
if (row.data[e]) {
|
||||||
result.push(row.item[e]);
|
result.push(row.data[e]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result.join(" - ");
|
return result.join(" - ");
|
||||||
|
} else {
|
||||||
|
const fields = parseGenField(rel__gen_fields);
|
||||||
|
return fields
|
||||||
|
.filter((e) => !e.is_pk)
|
||||||
|
.map((e) => row.data[e.name])
|
||||||
|
.filter((e) => e)
|
||||||
|
.join(" - ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return row.label;
|
return row.label;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ export const gen_rel_many = (prop: {
|
||||||
rel: any;
|
rel: any;
|
||||||
}) => {
|
}) => {
|
||||||
const { table_parent, arg, rel } = prop;
|
const { table_parent, arg, rel } = prop;
|
||||||
console.log({ rel });
|
|
||||||
const parent = rel.find((e: any) => e.name === table_parent);
|
const parent = rel.find((e: any) => e.name === table_parent);
|
||||||
const master = rel.find(
|
const master = rel.find(
|
||||||
(e: any) => e.name !== table_parent && e.type === "has-one"
|
(e: any) => e.name !== table_parent && e.type === "has-one"
|
||||||
|
|
@ -124,20 +123,29 @@ export const gen_rel_many = (prop: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const get_label = `\
|
const get_label = `\
|
||||||
(row: { value: string; label: string; item?: any }) => {
|
(row: { value: string; label: string; data?: any }) => {
|
||||||
const cols = ${JSON.stringify(cols)};
|
const cols = ${JSON.stringify(cols)};
|
||||||
|
|
||||||
if (isEditor) {
|
if (isEditor) {
|
||||||
return row.label;
|
return row.label;
|
||||||
}
|
}
|
||||||
const result = [];
|
const result = [];
|
||||||
if (!!row.item && !Array.isArray(row.item)) {
|
if (!!row.data && !row.label && !Array.isArray(row.data)) {
|
||||||
|
if(cols.length > 0){
|
||||||
cols.map((e) => {
|
cols.map((e) => {
|
||||||
if (row.item[e]) {
|
if (row.data[e]) {
|
||||||
result.push(row.item[e]);
|
result.push(row.data[e]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result.join(" - ");
|
return result.join(" - ");
|
||||||
|
} else {
|
||||||
|
const fields = parseGenField(rel__gen_fields);
|
||||||
|
return fields
|
||||||
|
.filter((e) => !e.is_pk)
|
||||||
|
.map((e) => row.data[e.name])
|
||||||
|
.filter((e) => e)
|
||||||
|
.join(" - ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return row.label;
|
return row.label;
|
||||||
}
|
}
|
||||||
|
|
@ -147,13 +155,13 @@ export const gen_rel_many = (prop: {
|
||||||
result.get_value = get_value;
|
result.get_value = get_value;
|
||||||
result.set_value = set_value;
|
result.set_value = set_value;
|
||||||
} else {
|
} else {
|
||||||
console.log("tidak punya master");
|
|
||||||
|
|
||||||
result.get_label = `\
|
result.get_label = `\
|
||||||
(row: { value: string; label: string; item?: any }) => {
|
(row: { value: string; label: string; item?: any }) => {
|
||||||
return row.label;
|
return row.label;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
result.get_value = `\
|
result.get_value = `\
|
||||||
(arg: {
|
(arg: {
|
||||||
options: { label: string; value: string; item?: string }[];
|
options: { label: string; value: string; item?: string }[];
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ export const generateRelation = async (
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
)) as any;
|
)) as any;
|
||||||
|
if (commit) {
|
||||||
item.edit.setProp("child", {
|
item.edit.setProp("child", {
|
||||||
mode: "jsx",
|
mode: "jsx",
|
||||||
value: {
|
value: {
|
||||||
|
|
@ -32,6 +33,12 @@ export const generateRelation = async (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await item.edit.commit();
|
await item.edit.commit();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(item.edit.props);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
import { generateSelect } from "lib/comps/md/gen/md-select";
|
import { generateSelect } from "lib/comps/md/gen/md-select";
|
||||||
import { createItem, parseGenField } from "lib/gen/utils";
|
import { createItem, parseGenField } from "lib/gen/utils";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
import { formatName, newField } from "./fields";
|
import { formatName, newField } from "./fields";
|
||||||
import { set } from "lib/utils/set";
|
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
|
||||||
|
|
||||||
export const genTableEdit = async (
|
export const genTableEdit = async (
|
||||||
item: PrasiItem,
|
item: PrasiItem,
|
||||||
|
|
@ -33,14 +32,23 @@ export const genTableEdit = async (
|
||||||
}
|
}
|
||||||
const childs = [] as Array<any>;
|
const childs = [] as Array<any>;
|
||||||
let first = true;
|
let first = true;
|
||||||
|
await Promise.all(
|
||||||
fields
|
fields
|
||||||
.map((e, idx) => {
|
.map(async (e, idx) => {
|
||||||
if (e.is_pk) return;
|
if (e.is_pk) return;
|
||||||
let value = [] as Array<string>;
|
let value = [] as Array<string>;
|
||||||
if (["has-one", "has-many"].includes(e.type)) {
|
if (["has-one", "has-many"].includes(e.type)) {
|
||||||
value = get(e, "value.checked") as any;
|
value = get(e, "value.checked") as any;
|
||||||
}
|
}
|
||||||
const field = newField(e, { parent_table: table, value }, false);
|
const field = await newField(
|
||||||
|
e,
|
||||||
|
{
|
||||||
|
parent_table: table,
|
||||||
|
value,
|
||||||
|
on_change: `() => { ext_fm.change(); }`,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
let tree_depth = "";
|
let tree_depth = "";
|
||||||
let tree_depth_built = "";
|
let tree_depth_built = "";
|
||||||
if (first) {
|
if (first) {
|
||||||
|
|
@ -61,13 +69,14 @@ export const genTableEdit = async (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.filter((e) => e) as any;
|
.filter((e) => e)
|
||||||
|
);
|
||||||
childs.push({
|
childs.push({
|
||||||
component: {
|
component: {
|
||||||
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||||
props: {
|
props: {
|
||||||
name: "option",
|
name: "option",
|
||||||
title: "option",
|
title: "",
|
||||||
child: {
|
child: {
|
||||||
id: createId(),
|
id: createId(),
|
||||||
name: "option",
|
name: "option",
|
||||||
|
|
@ -133,7 +142,11 @@ export const genTableEdit = async (
|
||||||
name: "new_text",
|
name: "new_text",
|
||||||
text: "",
|
text: "",
|
||||||
type: "text",
|
type: "text",
|
||||||
layout: { dir: "col", gap: 0, align: "center" },
|
layout: {
|
||||||
|
dir: "col",
|
||||||
|
gap: 0,
|
||||||
|
align: "left",
|
||||||
|
},
|
||||||
script: {},
|
script: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -240,7 +253,7 @@ export const genTableEdit = async (
|
||||||
name: "new_text",
|
name: "new_text",
|
||||||
text: "",
|
text: "",
|
||||||
type: "text",
|
type: "text",
|
||||||
layout: { dir: "col", gap: 0, align: "center" },
|
layout: { dir: "col", gap: 0, align: "left" },
|
||||||
script: {},
|
script: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -285,7 +298,7 @@ export const genTableEdit = async (
|
||||||
dir: "row",
|
dir: "row",
|
||||||
gap: 10,
|
gap: 10,
|
||||||
wrap: "flex-nowrap",
|
wrap: "flex-nowrap",
|
||||||
align: "top-left",
|
align: "left",
|
||||||
},
|
},
|
||||||
padding: { b: 0, l: 10, r: 10, t: 0 },
|
padding: { b: 0, l: 10, r: 10, t: 0 },
|
||||||
},
|
},
|
||||||
|
|
@ -304,6 +317,7 @@ export const genTableEdit = async (
|
||||||
name: "btn-submit",
|
name: "btn-submit",
|
||||||
type: "item",
|
type: "item",
|
||||||
edit: null as any,
|
edit: null as any,
|
||||||
|
padding: { b: 10, l: 10, r: 10, t: 0 },
|
||||||
childs: [
|
childs: [
|
||||||
{
|
{
|
||||||
id: createId(),
|
id: createId(),
|
||||||
|
|
@ -354,12 +368,17 @@ export const genTableEdit = async (
|
||||||
const option = {
|
const option = {
|
||||||
id: createId(),
|
id: createId(),
|
||||||
name: "bottom",
|
name: "bottom",
|
||||||
|
padding: { b: 10, l: 10, r: 10, t: 0 },
|
||||||
type: "item",
|
type: "item",
|
||||||
childs: [
|
childs: [
|
||||||
{
|
{
|
||||||
id: createId(),
|
id: createId(),
|
||||||
name: "bottom",
|
name: "wrapper",
|
||||||
type: "item",
|
type: "item",
|
||||||
|
dim: {
|
||||||
|
h: "fit",
|
||||||
|
w: "fit",
|
||||||
|
},
|
||||||
childs: [
|
childs: [
|
||||||
{
|
{
|
||||||
id: createId(),
|
id: createId(),
|
||||||
|
|
@ -380,7 +399,7 @@ export const genTableEdit = async (
|
||||||
variant: { value: ' "primary";\n' },
|
variant: { value: ' "primary";\n' },
|
||||||
on_click: {
|
on_click: {
|
||||||
value:
|
value:
|
||||||
' (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n console.log("masuk");\n ext_fm.add();\n }\n};\n',
|
' (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n ext_fm.add();\n }\n};\n',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -436,7 +455,7 @@ export const genTableEdit = async (
|
||||||
name: "new_text",
|
name: "new_text",
|
||||||
text: "",
|
text: "",
|
||||||
type: "text",
|
type: "text",
|
||||||
layout: { dir: "col", gap: 0, align: "center" },
|
layout: { dir: "col", gap: 0, align: "left" },
|
||||||
script: {},
|
script: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -456,9 +475,9 @@ export const genTableEdit = async (
|
||||||
],
|
],
|
||||||
layout: {
|
layout: {
|
||||||
dir: "row",
|
dir: "row",
|
||||||
gap: 10,
|
gap: 5,
|
||||||
wrap: "flex-nowrap",
|
wrap: "flex-nowrap",
|
||||||
align: "top-left",
|
align: "left",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -488,9 +507,9 @@ export const genTableEdit = async (
|
||||||
name: "prop_1",
|
name: "prop_1",
|
||||||
type: "string",
|
type: "string",
|
||||||
value:
|
value:
|
||||||
'(e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n console.log("masuk")\n ext_fm.add();\n // const value = fm.data[name] || [];\n // if (Array.isArray(value)) {\n // value.push({});\n // fm.render();\n // } else {\n // value = [];\n // fm.render();\n // }\n }\n}',
|
'(e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n ext_fm.add();\n }\n}',
|
||||||
valueBuilt:
|
valueBuilt:
|
||||||
' (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n console.log("masuk");\n ext_fm.add();\n }\n};\n',
|
' (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (typeof ext_fm === "object") {\n ext_fm.add();\n }\n};\n',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ref_ids: {},
|
ref_ids: {},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
export const get_value = ({
|
export const get_value = ({
|
||||||
pk,
|
pk,
|
||||||
table,
|
table,
|
||||||
select
|
select,
|
||||||
}: {
|
}: {
|
||||||
pk: string;
|
pk: string;
|
||||||
table: string;
|
table: string;
|
||||||
|
|
@ -15,12 +15,12 @@ export const get_value = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `\
|
return `\
|
||||||
(arg: {
|
(arg: {
|
||||||
options: { label: string; value: string; item?: string }[];
|
options: { label: string; value: string; item?: string }[];
|
||||||
fm: FMLocal;
|
fm: FMLocal;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { options, fm, name, type } = arg;
|
const { options, fm, name, type } = arg;
|
||||||
if(isEditor){
|
if(isEditor){
|
||||||
return fm.data[name];
|
return fm.data[name];
|
||||||
|
|
@ -32,13 +32,15 @@ export const get_value = ({
|
||||||
if(typeof data === "object"){
|
if(typeof data === "object"){
|
||||||
if(typeof data?.connect?.${pk} === "string"){
|
if(typeof data?.connect?.${pk} === "string"){
|
||||||
result = data.connect.${pk};
|
result = data.connect.${pk};
|
||||||
}else if (typeof data?.id === "string") {
|
} else if (typeof data?.id === "string") {
|
||||||
result = data.id;
|
result = data.id;
|
||||||
|
} else if (data?.disconnect === true) {
|
||||||
|
result = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(ex){
|
}catch(ex){
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ export const on_load = ({
|
||||||
select: any;
|
select: any;
|
||||||
pks: Record<string, string>;
|
pks: Record<string, string>;
|
||||||
opt?: {
|
opt?: {
|
||||||
before_load: string;
|
before_load?: string;
|
||||||
after_load: string;
|
after_load?: string;
|
||||||
};
|
};
|
||||||
}) => {
|
}) => {
|
||||||
const sample: any = {};
|
const sample: any = {};
|
||||||
|
|
@ -41,19 +41,19 @@ async (opt) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
${
|
${opt?.before_load ? opt.before_load : `let id = raw_id`}
|
||||||
opt?.before_load
|
|
||||||
? opt.before_load
|
|
||||||
: `let id = raw_id`
|
|
||||||
}
|
|
||||||
|
|
||||||
let item = {};
|
let item = {};
|
||||||
if (id){
|
let where = {
|
||||||
item = await db.${table}.findFirst({
|
|
||||||
where: {
|
|
||||||
${pk}: id,
|
${pk}: id,
|
||||||
},
|
};
|
||||||
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
if (id){
|
||||||
|
const table = db[gen__table] as any;
|
||||||
|
const fields = parseGenField(gen__fields);
|
||||||
|
|
||||||
|
const gen = generateSelect(fields);
|
||||||
|
item = await table?.findFirst({
|
||||||
|
where,
|
||||||
|
select: gen.select,
|
||||||
});
|
});
|
||||||
|
|
||||||
${opt?.after_load ? opt?.after_load : ""}
|
${opt?.after_load ? opt?.after_load : ""}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,20 @@ export const on_load_rel = ({
|
||||||
table,
|
table,
|
||||||
select,
|
select,
|
||||||
pks,
|
pks,
|
||||||
}: {
|
}: {
|
||||||
pk: string;
|
pk: string;
|
||||||
table: string;
|
table: string;
|
||||||
select: any;
|
select: any;
|
||||||
pks: Record<string, string>;
|
pks: Record<string, string>;
|
||||||
}) => {
|
}) => {
|
||||||
const sample = {
|
const sample = {
|
||||||
label: "sample",
|
label: "sample",
|
||||||
value: "sample",
|
value: "sample",
|
||||||
data: null
|
data: null,
|
||||||
} as any;
|
} as any;
|
||||||
const cols = [];
|
const cols = [];
|
||||||
for (const [k, v] of Object.entries(select) as any) {
|
for (const [k, v] of Object.entries(select) as any) {
|
||||||
if(k !== pk && typeof v !== "object"){
|
if (k !== pk && typeof v !== "object") {
|
||||||
cols.push(k);
|
cols.push(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -35,8 +35,14 @@ export const on_load_rel = ({
|
||||||
return await db.${table}.count();
|
return await db.${table}.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fields = parseGenField(rel__gen_fields);
|
||||||
|
const res = generateSelect(fields);
|
||||||
|
|
||||||
const items = await db.${table}.findMany({
|
const items = await db.${table}.findMany({
|
||||||
select: ${JSON.stringify(select)},
|
select: {
|
||||||
|
...${JSON.stringify(select)},
|
||||||
|
...(res?.select || {})
|
||||||
|
},
|
||||||
orderBy: arg.orderBy || {
|
orderBy: arg.orderBy || {
|
||||||
${pk}: "desc"
|
${pk}: "desc"
|
||||||
},
|
},
|
||||||
|
|
@ -53,18 +59,27 @@ export const on_load_rel = ({
|
||||||
})
|
})
|
||||||
return result.join(" - ");
|
return result.join(" - ");
|
||||||
}
|
}
|
||||||
done(items.map((e) => {
|
|
||||||
|
let blank: any = undefined;
|
||||||
|
if (ext__required !== "y") {
|
||||||
|
blank = { value: undefined, label: "", data: {} };
|
||||||
|
}
|
||||||
|
done(
|
||||||
|
[
|
||||||
|
blank,
|
||||||
|
...items.map((e) => {
|
||||||
return {
|
return {
|
||||||
value: e.${pk},
|
value: e.${pk},
|
||||||
label: getLabel(e),
|
label: getLabel(e),
|
||||||
data: e,
|
data: e,
|
||||||
}
|
};
|
||||||
}))
|
}),
|
||||||
|
].filter((e) => e),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
done([])
|
done([])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,17 @@ export const set_value = ({
|
||||||
}) => {
|
}) => {
|
||||||
const { selected, options, fm, name, type } = arg;
|
const { selected, options, fm, name, type } = arg;
|
||||||
if (type === "single-option") {
|
if (type === "single-option") {
|
||||||
|
if (selected[0]) {
|
||||||
fm.data[name] = {
|
fm.data[name] = {
|
||||||
connect: {
|
connect: {
|
||||||
${pk}: selected[0],
|
${pk}: selected[0],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
fm.data[name] = {
|
||||||
|
disconnect: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fm.data[name] = selected.map((e) => e);
|
fm.data[name] = selected.map((e) => e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ export type FMProps = {
|
||||||
gen_fields: any;
|
gen_fields: any;
|
||||||
gen_table: string;
|
gen_table: string;
|
||||||
on_load_deps?: any[];
|
on_load_deps?: any[];
|
||||||
|
feature?: any[];
|
||||||
|
sfd_field?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GenField =
|
export type GenField =
|
||||||
|
|
@ -87,7 +89,8 @@ export type FieldProp = {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
show_label: boolean;
|
show_label: boolean;
|
||||||
msg_error: string;
|
msg_error: string;
|
||||||
gen_table: string;
|
gen_table?: string;
|
||||||
|
gen_fields?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FMInternal = {
|
export type FMInternal = {
|
||||||
|
|
@ -125,6 +128,9 @@ export type FMInternal = {
|
||||||
height: number;
|
height: number;
|
||||||
field: "full" | "half";
|
field: "full" | "half";
|
||||||
};
|
};
|
||||||
|
soft_delete: {
|
||||||
|
field: any;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
export type FMLocal = FMInternal & { render: () => void };
|
export type FMLocal = FMInternal & { render: () => void };
|
||||||
|
|
||||||
|
|
@ -150,6 +156,7 @@ export type FieldInternal<T extends FieldProp["type"]> = {
|
||||||
options: {
|
options: {
|
||||||
on_load?: () => Promise<{ value: string; label: string }[]>;
|
on_load?: () => Promise<{ value: string; label: string }[]>;
|
||||||
};
|
};
|
||||||
|
on_change?: (arg: { value: any, name: string, fm: FMLocal }) => void | Promise<void>;
|
||||||
prop?: any;
|
prop?: any;
|
||||||
};
|
};
|
||||||
export type FieldLocal = FieldInternal<any> & {
|
export type FieldLocal = FieldInternal<any> & {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
}
|
}
|
||||||
const { on_load, sonar } = fm.props;
|
const { on_load, sonar } = fm.props;
|
||||||
fm.error = formError(fm);
|
fm.error = formError(fm);
|
||||||
|
|
||||||
fm.field_def = {};
|
fm.field_def = {};
|
||||||
const defs = parseGenField(fm.props.gen_fields);
|
const defs = parseGenField(fm.props.gen_fields);
|
||||||
for (const d of defs) {
|
for (const d of defs) {
|
||||||
|
|
@ -110,7 +109,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof fm.props.on_submit === "function") {
|
if (typeof fm.props.on_submit === "function") {
|
||||||
if (fm.props.sonar === "on") {
|
if (fm.props.sonar === "on" && !isEditor) {
|
||||||
toast.loading(
|
toast.loading(
|
||||||
<>
|
<>
|
||||||
<Loader2 className="c-h-4 c-w-4 c-animate-spin" />
|
<Loader2 className="c-h-4 c-w-4 c-animate-spin" />
|
||||||
|
|
@ -126,7 +125,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
|
|
||||||
toast.dismiss();
|
toast.dismiss();
|
||||||
done_all(success);
|
done_all(success);
|
||||||
if (fm.props.sonar === "on") {
|
if (fm.props.sonar === "on" && !isEditor) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
toast.dismiss();
|
toast.dismiss();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export const useField = (
|
||||||
required: required === "y",
|
required: required === "y",
|
||||||
required_msg: arg.required_msg,
|
required_msg: arg.required_msg,
|
||||||
disabled: arg.disabled === "y",
|
disabled: arg.disabled === "y",
|
||||||
|
on_change: arg.on_change,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (field.status === "init" || isEditor) {
|
if (field.status === "init" || isEditor) {
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,27 @@ import { fields_map } from "@/utils/format-value";
|
||||||
import { useLocal } from "@/utils/use-local";
|
import { useLocal } from "@/utils/use-local";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { ChangeEvent, FC, MouseEvent, ReactNode, useEffect } from "react";
|
import {
|
||||||
|
ChangeEvent,
|
||||||
|
FC,
|
||||||
|
MouseEvent,
|
||||||
|
ReactElement,
|
||||||
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
import DataGrid, {
|
import DataGrid, {
|
||||||
ColumnOrColumnGroup,
|
ColumnOrColumnGroup,
|
||||||
|
RenderCellProps,
|
||||||
Row,
|
Row,
|
||||||
SELECT_COLUMN_KEY,
|
SELECT_COLUMN_KEY,
|
||||||
SortColumn,
|
SortColumn,
|
||||||
} from "react-data-grid";
|
} from "react-data-grid";
|
||||||
import "./TableList.css";
|
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { Toaster, toast } from "sonner";
|
import { Toaster, toast } from "sonner";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
|
||||||
import { sortTree } from "./utils/sort-tree";
|
|
||||||
import { filterWhere } from "../filter/utils/filter-where";
|
import { filterWhere } from "../filter/utils/filter-where";
|
||||||
|
import { Skeleton } from "../ui/skeleton";
|
||||||
|
import "./TableList.css";
|
||||||
|
import { sortTree } from "./utils/sort-tree";
|
||||||
|
|
||||||
type OnRowClick = (arg: {
|
type OnRowClick = (arg: {
|
||||||
row: any;
|
row: any;
|
||||||
|
|
@ -38,7 +46,6 @@ type TableListProp = {
|
||||||
}) => Promise<any[]>;
|
}) => Promise<any[]>;
|
||||||
on_init: (arg?: any) => any;
|
on_init: (arg?: any) => any;
|
||||||
mode: "table" | "list" | "grid" | "auto";
|
mode: "table" | "list" | "grid" | "auto";
|
||||||
// _meta: Record<string, any>;
|
|
||||||
_item: PrasiItem;
|
_item: PrasiItem;
|
||||||
gen_fields: string[];
|
gen_fields: string[];
|
||||||
row_click: OnRowClick;
|
row_click: OnRowClick;
|
||||||
|
|
@ -47,10 +54,16 @@ type TableListProp = {
|
||||||
feature?: Array<any>;
|
feature?: Array<any>;
|
||||||
filter_name: string;
|
filter_name: string;
|
||||||
render_row?: (child: any, data: any) => ReactNode;
|
render_row?: (child: any, data: any) => ReactNode;
|
||||||
rowHeight?: number;
|
row_height?: number;
|
||||||
render_col?: (props: any) => ReactNode;
|
render_col?: (arg: {
|
||||||
soft_delete_field: string;
|
props: RenderCellProps<any, unknown>;
|
||||||
|
tbl: any;
|
||||||
|
child: any;
|
||||||
|
}) => ReactNode;
|
||||||
|
softdel_field?: string;
|
||||||
|
gen_table?: string;
|
||||||
|
softdel_type?: string;
|
||||||
|
cache_row?: boolean;
|
||||||
};
|
};
|
||||||
const w = window as any;
|
const w = window as any;
|
||||||
const selectCellClassname = css`
|
const selectCellClassname = css`
|
||||||
|
|
@ -77,11 +90,12 @@ export const TableList: FC<TableListProp> = ({
|
||||||
feature,
|
feature,
|
||||||
filter_name,
|
filter_name,
|
||||||
render_row,
|
render_row,
|
||||||
rowHeight,
|
row_height: rowHeight,
|
||||||
render_col,
|
render_col,
|
||||||
value
|
value,
|
||||||
|
cache_row,
|
||||||
}) => {
|
}) => {
|
||||||
const where = get(w, `prasi_filter.${filter_name}`) ?? "hello";
|
const where = get(w, `prasi_filter.${filter_name}`) ? {} : {};
|
||||||
const whereQuery = filterWhere("hello");
|
const whereQuery = filterWhere("hello");
|
||||||
if (mode === "auto") {
|
if (mode === "auto") {
|
||||||
if (w.isMobile) {
|
if (w.isMobile) {
|
||||||
|
|
@ -124,13 +138,13 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
cached_row: new WeakMap<any, ReactElement>(),
|
||||||
sort: {
|
sort: {
|
||||||
columns: [] as SortColumn[],
|
columns: [] as SortColumn[],
|
||||||
on_change: (cols: SortColumn[]) => {
|
on_change: (cols: SortColumn[]) => {
|
||||||
if (feature?.find((e) => e === "sorting")) {
|
if (feature?.find((e) => e === "sorting")) {
|
||||||
local.sort.columns = cols;
|
local.sort.columns = cols;
|
||||||
local.paging.skip = 0;
|
local.paging.skip = 0;
|
||||||
|
|
||||||
if (cols.length > 0) {
|
if (cols.length > 0) {
|
||||||
const { columnKey, direction } = cols[0];
|
const { columnKey, direction } = cols[0];
|
||||||
|
|
||||||
|
|
@ -179,14 +193,18 @@ export const TableList: FC<TableListProp> = ({
|
||||||
"asc" | "desc" | Record<string, "asc" | "desc">
|
"asc" | "desc" | Record<string, "asc" | "desc">
|
||||||
>,
|
>,
|
||||||
},
|
},
|
||||||
|
soft_delete: {
|
||||||
|
field: null as any,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if(typeof value !== "undefined"){
|
|
||||||
local.data = value;
|
|
||||||
}
|
|
||||||
// code ini digunakan untuk mengambil nama dari pk yang akan digunakan sebagai key untuk id
|
// code ini digunakan untuk mengambil nama dari pk yang akan digunakan sebagai key untuk id
|
||||||
const pk = local.pk?.name || "id";
|
const pk = local.pk?.name || "id";
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditor) return;
|
if (isEditor || value) {
|
||||||
|
on_init(local);
|
||||||
|
return;
|
||||||
|
}
|
||||||
(async () => {
|
(async () => {
|
||||||
on_init(local);
|
on_init(local);
|
||||||
if (local.status === "reload" && typeof on_load === "function") {
|
if (local.status === "reload" && typeof on_load === "function") {
|
||||||
|
|
@ -198,7 +216,10 @@ export const TableList: FC<TableListProp> = ({
|
||||||
async reload() {},
|
async reload() {},
|
||||||
where,
|
where,
|
||||||
orderBy,
|
orderBy,
|
||||||
paging: { take: local.paging.take, skip: local.paging.skip },
|
paging: {
|
||||||
|
take: local.paging.take > 0 ? local.paging.take : undefined,
|
||||||
|
skip: local.paging.skip,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if (id_parent) {
|
if (id_parent) {
|
||||||
load_args.paging = {};
|
load_args.paging = {};
|
||||||
|
|
@ -218,6 +239,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [local.status, on_load, local.sort.orderBy]);
|
}, [local.status, on_load, local.sort.orderBy]);
|
||||||
|
|
||||||
const raw_childs = get(
|
const raw_childs = get(
|
||||||
child,
|
child,
|
||||||
"props.meta.item.component.props.child.content.childs"
|
"props.meta.item.component.props.child.content.childs"
|
||||||
|
|
@ -341,7 +363,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
for (const child of childs) {
|
for (const child of childs) {
|
||||||
let key = getProp(child, "name", {});
|
let key = getProp(child, "name", {});
|
||||||
const name = getProp(child, "title", {});
|
const name = getProp(child, "title", "");
|
||||||
const width = parseInt(getProp(child, "width", {}));
|
const width = parseInt(getProp(child, "width", {}));
|
||||||
|
|
||||||
columns.push({
|
columns.push({
|
||||||
|
|
@ -352,7 +374,12 @@ export const TableList: FC<TableListProp> = ({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
renderCell(props) {
|
renderCell(props) {
|
||||||
if (typeof render_col === "function")
|
if (typeof render_col === "function")
|
||||||
return render_col({ props, tbl: local, child });
|
return render_col({
|
||||||
|
props,
|
||||||
|
tbl: local,
|
||||||
|
child,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PassProp
|
<PassProp
|
||||||
idx={props.rowIdx}
|
idx={props.rowIdx}
|
||||||
|
|
@ -389,9 +416,6 @@ export const TableList: FC<TableListProp> = ({
|
||||||
</>,
|
</>,
|
||||||
{
|
{
|
||||||
dismissible: true,
|
dismissible: true,
|
||||||
className: css`
|
|
||||||
background: #e4f7ff;
|
|
||||||
`,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -414,15 +438,20 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(typeof value === "undefined")
|
if (typeof value !== "undefined") {
|
||||||
|
local.data = value;
|
||||||
|
local.status = "ready" as any;
|
||||||
|
} else {
|
||||||
if (isEditor && local.status !== "ready") {
|
if (isEditor && local.status !== "ready") {
|
||||||
if (local.data.length === 0) {
|
if (local.data.length === 0) {
|
||||||
const load_args: any = {
|
const load_args: any = {
|
||||||
async reload() {},
|
async reload() {},
|
||||||
where,
|
where,
|
||||||
paging: { take: local.paging.take, skip: local.paging.skip },
|
paging: {
|
||||||
|
take: local.paging.take > 0 ? local.paging.take : undefined,
|
||||||
|
skip: local.paging.skip,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (id_parent) load_args.paging = {};
|
if (id_parent) load_args.paging = {};
|
||||||
if (typeof on_load === "function") {
|
if (typeof on_load === "function") {
|
||||||
local.data = on_load({ ...load_args, mode: "query" }) as any;
|
local.data = on_load({ ...load_args, mode: "query" }) as any;
|
||||||
|
|
@ -430,9 +459,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
local.status = "ready";
|
local.status = "ready";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let selected_idx = -1;
|
|
||||||
|
|
||||||
let data = local.data || [];
|
let data = local.data || [];
|
||||||
if (id_parent && local.pk && local.sort.columns.length === 0) {
|
if (id_parent && local.pk && local.sort.columns.length === 0) {
|
||||||
|
|
@ -498,12 +525,20 @@ export const TableList: FC<TableListProp> = ({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rows={data}
|
rows={data}
|
||||||
onScroll={local.paging.scroll}
|
onScroll={local.paging.scroll}
|
||||||
|
selectedRows={new Set() as ReadonlySet<any>}
|
||||||
|
onSelectedCellChange={() => {}}
|
||||||
|
onSelectedRowsChange={() => {}}
|
||||||
renderers={
|
renderers={
|
||||||
local.status !== "ready"
|
local.status !== "ready"
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
renderRow(key, props) {
|
renderRow(key, props) {
|
||||||
const is_selected = selected_idx === props.rowIdx;
|
if (
|
||||||
|
cache_row === true &&
|
||||||
|
local.cached_row.has(props.row)
|
||||||
|
) {
|
||||||
|
return local.cached_row.get(props.row);
|
||||||
|
}
|
||||||
const isSelect = selected({
|
const isSelect = selected({
|
||||||
idx: props.rowIdx,
|
idx: props.rowIdx,
|
||||||
row: props.row,
|
row: props.row,
|
||||||
|
|
@ -533,16 +568,10 @@ export const TableList: FC<TableListProp> = ({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
if (typeof render_row === "function") {
|
if (cache_row) {
|
||||||
return render_row(child_row, props.row);
|
local.cached_row.set(props.row, child_row);
|
||||||
}
|
}
|
||||||
// return child_row;
|
return child_row;
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="c-contents">{child_row}</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
noRowsFallback: (
|
noRowsFallback: (
|
||||||
<div className="c-flex-1 c-w-full absolute inset-0 c-flex c-flex-col c-items-center c-justify-center">
|
<div className="c-flex-1 c-w-full absolute inset-0 c-flex c-flex-col c-items-center c-justify-center">
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import {
|
||||||
import { MDLocalInternal, MDProps } from "./utils/typings";
|
import { MDLocalInternal, MDProps } from "./utils/typings";
|
||||||
import { mdRenderLoop } from "./utils/md-render-loop";
|
import { mdRenderLoop } from "./utils/md-render-loop";
|
||||||
import { parseGenField } from "lib/gen/utils";
|
import { parseGenField } from "lib/gen/utils";
|
||||||
import { NDT } from "src/data/timezoneNames";
|
|
||||||
import { mdBread } from "./utils/md-bread";
|
|
||||||
|
|
||||||
export const MasterDetail: FC<MDProps> = (arg) => {
|
export const MasterDetail: FC<MDProps> = (arg) => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -34,10 +32,9 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
||||||
name,
|
name,
|
||||||
status: isEditor ? "init" : "ready",
|
status: isEditor ? "init" : "ready",
|
||||||
actions: [],
|
actions: [],
|
||||||
breadcrumb: {
|
header: {
|
||||||
list: [],
|
breadcrumb: [],
|
||||||
render: () => {},
|
render: () => {},
|
||||||
reload: () => {}
|
|
||||||
},
|
},
|
||||||
selected: null,
|
selected: null,
|
||||||
tab: {
|
tab: {
|
||||||
|
|
@ -83,7 +80,7 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
||||||
md.status = "ready";
|
md.status = "ready";
|
||||||
const fields = parseGenField(gen_fields);
|
const fields = parseGenField(gen_fields);
|
||||||
const pk = fields.find((e) => e.is_pk);
|
const pk = fields.find((e) => e.is_pk);
|
||||||
md.pk = pk
|
md.pk = pk;
|
||||||
md.params.parse();
|
md.params.parse();
|
||||||
if (pk) {
|
if (pk) {
|
||||||
const value = md.params.hash[md.name];
|
const value = md.params.hash[md.name];
|
||||||
|
|
@ -92,13 +89,12 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
||||||
const tab = md.params.tabs[md.name];
|
const tab = md.params.tabs[md.name];
|
||||||
if (tab && md.tab.list.includes(tab)) {
|
if (tab && md.tab.list.includes(tab)) {
|
||||||
md.tab.active = tab;
|
md.tab.active = tab;
|
||||||
}else{
|
} else {
|
||||||
md.tab.active = "detail"
|
md.tab.active = "detail";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
md.breadcrumb.reload();
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ export const generateTableList = async (
|
||||||
) => {
|
) => {
|
||||||
let table = "" as string;
|
let table = "" as string;
|
||||||
try {
|
try {
|
||||||
table = eval(data.gen_table.value);
|
table = eval(data.gen__table.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
table = data.gen_table.value;
|
table = data.gen__table.value;
|
||||||
}
|
}
|
||||||
const raw_fields = JSON.parse(data.gen_fields.value) as (
|
const raw_fields = JSON.parse(data.gen__fields.value) as (
|
||||||
| string
|
| string
|
||||||
| { value: string; checked: string[] }
|
| { value: string; checked: string[] }
|
||||||
)[];
|
)[];
|
||||||
|
|
@ -53,7 +53,7 @@ export const generateTableList = async (
|
||||||
if (data["opt__on_load"]) {
|
if (data["opt__on_load"]) {
|
||||||
result.opt__on_load = {
|
result.opt__on_load = {
|
||||||
mode: "raw",
|
mode: "raw",
|
||||||
value: on_load({ pk, table, select, pks }),
|
value: on_load({ pk, table, select, pks,fields }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
@ -91,10 +91,10 @@ export const generateTableList = async (
|
||||||
adv: {
|
adv: {
|
||||||
js: `\
|
js: `\
|
||||||
<div {...props} className={cx(props.className, "")}>
|
<div {...props} className={cx(props.className, "")}>
|
||||||
${arg.mode === "list" ? "{JSON.stringify(row)}" : "<FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />"}
|
${arg.mode === "list" ? "{JSON.stringify(row)}" : `<FormatValue value={col.value} name={col.name} gen_fields={gen__fields} ${tree_depth} />`}
|
||||||
</div>`,
|
</div>`,
|
||||||
jsBuilt: `\
|
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} })));
|
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} })));
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export const generateMDForm = async (
|
||||||
props,
|
props,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
generateForm(async (props: any) => {}, props, tablelist, false);
|
generateForm(async (props: any) => {}, props, tablelist, false, true);
|
||||||
tab_detail?.edit.setProp("breadcrumb", {
|
tab_detail?.edit.setProp("breadcrumb", {
|
||||||
mode: "raw",
|
mode: "raw",
|
||||||
value: `\
|
value: `\
|
||||||
|
|
@ -93,14 +93,7 @@ export const generateMDForm = async (
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
console.log({form: {
|
|
||||||
type: "item",
|
|
||||||
name: "item",
|
|
||||||
component: {
|
|
||||||
id: "c4e65c26-4f36-48aa-a5b3-0771feac082e",
|
|
||||||
props,
|
|
||||||
},
|
|
||||||
}})
|
|
||||||
tab_detail?.edit.setChilds([
|
tab_detail?.edit.setChilds([
|
||||||
{
|
{
|
||||||
type: "item",
|
type: "item",
|
||||||
|
|
|
||||||
|
|
@ -36,5 +36,4 @@ export const generateMasterDetail: GenFn<{ item: PrasiItem, table: string, field
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
await item.edit.commit();
|
await item.edit.commit();
|
||||||
console.log({item})
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
import { formatName } from "lib/comps/form/gen/fields";
|
||||||
import { createItem } from "lib/gen/utils";
|
import { createItem } from "lib/gen/utils";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
import { generateTableList } from "./gen-table-list";
|
import { generateTableList } from "./gen-table-list";
|
||||||
import { formatName } from "lib/comps/form/gen/fields";
|
|
||||||
|
|
||||||
export const generateList = async (
|
export const generateList = async (
|
||||||
arg: { item: PrasiItem; table: string; fields: any },
|
arg: { item: PrasiItem; table: string; fields: any },
|
||||||
|
|
@ -13,7 +13,7 @@ export const generateList = async (
|
||||||
(e) => get(e, "component.id") === "c68415ca-dac5-44fe-aeb6-936caf8cc491"
|
(e) => get(e, "component.id") === "c68415ca-dac5-44fe-aeb6-936caf8cc491"
|
||||||
);
|
);
|
||||||
const props: Record<string, PropVal> = {
|
const props: Record<string, PropVal> = {
|
||||||
gen_table: {
|
gen__table: {
|
||||||
mode: "string",
|
mode: "string",
|
||||||
value: `"${arg.table}"`,
|
value: `"${arg.table}"`,
|
||||||
},
|
},
|
||||||
|
|
@ -77,7 +77,7 @@ rows: any[];
|
||||||
idx: any;
|
idx: any;
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
gen_fields: {
|
gen__fields: {
|
||||||
mode: "raw",
|
mode: "raw",
|
||||||
value: `${JSON.stringify(arg.fields)}`,
|
value: `${JSON.stringify(arg.fields)}`,
|
||||||
},
|
},
|
||||||
|
|
@ -117,22 +117,17 @@ idx: any;
|
||||||
url?: string;
|
url?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
})
|
});
|
||||||
console.log({
|
|
||||||
|
tab_master?.edit.setChilds([
|
||||||
|
{
|
||||||
type: "item",
|
type: "item",
|
||||||
name: "item",
|
name: "item",
|
||||||
component: {
|
component: {
|
||||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||||
props,
|
props,
|
||||||
},
|
},
|
||||||
})
|
|
||||||
tab_master?.edit.setChilds([ {
|
|
||||||
type: "item",
|
|
||||||
name: "item",
|
|
||||||
component: {
|
|
||||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
|
||||||
props,
|
|
||||||
},
|
},
|
||||||
}]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,22 @@ export const generateSelect = (data: Array<any>) => {
|
||||||
select: {},
|
select: {},
|
||||||
};
|
};
|
||||||
for (const r of f.relation.fields) {
|
for (const r of f.relation.fields) {
|
||||||
|
if (r.type === "has-one") {
|
||||||
|
select[f.name].select[r.name] = { select: {} };
|
||||||
|
for (const rel of r.relation.fields) {
|
||||||
|
select[f.name].select[r.name].select[rel.name] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
select[f.name].select[r.name] = true;
|
select[f.name].select[r.name] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (f.is_pk) {
|
if (f.is_pk) {
|
||||||
pk = f.name;
|
pk = f.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pk,
|
pk,
|
||||||
select,
|
select,
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,31 @@ export const on_load = ({
|
||||||
table,
|
table,
|
||||||
select,
|
select,
|
||||||
pks,
|
pks,
|
||||||
}: {
|
fields,
|
||||||
|
}: {
|
||||||
pk: string;
|
pk: string;
|
||||||
table: string;
|
table: string;
|
||||||
select: any;
|
select: any;
|
||||||
pks: Record<string, string>;
|
pks: Record<string, string>;
|
||||||
}) => {
|
fields: Array<any>;
|
||||||
|
}) => {
|
||||||
const sample = {} as any;
|
const sample = {} as any;
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(select) as any) {
|
for (const [k, v] of Object.entries(select) as any) {
|
||||||
if (typeof v === "object") {
|
if (typeof v === "object") {
|
||||||
sample[k] = {};
|
const val = {} as any;
|
||||||
|
|
||||||
Object.keys(v.select)
|
Object.keys(v.select)
|
||||||
.filter((e) => e !== pks[k])
|
.filter((e) => e !== pks[k])
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
sample[k][e] = "sample";
|
val[e] = "sample";
|
||||||
});
|
});
|
||||||
|
const field = fields.find((e) => e.name === k);
|
||||||
|
sample[k] = val;
|
||||||
|
if(field){
|
||||||
|
if(field.type === "has-many"){
|
||||||
|
sample[k] = [val];
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sample[k] = "sample";
|
sample[k] = "sample";
|
||||||
}
|
}
|
||||||
|
|
@ -30,15 +38,30 @@ export const on_load = ({
|
||||||
if (isEditor) return [${JSON.stringify(sample)}];
|
if (isEditor) return [${JSON.stringify(sample)}];
|
||||||
|
|
||||||
return new Promise(async (done) => {
|
return new Promise(async (done) => {
|
||||||
|
let where = arg.where;
|
||||||
|
try {
|
||||||
|
if (!isEditor)
|
||||||
|
where = softDeleteFilter(where, {
|
||||||
|
feature: opt__feature,
|
||||||
|
field: sft__fields,
|
||||||
|
type: sft__type,
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
if (arg.mode === 'count') {
|
if (arg.mode === 'count') {
|
||||||
return await db.${table}.count();
|
return await db.${table}.count({
|
||||||
|
where: {
|
||||||
|
...where,
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = await db.${table}.findMany({
|
const items = await db.${table}.findMany({
|
||||||
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
||||||
orderBy: arg.orderBy || {
|
orderBy: arg.orderBy || {
|
||||||
${pk}: "desc"
|
${pk}: "desc"
|
||||||
},
|
},
|
||||||
|
where: {
|
||||||
|
...where,
|
||||||
|
},
|
||||||
...arg.paging,
|
...arg.paging,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -54,5 +77,4 @@ export const on_load = ({
|
||||||
where?: any
|
where?: any
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ export const MDDetail: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
||||||
if (!detail) {
|
if (!detail) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
console.log(md.tab.list);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{md.props.show_head === "only-child" && <MDHeader md={md} mdr={mdr} />}
|
{md.props.show_head === "only-child" && <MDHeader md={md} mdr={mdr} />}
|
||||||
|
|
@ -116,10 +115,8 @@ export const MDRenderTab: FC<{
|
||||||
}> = ({ child, on_init, breadcrumb }) => {
|
}> = ({ child, on_init, breadcrumb }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let md = on_init();
|
let md = on_init();
|
||||||
md.breadcrumb.list = breadcrumb();
|
md.header.breadcrumb = breadcrumb();
|
||||||
if (!isEditor) {
|
md.header.render();
|
||||||
md.breadcrumb.reload();
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
return <>{child}</>;
|
return <>{child}</>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { FC } from "react";
|
import { FC, useState } from "react";
|
||||||
import { MDLocal, MDRef } from "../utils/typings";
|
import { MDLocal, MDRef } from "../utils/typings";
|
||||||
|
|
||||||
export const MDHeader: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
export const MDHeader: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
||||||
|
const [_, set] = useState({});
|
||||||
const head = mdr.item.edit.props?.header.value;
|
const head = mdr.item.edit.props?.header.value;
|
||||||
const PassProp = mdr.PassProp;
|
const PassProp = mdr.PassProp;
|
||||||
|
md.header.render = () => set({});
|
||||||
return <PassProp md={md}>{head}</PassProp>;
|
return <PassProp md={md}>{head}</PassProp>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ export const MDRenderMaster: FC<{
|
||||||
min_size: any;
|
min_size: any;
|
||||||
child: any;
|
child: any;
|
||||||
on_init: () => MDLocal;
|
on_init: () => MDLocal;
|
||||||
breadcrumb: () => Array<any>
|
breadcrumb: () => Array<any>;
|
||||||
}> = ({ child, on_init, min_size, size, breadcrumb }) => {
|
}> = ({ child, on_init, min_size, size, breadcrumb }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log("master");
|
||||||
let md = on_init();
|
let md = on_init();
|
||||||
md.breadcrumb.list = breadcrumb();
|
md.header.breadcrumb = breadcrumb();
|
||||||
if(!isEditor){
|
md.header.render();
|
||||||
md.breadcrumb.reload();
|
|
||||||
}
|
|
||||||
if (md) {
|
if (md) {
|
||||||
let width = 0;
|
let width = 0;
|
||||||
let min_width = 0;
|
let min_width = 0;
|
||||||
|
|
@ -33,8 +33,8 @@ export const MDRenderMaster: FC<{
|
||||||
md.panel.min_size = min_width;
|
md.panel.min_size = min_width;
|
||||||
md.panel.size = width;
|
md.panel.size = width;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
return <>{child}</>;
|
return <>{child}</>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
|
||||||
md.props.gen_table = gen_table;
|
md.props.gen_table = gen_table;
|
||||||
md.props.on_init = on_init;
|
md.props.on_init = on_init;
|
||||||
if (!mdr.master || (mdr.master && !get(mdr, "master.edit.childs.0.childs.length"))) {
|
if (!mdr.master || (mdr.master && !get(mdr, "master.edit.childs.0.childs.length"))) {
|
||||||
md.breadcrumb.list = [
|
md.header.breadcrumb = [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
<>
|
<>
|
||||||
|
|
@ -39,7 +39,7 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
|
||||||
];
|
];
|
||||||
md.status = "unready";
|
md.status = "unready";
|
||||||
} else {
|
} else {
|
||||||
md.breadcrumb.list = [];
|
md.header.breadcrumb = [];
|
||||||
md.status = "ready";
|
md.status = "ready";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import get from "lodash.get";
|
|
||||||
import { MDLocal, MDProps, MDRef } from "./typings";
|
|
||||||
import { getProp } from "lib/utils/get-prop";
|
|
||||||
|
|
||||||
export const mdBread = (md: MDLocal, mdr: MDRef, props: MDProps, item: PrasiItem) => {
|
|
||||||
const child = get(item, "component.props.child.content.childs") || [];
|
|
||||||
const master = child.find((e) => get(e, "component.id")=== "c68415ca-dac5-44fe-aeb6-936caf8cc491")
|
|
||||||
let mode = "master";
|
|
||||||
if (isEditor) {
|
|
||||||
mode = md.props.editor_tab;
|
|
||||||
} else {
|
|
||||||
if (typeof md.selected === "object") {
|
|
||||||
if (!md.tab.active) {
|
|
||||||
md.tab.active = md.tab.list[0];
|
|
||||||
}
|
|
||||||
mode = md.tab.active;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const done = (item: Array<any>) => {
|
|
||||||
md.breadcrumb.list = item || [];
|
|
||||||
}
|
|
||||||
if(mode === "master"){
|
|
||||||
const master_bread = getProp(master, "breadcrumb", { md });
|
|
||||||
if (master_bread instanceof Promise) {
|
|
||||||
master_bread.then((e) => {
|
|
||||||
done(e)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done(master_bread)
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
const tab = child.find((e) => get(e, "component.id")=== "cb52075a-14ab-455a-9847-6f1d929a2a73" && eval(get(e, "component.props.name.value")) === mode)
|
|
||||||
const master_bread = getProp(tab, "breadcrumb", { md });
|
|
||||||
if (master_bread instanceof Promise) {
|
|
||||||
master_bread.then((e) => {
|
|
||||||
done(e)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done(master_bread)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log({mode})
|
|
||||||
};
|
|
||||||
|
|
@ -34,7 +34,7 @@ export type MDActions = {
|
||||||
export type MDLocalInternal = {
|
export type MDLocalInternal = {
|
||||||
name: string;
|
name: string;
|
||||||
status: "init" | "unready" | "ready";
|
status: "init" | "unready" | "ready";
|
||||||
breadcrumb: {list:BreadItem[], render: () => void, reload: () => void};
|
header: { breadcrumb: BreadItem[]; render: () => void };
|
||||||
actions: MDActions;
|
actions: MDActions;
|
||||||
selected: any;
|
selected: any;
|
||||||
tab: {
|
tab: {
|
||||||
|
|
@ -89,11 +89,13 @@ export type MDLocal = MDLocalInternal & { render: (force?: boolean) => void };
|
||||||
export const MasterDetailType = `const md = {
|
export const MasterDetailType = `const md = {
|
||||||
name: string;
|
name: string;
|
||||||
status: string;
|
status: string;
|
||||||
|
header: {
|
||||||
breadcrumb: {
|
breadcrumb: {
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
url?: string;
|
url?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}[];
|
}[]
|
||||||
|
};
|
||||||
actions: (
|
actions: (
|
||||||
{
|
{
|
||||||
action?: string;
|
action?: string;
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ const buttonVariants = cva(
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "c-h-10 c-px-4 c-py-2",
|
default: "c-h-10 c-px-4 c-py-2",
|
||||||
|
xs: "c-h-7 c-rounded-sm c-px-2",
|
||||||
sm: "c-h-9 c-rounded-md c-px-3",
|
sm: "c-h-9 c-rounded-md c-px-3",
|
||||||
lg: "c-h-11 c-rounded-md c-px-8",
|
lg: "c-h-11 c-rounded-md c-px-8",
|
||||||
icon: "c-h-10 c-w-10",
|
icon: "c-h-10 c-w-10",
|
||||||
nozise: ""
|
nozise: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
|
@ -36,16 +37,16 @@ const buttonVariants = cva(
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLDivElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean;
|
asChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
const Button = React.forwardRef<HTMLDivElement, ButtonProps>(
|
||||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
const Comp = asChild ? Slot : "button";
|
const Comp = asChild ? Slot : "button";
|
||||||
return (
|
return (
|
||||||
<Comp
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({ variant, size, className }),
|
buttonVariants({ variant, size, className }),
|
||||||
`btn-${variant || "default"} btn c-transition-all c-duration-300`
|
`btn-${variant || "default"} btn c-transition-all c-duration-300`
|
||||||
|
|
@ -58,10 +59,10 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
);
|
);
|
||||||
Button.displayName = "Button";
|
Button.displayName = "Button";
|
||||||
|
|
||||||
const FloatButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
const FloatButton = React.forwardRef<HTMLDivElement, ButtonProps>(
|
||||||
({ variant, className, ...props }, ref) => {
|
({ variant, className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({ variant, className }),
|
buttonVariants({ variant, className }),
|
||||||
`btn-${
|
`btn-${
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ export const TypeaheadOptions: FC<{
|
||||||
`
|
`
|
||||||
: css`
|
: css`
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
|
`,
|
||||||
|
css`
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: auto;
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
@ -75,7 +79,7 @@ export const TypeaheadOptions: FC<{
|
||||||
onSelect?.(item.value);
|
onSelect?.(item.value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label || <> </>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { Badge } from "./badge";
|
||||||
import { TypeaheadOptions } from "./typeahead-opt";
|
import { TypeaheadOptions } from "./typeahead-opt";
|
||||||
|
|
||||||
export const Typeahead: FC<{
|
export const Typeahead: FC<{
|
||||||
value?: string[];
|
value?: string[] | null;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
options?: (arg: {
|
options?: (arg: {
|
||||||
search: string;
|
search: string;
|
||||||
|
|
@ -90,6 +90,7 @@ export const Typeahead: FC<{
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!value) return;
|
||||||
if (!isEditor) {
|
if (!isEditor) {
|
||||||
if (local.options.length === 0) {
|
if (local.options.length === 0) {
|
||||||
loadOptions().then(() => {
|
loadOptions().then(() => {
|
||||||
|
|
@ -105,6 +106,9 @@ export const Typeahead: FC<{
|
||||||
if (typeof value === "object" && value) {
|
if (typeof value === "object" && value) {
|
||||||
local.value = value;
|
local.value = value;
|
||||||
local.render();
|
local.render();
|
||||||
|
} else {
|
||||||
|
local.value = [];
|
||||||
|
local.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -299,7 +303,17 @@ export const Typeahead: FC<{
|
||||||
if (local.mode === "single" && local.value.length > 1) {
|
if (local.mode === "single" && local.value.length > 1) {
|
||||||
local.value = [local.value.pop() || ""];
|
local.value = [local.value.pop() || ""];
|
||||||
}
|
}
|
||||||
const valueLabel = local.value.map((value) => {
|
|
||||||
|
if (local.value.length === 0) {
|
||||||
|
if (local.mode === "single") {
|
||||||
|
if (!local.open) {
|
||||||
|
local.select = null;
|
||||||
|
local.search.input = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueLabel = local.value?.map((value) => {
|
||||||
const item = local.options.find((item) => item.value === value);
|
const item = local.options.find((item) => item.value === value);
|
||||||
|
|
||||||
if (local.mode === "single") {
|
if (local.mode === "single") {
|
||||||
|
|
@ -341,7 +355,7 @@ export const Typeahead: FC<{
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>{e?.label}</div>
|
<div>{e?.label || <> </>}</div>
|
||||||
<X size={12} />
|
<X size={12} />
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
|
|
@ -503,7 +517,7 @@ export const Typeahead: FC<{
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
"c-absolute c-pointer-events-none c-z-10 c-inset-0 c-left-auto c-flex c-items-center ",
|
"c-absolute c-pointer-events-none c-z-10 c-inset-0 c-left-auto c-flex c-items-center ",
|
||||||
" c-justify-center c-w-6 c-mr-1 c-my-2 c-bg-transparent",
|
" c-justify-center c-w-6 c-mr-1 c-my-2 c-bg-white",
|
||||||
disabled && "c-hidden"
|
disabled && "c-hidden"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ export { prasi_gen } from "@/gen/prasi_gen";
|
||||||
export { password } from "@/utils/password";
|
export { password } from "@/utils/password";
|
||||||
export { generateTableList } from "@/comps/md/gen/gen-table-list";
|
export { generateTableList } from "@/comps/md/gen/gen-table-list";
|
||||||
export { generateForm } from "@/comps/form/gen/gen-form";
|
export { generateForm } from "@/comps/form/gen/gen-form";
|
||||||
|
export { generateSelect } from "@/comps/md/gen/md-select";
|
||||||
|
|
||||||
/** Session */
|
/** Session */
|
||||||
export {
|
export {
|
||||||
|
|
@ -81,11 +82,9 @@ export {
|
||||||
RG,
|
RG,
|
||||||
UserSession,
|
UserSession,
|
||||||
} from "@/preset/login/utils/register";
|
} from "@/preset/login/utils/register";
|
||||||
export { prasi_user } from "@/preset/login/utils/user";
|
|
||||||
export { Login } from "@/preset/login/Login";
|
export { Login } from "@/preset/login/Login";
|
||||||
export { logout } from "@/preset/login/utils/logout";
|
export { logout } from "@/preset/login/utils/logout";
|
||||||
export { generateLogin } from "@/preset/login/utils/generate";
|
export { generateLogin } from "@/preset/login/utils/generate";
|
||||||
export { select as generateSelect } from "@/preset/login/utils/select";
|
|
||||||
|
|
||||||
export { Card } from "@/comps/custom/Card";
|
export { Card } from "@/comps/custom/Card";
|
||||||
|
|
||||||
|
|
@ -114,4 +113,4 @@ export { getPathname } from "./utils/pathname";
|
||||||
|
|
||||||
export * from "@/comps/ui/typeahead";
|
export * from "@/comps/ui/typeahead";
|
||||||
export * from "@/comps/ui/input";
|
export * from "@/comps/ui/input";
|
||||||
export {softDeleteFilter} from "@/utils/soft-delete-filter"
|
export { softDeleteFilter } from "@/utils/soft-delete-filter";
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ export const on_submit = ({
|
||||||
|
|
||||||
return `\
|
return `\
|
||||||
async ({ form, error }: IForm) => {
|
async ({ form, error }: IForm) => {
|
||||||
|
if (isEditor) return false;
|
||||||
if (typeof form !== "object") return false;
|
if (typeof form !== "object") return false;
|
||||||
if (typeof error === "object" && Object.keys(error).length > 0) return false;
|
if (typeof error === "object" && Object.keys(error).length > 0) return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { FC, useEffect } from "react";
|
import { FC, useEffect } from "react";
|
||||||
import { prasi_user } from "./utils/user";
|
import { loadSession } from "./utils/load";
|
||||||
|
|
||||||
const w = window as unknown as {
|
const w = window as unknown as {
|
||||||
|
user: any;
|
||||||
prasi_home: Record<string, string>;
|
prasi_home: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -15,8 +16,11 @@ export const Login: FC<LGProps> = (props) => {
|
||||||
w.prasi_home = props.url_home[0];
|
w.prasi_home = props.url_home[0];
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
const home = prasi_user.prasi_home[prasi_user.user.m_role.name];
|
loadSession();
|
||||||
|
if (w.user) {
|
||||||
|
const home = w.prasi_home[w.user.m_role.name];
|
||||||
navigate(home);
|
navigate(home);
|
||||||
|
}
|
||||||
} catch (e: any) {}
|
} catch (e: any) {}
|
||||||
}, []);
|
}, []);
|
||||||
return <>{props.body}</>;
|
return <>{props.body}</>;
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,8 @@ export const generateLogin = async (
|
||||||
});
|
});
|
||||||
if (data_user) {
|
if (data_user) {
|
||||||
registerSession({ data: data_user, expired: null });
|
registerSession({ data: data_user, expired: null });
|
||||||
const home = prasi_user.prasi_home[prasi_user.user.m_role.name];
|
const w = window as any;
|
||||||
|
const home = w.prasi_home[w.user.m_role.name];
|
||||||
navigate(home);
|
navigate(home);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { logout } from "./logout";
|
||||||
const w = window as any;
|
const w = window as any;
|
||||||
const parse = parser.exportAsFunctionAny("en-US");
|
const parse = parser.exportAsFunctionAny("en-US");
|
||||||
export const loadSession = (url_login?: string) => {
|
export const loadSession = (url_login?: string) => {
|
||||||
|
if (!isEditor) {
|
||||||
try {
|
try {
|
||||||
const user = localStorage.getItem("user");
|
const user = localStorage.getItem("user");
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
@ -12,19 +13,17 @@ export const loadSession = (url_login?: string) => {
|
||||||
if (typeof raw === "object") {
|
if (typeof raw === "object") {
|
||||||
const session: UserSession = raw;
|
const session: UserSession = raw;
|
||||||
const expired = parse(session.expired);
|
const expired = parse(session.expired);
|
||||||
if (
|
if (expired instanceof Date) {
|
||||||
typeof expired === "object" &&
|
|
||||||
expired instanceof Date
|
|
||||||
) {
|
|
||||||
if (new Date() > expired) {
|
if (new Date() > expired) {
|
||||||
logout(url_login);
|
if (url_login) logout(url_login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logout(url_login);
|
if (url_login) logout(url_login);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logout(url_login);
|
if (url_login) logout(url_login);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,5 @@ export const logout = (url_login?: string) => {
|
||||||
if (localStorage.getItem("user")) {
|
if (localStorage.getItem("user")) {
|
||||||
localStorage.removeItem("user");
|
localStorage.removeItem("user");
|
||||||
}
|
}
|
||||||
if (!getPathname().startsWith("/dev")) {
|
|
||||||
if (url_login) navigate(url_login);
|
if (url_login) navigate(url_login);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
export const prasi_user = window as unknown as {
|
|
||||||
user: {
|
|
||||||
id: string;
|
|
||||||
username: string;
|
|
||||||
name: string;
|
|
||||||
fullname: string;
|
|
||||||
m_role: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
prasi_home: Record<string, string>;
|
|
||||||
};
|
|
||||||
|
|
@ -32,9 +32,9 @@ type LYTChild = {
|
||||||
desktop?: ReactNode;
|
desktop?: ReactNode;
|
||||||
tablet?: ReactNode;
|
tablet?: ReactNode;
|
||||||
child?: ReactNode;
|
child?: ReactNode;
|
||||||
children: ReactNode;
|
default_layout: ReactNode;
|
||||||
exception?: Array<string>;
|
exception?: Array<string>;
|
||||||
defaultLayout: ReactNode;
|
blank_layout: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Layout: FC<LYTChild> = (props) => {
|
export const Layout: FC<LYTChild> = (props) => {
|
||||||
|
|
@ -64,12 +64,18 @@ export const Layout: FC<LYTChild> = (props) => {
|
||||||
const no_layout = props.exception;
|
const no_layout = props.exception;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadSession("/auth/login");
|
loadSession("/auth/login");
|
||||||
|
render();
|
||||||
}, []);
|
}, []);
|
||||||
if (Array.isArray(no_layout))
|
|
||||||
|
if (!isEditor && Array.isArray(no_layout)) {
|
||||||
if (no_layout.length) {
|
if (no_layout.length) {
|
||||||
if (no_layout.includes(path)) {
|
if (no_layout.includes(path)) {
|
||||||
return <>{props.defaultLayout}</>;
|
return <>{props.blank_layout}</>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <>{props.children}</>;
|
}
|
||||||
|
|
||||||
|
if (!w.user) return props.blank_layout;
|
||||||
|
|
||||||
|
return <>{props.default_layout}</>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const isEmptyString = (data: any) => {
|
||||||
|
if(typeof data === 'string'){
|
||||||
|
return data.trim() === '' || data === "" || !data
|
||||||
|
}
|
||||||
|
return typeof data === "undefined"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { prasi_gen } from "lib/gen/prasi_gen";
|
||||||
|
|
||||||
|
export const sofDeleteField = async (
|
||||||
|
table: string,
|
||||||
|
field: string
|
||||||
|
) => {
|
||||||
|
const result = {} as any;
|
||||||
|
const fields =await prasi_gen.prop.fields(table);
|
||||||
|
const value = fields.find((e: any) => {
|
||||||
|
const val = JSON.parse(e.value);
|
||||||
|
if (val.type === "has-one" || val.type === "has-many" || val.is_pk) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (e.label === field);
|
||||||
|
});
|
||||||
|
if(value) return JSON.parse(value.value)
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
@ -1,26 +1,28 @@
|
||||||
|
import { isEmptyString } from "./is-empty-string";
|
||||||
|
|
||||||
export const softDeleteFilter = (
|
export const softDeleteFilter = (
|
||||||
where: any,
|
where: any,
|
||||||
soft: {
|
soft: {
|
||||||
field: string;
|
field: string;
|
||||||
type: "boolean" | "nullable";
|
type: "boolean" | "nullable";
|
||||||
|
feature: Array<string>;
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
console.log({ where });
|
const feature = soft.feature || [];
|
||||||
|
if (!feature.find((e) => e === "soft_delete")) return where;
|
||||||
const defaultParam = typeof where === "object" ? where : {};
|
const defaultParam = typeof where === "object" ? where : {};
|
||||||
|
if (isEmptyString(soft.field) || isEmptyString(soft.type))
|
||||||
|
return defaultParam;
|
||||||
const result = {
|
const result = {
|
||||||
AND: [
|
AND: [
|
||||||
typeof where === "object"
|
typeof defaultParam === "object" ? { ...defaultParam } : {},
|
||||||
? { ...defaultParam }
|
{
|
||||||
: {
|
|
||||||
[soft.field]:
|
[soft.field]:
|
||||||
soft.type === "boolean"
|
soft.type === "boolean"
|
||||||
? true
|
? false
|
||||||
: {
|
:null,
|
||||||
not: null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
console.log(result);
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue