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 { Skeleton } from "../ui/skeleton";
|
||||
import get from "lodash.get";
|
||||
import { FieldLoading } from "../ui/field-loading";
|
||||
|
||||
export type BreadItem = {
|
||||
label: React.ReactNode;
|
||||
|
|
@ -16,43 +17,7 @@ type BreadcrumbProps = {
|
|||
item?: PrasiItem;
|
||||
};
|
||||
|
||||
export const Breadcrumb: FC<BreadcrumbProps> = ({
|
||||
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();
|
||||
}, []);
|
||||
|
||||
export const Breadcrumb: FC<BreadcrumbProps> = ({ value, className }) => {
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
|
|
@ -60,55 +25,49 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({
|
|||
className
|
||||
)}
|
||||
>
|
||||
{local.status !== "ready" ? (
|
||||
<Skeleton className="c-h-4 c-w-[80%]" />
|
||||
) : (
|
||||
<>
|
||||
{local.list &&
|
||||
(local.list || []).map((item, index): ReactNode => {
|
||||
const lastIndex = local.list.length - 1;
|
||||
{(value || []).map((cur, index): ReactNode => {
|
||||
const lastIndex = (value || []).length - 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
{index === lastIndex ? (
|
||||
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
||||
{item?.label}
|
||||
</h1>
|
||||
) : (
|
||||
<h1
|
||||
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer hover:c-underline"
|
||||
onClick={(ev) => {
|
||||
if (item.url) navigate(item.url || "");
|
||||
if (item.onClick) item.onClick(ev);
|
||||
}}
|
||||
>
|
||||
{item?.label}
|
||||
</h1>
|
||||
)}
|
||||
return (
|
||||
<>
|
||||
{index === lastIndex ? (
|
||||
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
||||
{cur?.label}
|
||||
</h1>
|
||||
) : (
|
||||
<h1
|
||||
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer hover:c-underline"
|
||||
onClick={(ev) => {
|
||||
if (isEditor) return;
|
||||
if (cur.url) navigate(cur.url || "");
|
||||
if (cur.onClick) cur.onClick(ev);
|
||||
}}
|
||||
>
|
||||
{cur?.label}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{index !== lastIndex && (
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-chevron-right"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
{index !== lastIndex && (
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-chevron-right"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import { editorFormData } from "./utils/ed-data";
|
|||
import { formInit } from "./utils/init";
|
||||
import { formReload } from "./utils/reload";
|
||||
import { getPathname } from "lib/utils/pathname";
|
||||
import { sofDeleteField } from "lib/utils/soft-del-rel";
|
||||
|
||||
const editorFormWidth = {} as Record<string, { w: number; f: any }>;
|
||||
|
||||
export { FMLocal } from "./typings";
|
||||
|
||||
export const Form: FC<FMProps> = (props) => {
|
||||
const { PassProp, body } = props;
|
||||
const { PassProp, body, feature, sfd_field } = props;
|
||||
const fm = useLocal<FMInternal>({
|
||||
data: editorFormData[props.item.id]
|
||||
? editorFormData[props.item.id].data
|
||||
|
|
@ -51,8 +52,30 @@ export const Form: FC<FMProps> = (props) => {
|
|||
? editorFormWidth[props.item.id].f
|
||||
: "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({
|
||||
el: null as null | HTMLFormElement,
|
||||
rob: new ResizeObserver(([e]) => {
|
||||
|
|
|
|||
|
|
@ -31,45 +31,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
|||
const errors = fm.error.get(name);
|
||||
const props = { ...arg.props };
|
||||
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 (
|
||||
<label
|
||||
|
|
@ -79,8 +41,8 @@ export const Field: FC<FieldProp> = (arg) => {
|
|||
css`
|
||||
padding: 5px 0px 0px 10px;
|
||||
`,
|
||||
|
||||
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 === "¾" && "c-w-3/4",
|
||||
w === "½" && "c-w-1/2",
|
||||
|
|
@ -111,7 +73,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
|||
{errors.length > 0 && (
|
||||
<div
|
||||
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"
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const FieldInput: FC<{
|
|||
child: any;
|
||||
_item: PrasiItem;
|
||||
arg: FieldProp;
|
||||
}> = ({ field, fm, arg, _item, PassProp, child}) => {
|
||||
}> = ({ field, fm, arg, _item, PassProp, child }) => {
|
||||
// return <></>
|
||||
const prefix =
|
||||
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") {
|
||||
const childsTableEdit = get(
|
||||
_item,
|
||||
|
|
@ -57,7 +59,7 @@ export const FieldInput: FC<{
|
|||
child: get(_item, "edit.props.child.value") as PrasiItem,
|
||||
bottom: childsTableEdit.find((e) => e.name === "bottom") as PrasiItem,
|
||||
};
|
||||
return (
|
||||
table_edit = (
|
||||
<TableEdit
|
||||
on_init={() => {
|
||||
return fm;
|
||||
|
|
@ -70,13 +72,38 @@ export const FieldInput: FC<{
|
|||
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 (
|
||||
<div
|
||||
className={cx(
|
||||
!["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"
|
||||
? css`
|
||||
|
|
@ -115,30 +142,40 @@ export const FieldInput: FC<{
|
|||
field.disabled && "c-pointer-events-none"
|
||||
)}
|
||||
>
|
||||
{type_field === "custom" && arg.custom ? (
|
||||
<>{custom}</>
|
||||
{not_ready ? (
|
||||
not_ready
|
||||
) : (
|
||||
<>
|
||||
{["date", "input"].includes(type_field) ? (
|
||||
<FieldTypeInput
|
||||
field={field}
|
||||
fm={fm}
|
||||
arg={arg}
|
||||
prop={
|
||||
{
|
||||
type: type_field as any,
|
||||
sub_type: arg.sub_type,
|
||||
prefix,
|
||||
suffix,
|
||||
} as PropTypeInput
|
||||
}
|
||||
/>
|
||||
) : ["single-option"].includes(type_field) ? (
|
||||
<SingleOption arg={arg} field={field} fm={fm} />
|
||||
) : ["multi-option"].includes(type_field) ? (
|
||||
<MultiOption arg={arg} field={field} fm={fm} />
|
||||
{type_field === "custom" && arg.custom ? (
|
||||
<>{custom}</>
|
||||
) : (
|
||||
<>{isValidElement(type_field) && type_field}</>
|
||||
<>
|
||||
{["date", "input"].includes(type_field) ? (
|
||||
<FieldTypeInput
|
||||
field={field}
|
||||
fm={fm}
|
||||
arg={arg}
|
||||
prop={
|
||||
{
|
||||
type: type_field as any,
|
||||
sub_type: arg.sub_type,
|
||||
prefix,
|
||||
suffix,
|
||||
} as PropTypeInput
|
||||
}
|
||||
/>
|
||||
) : ["single-option"].includes(type_field) ? (
|
||||
<SingleOption arg={arg} field={field} fm={fm} />
|
||||
) : ["multi-option"].includes(type_field) ? (
|
||||
arg.sub_type === "table-edit" ? (
|
||||
table_edit
|
||||
) : (
|
||||
<MultiOption arg={arg} field={field} fm={fm} />
|
||||
)
|
||||
) : (
|
||||
<>{isValidElement(type_field) && type_field}</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { TableList } from "lib/comps/list/TableList";
|
||||
import { useLocal } from "lib/utils/use-local";
|
||||
import { FC } from "react";
|
||||
import { FC, ReactElement, useEffect, useRef } from "react";
|
||||
import { BaseForm } from "../../base/BaseForm";
|
||||
import { FMLocal } from "../../typings";
|
||||
import get from "lodash.get";
|
||||
|
||||
export const TableEdit: FC<{
|
||||
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 (
|
||||
<>
|
||||
<div className="c-w-full c-h-full c-flex c-flex-col">
|
||||
|
|
@ -32,6 +41,18 @@ export const TableEdit: FC<{
|
|||
> .rdg {
|
||||
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={{
|
||||
|
|
@ -41,57 +62,82 @@ export const TableEdit: FC<{
|
|||
? 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
|
||||
rowHeight={50}
|
||||
row_height={50}
|
||||
feature={[]}
|
||||
child={child}
|
||||
PassProp={PassProp}
|
||||
name={""}
|
||||
value={value}
|
||||
on_init={() => {}}
|
||||
on_init={(tbl) => {
|
||||
local.tbl = tbl;
|
||||
local.render();
|
||||
}}
|
||||
mode={"table"}
|
||||
_item={item}
|
||||
gen_fields={[]}
|
||||
row_click={() => {}}
|
||||
row_click={({ event }) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
selected={() => {
|
||||
return false;
|
||||
}}
|
||||
filter_name={""}
|
||||
render_col={(arg: any) => {
|
||||
render_col={(arg) => {
|
||||
const { props, tbl, child } = arg;
|
||||
const fm_row = { ...fm };
|
||||
const fm_row = { ...fm, render: local.render };
|
||||
fm_row.data = props.row;
|
||||
fm_row.render = fm.render;
|
||||
local.tbl = tbl;
|
||||
|
||||
const key = props.column.key;
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: props.column.key,
|
||||
name: key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={tbl.data}
|
||||
fm={fm_row}
|
||||
ext_fm={{
|
||||
change: () => {},
|
||||
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();
|
||||
}
|
||||
fm.data[name] = tbl.data.filter(
|
||||
(e: any) => e !== props.row
|
||||
);
|
||||
fm.render();
|
||||
},
|
||||
add: () => {
|
||||
if (Array.isArray(value)) {
|
||||
value.push({});
|
||||
} else {
|
||||
alert("value bukan array");
|
||||
}
|
||||
tbl.data.push({});
|
||||
fm.render();
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
|
@ -99,35 +145,23 @@ export const TableEdit: FC<{
|
|||
</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>
|
||||
<PassProp
|
||||
ext_fm={{
|
||||
add: () => {
|
||||
if (Array.isArray(value)) {
|
||||
value.push({});
|
||||
fm.data[name] = value;
|
||||
fm.render();
|
||||
} else {
|
||||
fm.data[name] = [{}];
|
||||
fm.render();
|
||||
}
|
||||
local.tbl.data.push({});
|
||||
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 { FC, useEffect } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||
import { FieldLoading } from "lib/comps/ui/field-loading";
|
||||
import { Typeahead } from "lib/comps/ui/typeahead";
|
||||
import { FC, useEffect } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||
|
||||
export const TypeDropdown: FC<{
|
||||
field: FieldLocal;
|
||||
|
|
@ -11,7 +11,7 @@ export const TypeDropdown: FC<{
|
|||
}> = ({ field, fm, arg }) => {
|
||||
const local = useLocal({
|
||||
loaded: false,
|
||||
options: [],
|
||||
options: [] as { value: string; label: string; data: any }[],
|
||||
});
|
||||
let value =
|
||||
typeof arg.opt_get_value === "function"
|
||||
|
|
@ -22,6 +22,7 @@ export const TypeDropdown: FC<{
|
|||
type: field.type,
|
||||
})
|
||||
: fm.data[field.name];
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof arg.on_load === "function") {
|
||||
const options = arg.on_load({});
|
||||
|
|
@ -38,6 +39,22 @@ export const TypeDropdown: FC<{
|
|||
} else {
|
||||
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.render();
|
||||
});
|
||||
|
|
@ -48,12 +65,16 @@ export const TypeDropdown: FC<{
|
|||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!local.loaded) return <FieldLoading />;
|
||||
if (field.type === "single-option")
|
||||
if (field.type === "single-option") {
|
||||
if (value === null) {
|
||||
fm.data[field.name] = undefined;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Typeahead
|
||||
value={value}
|
||||
value={Array.isArray(value) ? value : [value]}
|
||||
onSelect={({ search, item }) => {
|
||||
if (item) {
|
||||
arg.opt_set_value({
|
||||
|
|
@ -77,6 +98,7 @@ export const TypeDropdown: FC<{
|
|||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ export const FieldTypeInput: FC<{
|
|||
arg: FieldProp;
|
||||
}> = ({ field, fm, prop, arg }) => {
|
||||
const input = useLocal({
|
||||
showHidePassword: false,
|
||||
show_pass: false,
|
||||
change_timeout: null as any,
|
||||
});
|
||||
let type_field = prop.sub_type;
|
||||
switch (type_field) {
|
||||
|
|
@ -49,7 +50,7 @@ export const FieldTypeInput: FC<{
|
|||
default:
|
||||
}
|
||||
|
||||
if (input.showHidePassword) {
|
||||
if (input.show_pass) {
|
||||
type_field = "text";
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +81,23 @@ export const FieldTypeInput: FC<{
|
|||
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 (
|
||||
<>
|
||||
{type_field === "textarea" ? (
|
||||
<AutoHeightTextarea
|
||||
onChange={(ev) => {
|
||||
fm.data[field.name] = ev.currentTarget.value;
|
||||
fm.render();
|
||||
renderOnChange();
|
||||
}}
|
||||
value={value || ""}
|
||||
disabled={field.disabled}
|
||||
|
|
@ -165,7 +176,7 @@ export const FieldTypeInput: FC<{
|
|||
fm.data[field.name] = value?.startDate
|
||||
? new Date(value?.startDate)
|
||||
: null;
|
||||
fm.render();
|
||||
renderOnChange();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
@ -173,6 +184,7 @@ export const FieldTypeInput: FC<{
|
|||
<div className="c-flex c-relative c-flex-1">
|
||||
<input
|
||||
type={type_field}
|
||||
tabIndex={0}
|
||||
onChange={(ev) => {
|
||||
if (["date", "datetime", "datetime-local"].includes(type_field)) {
|
||||
let result = null;
|
||||
|
|
@ -183,7 +195,7 @@ export const FieldTypeInput: FC<{
|
|||
} else {
|
||||
fm.data[field.name] = ev.currentTarget.value;
|
||||
}
|
||||
fm.render();
|
||||
renderOnChange();
|
||||
}}
|
||||
placeholder={arg.placeholder || ""}
|
||||
value={value}
|
||||
|
|
@ -195,6 +207,9 @@ export const FieldTypeInput: FC<{
|
|||
display = "";
|
||||
field.render();
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && fm.status === "ready") fm.submit();
|
||||
}}
|
||||
onBlur={() => {
|
||||
field.focused = false;
|
||||
field.render();
|
||||
|
|
@ -204,12 +219,12 @@ export const FieldTypeInput: FC<{
|
|||
<div
|
||||
className="c-absolute c-right-0 c-h-full c-flex c-items-center c-cursor-pointer"
|
||||
onClick={() => {
|
||||
input.showHidePassword = !input.showHidePassword;
|
||||
input.show_pass = !input.show_pass;
|
||||
input.render();
|
||||
}}
|
||||
>
|
||||
<div className="">
|
||||
{input.showHidePassword ? (
|
||||
{input.show_pass ? (
|
||||
<EyeIcon className="c-h-4" />
|
||||
) : (
|
||||
<EyeOff className="c-h-4" />
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const FieldMoney: FC<{
|
|||
ref: null as any,
|
||||
});
|
||||
let display: any = null;
|
||||
const money = formatMoney(Number(value) || 0)
|
||||
const money = formatMoney(Number(value) || 0);
|
||||
return (
|
||||
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
||||
<div
|
||||
|
|
@ -42,6 +42,13 @@ export const FieldMoney: FC<{
|
|||
onChange={(ev) => {
|
||||
fm.data[field.name] = ev.currentTarget.value;
|
||||
fm.render();
|
||||
if (field.on_change) {
|
||||
field.on_change({
|
||||
value: fm.data[field.name],
|
||||
name: field.name,
|
||||
fm,
|
||||
});
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
disabled={field.disabled}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ export const FieldRichText: FC<{
|
|||
});
|
||||
useEffect(() => {
|
||||
if (local.ref) {
|
||||
console.log(local.ref);
|
||||
console.log(local.ref.current);
|
||||
const q = new Quill(local.ref, {
|
||||
theme: "snow",
|
||||
modules: {
|
||||
|
|
|
|||
|
|
@ -14,27 +14,27 @@ export const FieldUpload: FC<{
|
|||
value: 0 as any,
|
||||
display: false as any,
|
||||
ref: null as any,
|
||||
drop: false as boolean
|
||||
drop: false as boolean,
|
||||
});
|
||||
let display: any = null;
|
||||
return (
|
||||
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
||||
<div
|
||||
onDrop={(e: any) => {
|
||||
console.log({ e });
|
||||
e.preventDefault();
|
||||
input.drop = false;
|
||||
input.render();
|
||||
}}
|
||||
onDragOver={(e:any) => {
|
||||
console.log("File(s) in drop zone");
|
||||
|
||||
onDragOver={(e: any) => {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
e.preventDefault();
|
||||
input.drop = true;
|
||||
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">
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
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 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 { get_value } from "./get-value";
|
||||
import { set_value } from "./set-value";
|
||||
import get from "lodash.get";
|
||||
import { generateRelation } from "./gen-rel";
|
||||
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 = {
|
||||
name: string;
|
||||
type: string;
|
||||
|
|
@ -22,9 +19,9 @@ export type GFCol = {
|
|||
fields: GFCol[];
|
||||
};
|
||||
};
|
||||
export const newField = (
|
||||
export const newField = async (
|
||||
arg: GFCol,
|
||||
opt: { parent_table: string; value: Array<string> },
|
||||
opt: { parent_table: string; value: Array<string>; on_change?: string },
|
||||
show_label: boolean
|
||||
) => {
|
||||
let show = typeof show_label === "boolean" ? show_label : true;
|
||||
|
|
@ -43,6 +40,9 @@ export const newField = (
|
|||
child: {
|
||||
childs: [],
|
||||
},
|
||||
ext__on_change: opt.on_change
|
||||
? [opt.on_change, opt.on_change]
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -59,6 +59,9 @@ export const newField = (
|
|||
child: {
|
||||
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",
|
||||
type: "single-option",
|
||||
sub_type: "toogle",
|
||||
ext__on_change: opt.on_change
|
||||
? [opt.on_change, opt.on_change]
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -89,6 +95,9 @@ export const newField = (
|
|||
child: {
|
||||
childs: [],
|
||||
},
|
||||
ext__on_change: opt.on_change
|
||||
? [opt.on_change, opt.on_change]
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -102,6 +111,12 @@ export const newField = (
|
|||
pks: {},
|
||||
});
|
||||
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({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
|
|
@ -112,6 +127,7 @@ export const newField = (
|
|||
ext__show_label: show ? "y" : "n",
|
||||
sub_type: "dropdown",
|
||||
rel__gen_table: arg.name,
|
||||
rel__gen_fields: [rel__gen_fields, rel__gen_fields],
|
||||
opt__on_load: [load],
|
||||
opt__label: [
|
||||
gen_label({
|
||||
|
|
@ -137,6 +153,9 @@ export const newField = (
|
|||
child: {
|
||||
childs: [],
|
||||
},
|
||||
ext__on_change: opt.on_change
|
||||
? [opt.on_change, opt.on_change]
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -146,48 +165,54 @@ export const newField = (
|
|||
arg,
|
||||
rel: fields,
|
||||
});
|
||||
if (result.on_load) {
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type: "multi-option",
|
||||
sub_type: "checkbox",
|
||||
rel__gen_table: arg.name,
|
||||
opt__on_load: [result.on_load],
|
||||
ext__show_label: show ? "y" : "n",
|
||||
opt__label: [result.get_label],
|
||||
opt__get_value: [result.get_value],
|
||||
opt__set_value: [result.set_value],
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
|
||||
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'" },
|
||||
},
|
||||
},
|
||||
});
|
||||
} 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: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
createItem({}),
|
||||
false
|
||||
),
|
||||
});
|
||||
}
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type: "multi-option",
|
||||
sub_type,
|
||||
rel__gen_table: arg.name,
|
||||
opt__on_load: [result.on_load],
|
||||
ext__show_label: show ? "y" : "n",
|
||||
opt__label: [result.get_label],
|
||||
opt__get_value: [result.get_value],
|
||||
opt__set_value: [result.set_value],
|
||||
rel__gen_fields: rel__gen_fields
|
||||
? [rel__gen_fields, rel__gen_fields]
|
||||
: undefined,
|
||||
child,
|
||||
ext__on_change: opt.on_change
|
||||
? [opt.on_change, opt.on_change]
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// type not found,
|
||||
|
|
@ -203,6 +228,9 @@ export const newField = (
|
|||
child: {
|
||||
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,
|
||||
data: any,
|
||||
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 (
|
||||
| string
|
||||
| { value: string; checked: string[] }
|
||||
|
|
@ -34,280 +40,341 @@ export const generateForm = async (
|
|||
if (data["on_load"]) {
|
||||
result.on_load = {
|
||||
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"]) {
|
||||
result.on_submit = {
|
||||
mode: "raw",
|
||||
value: `\
|
||||
async ({ form, error }: IForm) => {
|
||||
let result = false;
|
||||
try {
|
||||
|
||||
const data = { ...form }; // data form
|
||||
const data_rel = ${JSON.stringify(
|
||||
rel_many
|
||||
)} // list relasi has many
|
||||
const data_master = {} as Record<string, any> | any; // variabel untuk data master
|
||||
const data_array = [] as Array<{
|
||||
table: string;
|
||||
data: Array<any>;
|
||||
fk: string;
|
||||
}>; // variabel untuk data array atau has many
|
||||
async ({ form, error, fm }: IForm) => {
|
||||
let result = false;
|
||||
try {
|
||||
if (typeof md !== "undefined") {
|
||||
fm.status = "saving";
|
||||
md.render();
|
||||
}
|
||||
|
||||
const data = { ...form }; // data form
|
||||
const data_rel = ${JSON.stringify(rel_many)} // list relasi has many
|
||||
const data_master = {} as Record<string, any> | any; // variabel untuk data master
|
||||
const data_array = [] as Array<{
|
||||
table: string;
|
||||
data: Array<any>;
|
||||
fk: string;
|
||||
}>; // variabel untuk data array atau has many
|
||||
|
||||
// proses untuk membagi antara data master dengan data array
|
||||
// data array / has many dilihat dari value yang berupa array
|
||||
for (const [k, v] of Object.entries(data) as any) {
|
||||
if (Array.isArray(v)) {
|
||||
const rel = Array.isArray(data_rel) && data_rel.length ? data_rel.find((e) => e.table === k) : null
|
||||
if (rel) {
|
||||
data_array.push({
|
||||
table: k,
|
||||
data: v,
|
||||
fk: rel.fk,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
data_master[k] = v;
|
||||
}
|
||||
}
|
||||
// hapus id dari data_master jika ada
|
||||
try {
|
||||
delete data_master.${pk};
|
||||
} catch (ex) {}
|
||||
if (form.${pk}) {
|
||||
await db.${table}.update({
|
||||
where: {
|
||||
// proses untuk membagi antara data master dengan data array
|
||||
// data array / has many dilihat dari value yang berupa array
|
||||
for (const [k, v] of Object.entries(data) as any) {
|
||||
if (Array.isArray(v)) {
|
||||
const rel = Array.isArray(data_rel) && data_rel.length ? data_rel.find((e) => e.table === k) : null
|
||||
if (rel) {
|
||||
data_array.push({
|
||||
table: k,
|
||||
data: v,
|
||||
fk: rel.fk,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
data_master[k] = v;
|
||||
}
|
||||
}
|
||||
// hapus id dari data_master jika ada
|
||||
try {
|
||||
delete data_master.${pk};
|
||||
} catch (ex) {}
|
||||
if (form.${pk}) {
|
||||
await db.${table}.update({
|
||||
where: {
|
||||
${pk}: form.${pk},
|
||||
},
|
||||
data: data_master,
|
||||
});
|
||||
} else {
|
||||
const res = await db.${table}.create({
|
||||
data: data_master,
|
||||
});
|
||||
if (res) form.${pk} = res.${pk};
|
||||
}
|
||||
if (data_array.length) {
|
||||
const exec_query_bulk = async (
|
||||
current: { table: string; data: Array<any>; fk: string },
|
||||
list: Array<{ table: string; data: Array<any>; fk: string }>,
|
||||
index: number,
|
||||
) => {
|
||||
if (list.length) {
|
||||
const data = current.data.map((e) => {
|
||||
return {
|
||||
...e,
|
||||
${table}: {
|
||||
connect: {
|
||||
${pk}: form.${pk},
|
||||
},
|
||||
data: data_master,
|
||||
});
|
||||
} else {
|
||||
const res = await db.${table}.create({
|
||||
data: data_master,
|
||||
});
|
||||
if (res) form.${pk} = res.${pk};
|
||||
}
|
||||
if (data_array.length) {
|
||||
const exec_query_bulk = async (
|
||||
current: { table: string; data: Array<any>; fk: string },
|
||||
list: Array<{ table: string; data: Array<any>; fk: string }>,
|
||||
index: number,
|
||||
) => {
|
||||
if (list.length) {
|
||||
const data = current.data.map((e) => {
|
||||
return {
|
||||
...e,
|
||||
${table}: {
|
||||
connect: {
|
||||
${pk}: form.${pk},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
await db._batch.upsert({
|
||||
table: current.table,
|
||||
where: {
|
||||
[current.fk]: form.${pk},
|
||||
},
|
||||
data: data,
|
||||
mode: "relation",
|
||||
} as any);
|
||||
|
||||
if (list.length > 1) {
|
||||
try {
|
||||
index++;
|
||||
if (index < list.length - 1) {
|
||||
await exec_query_bulk(list[index], list, index);
|
||||
}
|
||||
} catch (ex) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
await exec_query_bulk(data_array[0], data_array, 0);
|
||||
}
|
||||
result = true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
result = false;
|
||||
},
|
||||
};
|
||||
});
|
||||
await db._batch.upsert({
|
||||
table: current.table,
|
||||
where: {
|
||||
[current.fk]: form.${pk},
|
||||
},
|
||||
data: data,
|
||||
mode: "relation",
|
||||
} as any);
|
||||
|
||||
if (list.length > 1) {
|
||||
try {
|
||||
index++;
|
||||
if (index < list.length - 1) {
|
||||
await exec_query_bulk(list[index], list, index);
|
||||
}
|
||||
} catch (ex) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
await exec_query_bulk(data_array[0], data_array, 0);
|
||||
}
|
||||
result = true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (typeof md !== "undefined") {
|
||||
fm.status = "ready";
|
||||
md.render();
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
type IForm = { form: any; error: Record<string, string> }
|
||||
type Init = { submit: () => Promise<boolean>; reload: () => void; fm: FMLocal }
|
||||
`,
|
||||
};
|
||||
}
|
||||
const childs = [];
|
||||
console.log({fields})
|
||||
for (const item of fields.filter((e) => !e.is_pk)) {
|
||||
let value = [] as Array<string>;
|
||||
if (["has-one", "has-many"].includes(item.type)) {
|
||||
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({
|
||||
id: createId(),
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "submit",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "bottom",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<Button\n {...props}\n onClick={(e) => {\n console.log(isEditor);\n if (!isEditor) on_click(e);\n }}\n variant={variant !== "primary" ? variant : undefined}\n size={size !== "default" ? size : undefined}\n>\n {label}\n</Button>',
|
||||
css: "& {\n display: flex;\n box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;\n\n &:hover {\n cursor: pointer;\n\n\n\n\n\n // &.mobile {}\n // &.desktop {}\n // &:hover {}\n }\n}",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement(\n Button,\n {\n ...props,\n onClick: (e) => {\n console.log(isEditor);\n if (!isEditor)\n on_click(e);\n },\n variant: variant !== "primary" ? variant : void 0,\n size: size !== "default" ? size : void 0\n },\n label\n));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "button",
|
||||
type: "item",
|
||||
childs: [],
|
||||
mobile: { linktag: {} },
|
||||
script: {
|
||||
props: {
|
||||
size: { value: ' "default";\n' },
|
||||
variant: { value: ' "primary";\n' },
|
||||
on_click: {
|
||||
value:
|
||||
" (e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n};\n",
|
||||
if (typeof is_md === "boolean" && !is_md)
|
||||
childs.push({
|
||||
id: createId(),
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "submit",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "bottom",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<Button\n {...props}\n onClick={(e) => {\n console.log(isEditor);\n if (!isEditor) on_click(e);\n }}\n variant={variant !== "primary" ? variant : undefined}\n size={size !== "default" ? size : undefined}\n>\n {label}\n</Button>',
|
||||
css: "& {\n display: flex;\n box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;\n\n &:hover {\n cursor: pointer;\n\n\n\n\n\n // &.mobile {}\n // &.desktop {}\n // &:hover {}\n }\n}",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement(\n Button,\n {\n ...props,\n onClick: (e) => {\n console.log(isEditor);\n if (!isEditor)\n on_click(e);\n },\n variant: variant !== "primary" ? variant : void 0,\n size: size !== "default" ? size : void 0\n },\n label\n));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "button",
|
||||
type: "item",
|
||||
childs: [],
|
||||
mobile: { linktag: {} },
|
||||
script: {
|
||||
props: {
|
||||
size: { value: ' "default";\n' },
|
||||
variant: { value: ' "primary";\n' },
|
||||
on_click: {
|
||||
value:
|
||||
" (e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n};\n",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: {
|
||||
id: "a15d152d-0118-408f-89f1-f6b2dfbd2e05",
|
||||
props: {
|
||||
size: {
|
||||
idx: 5,
|
||||
meta: {
|
||||
type: "option",
|
||||
options: '["default", "sm", "lg", "icon","nosize"]',
|
||||
optionsBuilt:
|
||||
' ["default", "sm", "lg", "icon", "nosize"];\n',
|
||||
},
|
||||
name: "prop_5",
|
||||
type: "string",
|
||||
value: '"default"',
|
||||
valueBuilt: ' "default";\n',
|
||||
},
|
||||
label: {
|
||||
idx: 1,
|
||||
meta: { type: "content-element" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value: '"hello"',
|
||||
content: {
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n {children}\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, children));\n',
|
||||
component: {
|
||||
id: "a15d152d-0118-408f-89f1-f6b2dfbd2e05",
|
||||
props: {
|
||||
size: {
|
||||
idx: 5,
|
||||
meta: {
|
||||
type: "option",
|
||||
options: '["default", "sm", "lg", "icon","nosize"]',
|
||||
optionsBuilt:
|
||||
' ["default", "sm", "lg", "icon", "nosize"];\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "label",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
name: "Wrapped",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2"><path d="M16 21v-2c0-1.886 0-2.828-.586-3.414C14.828 15 13.886 15 12 15h-1c-1.886 0-2.828 0-3.414.586C7 16.172 7 17.114 7 19v2" /><path stroke-linecap="round" d="M7 8h5" /><path d="M3 9c0-2.828 0-4.243.879-5.121C4.757 3 6.172 3 9 3h7.172c.408 0 .613 0 .796.076c.184.076.329.22.618.51l2.828 2.828c.29.29.434.434.51.618c.076.183.076.388.076.796V15c0 2.828 0 4.243-.879 5.121C19.243 21 17.828 21 15 21H9c-2.828 0-4.243 0-5.121-.879C3 19.243 3 17.828 3 15z" /></g></svg>\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24" }, /* @__PURE__ */ React.createElement("g", { fill: "none", stroke: "currentColor", "stroke-width": "2" }, /* @__PURE__ */ React.createElement("path", { d: "M16 21v-2c0-1.886 0-2.828-.586-3.414C14.828 15 13.886 15 12 15h-1c-1.886 0-2.828 0-3.414.586C7 16.172 7 17.114 7 19v2" }), /* @__PURE__ */ React.createElement("path", { "stroke-linecap": "round", d: "M7 8h5" }), /* @__PURE__ */ React.createElement("path", { d: "M3 9c0-2.828 0-4.243.879-5.121C4.757 3 6.172 3 9 3h7.172c.408 0 .613 0 .796.076c.184.076.329.22.618.51l2.828 2.828c.29.29.434.434.51.618c.076.183.076.388.076.796V15c0 2.828 0 4.243-.879 5.121C19.243 21 17.828 21 15 21H9c-2.828 0-4.243 0-5.121-.879C3 19.243 3 17.828 3 15z" })))));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
html: "aadd",
|
||||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
script: {},
|
||||
},
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n Save\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, "Save"));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "new_item",
|
||||
type: "item",
|
||||
childs: [],
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
dir: "row",
|
||||
gap: 10,
|
||||
wrap: "flex-nowrap",
|
||||
align: "top-left",
|
||||
},
|
||||
name: "prop_5",
|
||||
type: "string",
|
||||
value: '"default"',
|
||||
valueBuilt: ' "default";\n',
|
||||
},
|
||||
label: {
|
||||
idx: 1,
|
||||
meta: { type: "content-element" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value: '"hello"',
|
||||
content: {
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n {children}\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, children));\n',
|
||||
},
|
||||
],
|
||||
hidden: false,
|
||||
layout: {
|
||||
dir: "col",
|
||||
gap: 0,
|
||||
wrap: "flex-nowrap",
|
||||
align: "center",
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "label",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
name: "Wrapped",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2"><path d="M16 21v-2c0-1.886 0-2.828-.586-3.414C14.828 15 13.886 15 12 15h-1c-1.886 0-2.828 0-3.414.586C7 16.172 7 17.114 7 19v2" /><path stroke-linecap="round" d="M7 8h5" /><path d="M3 9c0-2.828 0-4.243.879-5.121C4.757 3 6.172 3 9 3h7.172c.408 0 .613 0 .796.076c.184.076.329.22.618.51l2.828 2.828c.29.29.434.434.51.618c.076.183.076.388.076.796V15c0 2.828 0 4.243-.879 5.121C19.243 21 17.828 21 15 21H9c-2.828 0-4.243 0-5.121-.879C3 19.243 3 17.828 3 15z" /></g></svg>\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24" }, /* @__PURE__ */ React.createElement("g", { fill: "none", stroke: "currentColor", "stroke-width": "2" }, /* @__PURE__ */ React.createElement("path", { d: "M16 21v-2c0-1.886 0-2.828-.586-3.414C14.828 15 13.886 15 12 15h-1c-1.886 0-2.828 0-3.414.586C7 16.172 7 17.114 7 19v2" }), /* @__PURE__ */ React.createElement("path", { "stroke-linecap": "round", d: "M7 8h5" }), /* @__PURE__ */ React.createElement("path", { d: "M3 9c0-2.828 0-4.243.879-5.121C4.757 3 6.172 3 9 3h7.172c.408 0 .613 0 .796.076c.184.076.329.22.618.51l2.828 2.828c.29.29.434.434.51.618c.076.183.076.388.076.796V15c0 2.828 0 4.243-.879 5.121C19.243 21 17.828 21 15 21H9c-2.828 0-4.243 0-5.121-.879C3 19.243 3 17.828 3 15z" })))));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
html: "aadd",
|
||||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
script: {},
|
||||
},
|
||||
{
|
||||
id: createId(),
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n Save\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, "Save"));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "new_item",
|
||||
type: "item",
|
||||
childs: [],
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
dir: "row",
|
||||
gap: 10,
|
||||
wrap: "flex-nowrap",
|
||||
align: "top-left",
|
||||
},
|
||||
},
|
||||
],
|
||||
hidden: false,
|
||||
layout: {
|
||||
dir: "col",
|
||||
gap: 0,
|
||||
wrap: "flex-nowrap",
|
||||
align: "center",
|
||||
},
|
||||
script: {},
|
||||
},
|
||||
script: {},
|
||||
valueBuilt: '"hello"',
|
||||
},
|
||||
valueBuilt: '"hello"',
|
||||
},
|
||||
variant: {
|
||||
idx: 3,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["primary", "secondary", "outline", "ghost", "link", "destructive"]',
|
||||
option_mode: "button",
|
||||
optionsBuilt:
|
||||
' ["primary", "secondary", "outline", "ghost", "link", "destructive"];\n',
|
||||
variant: {
|
||||
idx: 3,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["primary", "secondary", "outline", "ghost", "link", "destructive"]',
|
||||
option_mode: "button",
|
||||
optionsBuilt:
|
||||
' ["primary", "secondary", "outline", "ghost", "link", "destructive"];\n',
|
||||
},
|
||||
name: "prop_3",
|
||||
type: "string",
|
||||
value: '"primary"',
|
||||
valueBuilt: ' "primary";\n',
|
||||
},
|
||||
on_click: {
|
||||
idx: 1,
|
||||
meta: { type: "text" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value:
|
||||
"(e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n}",
|
||||
valueBuilt:
|
||||
" (e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n};\n",
|
||||
},
|
||||
name: "prop_3",
|
||||
type: "string",
|
||||
value: '"primary"',
|
||||
valueBuilt: ' "primary";\n',
|
||||
},
|
||||
on_click: {
|
||||
idx: 1,
|
||||
meta: { type: "text" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value:
|
||||
"(e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n}",
|
||||
valueBuilt:
|
||||
" (e) => {\n e.preventDefault();\n e.stopPropagation();\n fm.submit();\n};\n",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
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) {
|
||||
Object.keys(result).map((e) => {
|
||||
item.edit.setProp(e, result[e]);
|
||||
|
|
@ -316,12 +383,13 @@ export const generateForm = async (
|
|||
mode: "jsx",
|
||||
value: createItem({
|
||||
name: "item",
|
||||
...body_prop,
|
||||
childs: childs,
|
||||
}),
|
||||
});
|
||||
await item.edit.commit();
|
||||
} else {
|
||||
console.log({ data });
|
||||
set(data, "body.value", { ...data.body?.value, ...body_prop });
|
||||
set(data, "body.value.childs", childs);
|
||||
Object.keys(result).map((e) => {
|
||||
set(data, e, result[e]);
|
||||
|
|
|
|||
|
|
@ -16,20 +16,29 @@ export const gen_label = ({
|
|||
}
|
||||
|
||||
return `\
|
||||
(row: { value: string; label: string; item?: any }) => {
|
||||
(row: { value: string; label: string; data?: any }) => {
|
||||
const cols = ${JSON.stringify(cols)};
|
||||
|
||||
if (isEditor) {
|
||||
return row.label;
|
||||
}
|
||||
const result = [];
|
||||
if (!!row.item && !Array.isArray(row.item)) {
|
||||
cols.map((e) => {
|
||||
if (row.item[e]) {
|
||||
result.push(row.item[e]);
|
||||
}
|
||||
});
|
||||
return result.join(" - ");
|
||||
if (!!row.data && !row.label && !Array.isArray(row.data)) {
|
||||
if(cols.length > 0){
|
||||
cols.map((e) => {
|
||||
if (row.data[e]) {
|
||||
result.push(row.data[e]);
|
||||
}
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ export const gen_rel_many = (prop: {
|
|||
rel: any;
|
||||
}) => {
|
||||
const { table_parent, arg, rel } = prop;
|
||||
console.log({ rel });
|
||||
const parent = rel.find((e: any) => e.name === table_parent);
|
||||
const master = rel.find(
|
||||
(e: any) => e.name !== table_parent && e.type === "has-one"
|
||||
|
|
@ -124,20 +123,29 @@ export const gen_rel_many = (prop: {
|
|||
}
|
||||
}
|
||||
const get_label = `\
|
||||
(row: { value: string; label: string; item?: any }) => {
|
||||
(row: { value: string; label: string; data?: any }) => {
|
||||
const cols = ${JSON.stringify(cols)};
|
||||
|
||||
if (isEditor) {
|
||||
return row.label;
|
||||
}
|
||||
const result = [];
|
||||
if (!!row.item && !Array.isArray(row.item)) {
|
||||
cols.map((e) => {
|
||||
if (row.item[e]) {
|
||||
result.push(row.item[e]);
|
||||
}
|
||||
});
|
||||
return result.join(" - ");
|
||||
if (!!row.data && !row.label && !Array.isArray(row.data)) {
|
||||
if(cols.length > 0){
|
||||
cols.map((e) => {
|
||||
if (row.data[e]) {
|
||||
result.push(row.data[e]);
|
||||
}
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
|
@ -147,13 +155,13 @@ export const gen_rel_many = (prop: {
|
|||
result.get_value = get_value;
|
||||
result.set_value = set_value;
|
||||
} else {
|
||||
console.log("tidak punya master");
|
||||
|
||||
result.get_label = `\
|
||||
(row: { value: string; label: string; item?: any }) => {
|
||||
return row.label;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
result.get_value = `\
|
||||
(arg: {
|
||||
options: { label: string; value: string; item?: string }[];
|
||||
|
|
|
|||
|
|
@ -21,17 +21,24 @@ export const generateRelation = async (
|
|||
},
|
||||
false
|
||||
)) as any;
|
||||
item.edit.setProp("child", {
|
||||
mode: "jsx",
|
||||
value: {
|
||||
id: createId(),
|
||||
name: "item",
|
||||
type: "item",
|
||||
edit: null as any,
|
||||
childs: result,
|
||||
},
|
||||
});
|
||||
await item.edit.commit();
|
||||
if (commit) {
|
||||
item.edit.setProp("child", {
|
||||
mode: "jsx",
|
||||
value: {
|
||||
id: createId(),
|
||||
name: "item",
|
||||
type: "item",
|
||||
edit: null as any,
|
||||
childs: result,
|
||||
},
|
||||
});
|
||||
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 { createItem, parseGenField } from "lib/gen/utils";
|
||||
import get from "lodash.get";
|
||||
import { formatName, newField } from "./fields";
|
||||
import { set } from "lib/utils/set";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
|
||||
export const genTableEdit = async (
|
||||
item: PrasiItem,
|
||||
|
|
@ -33,41 +32,51 @@ export const genTableEdit = async (
|
|||
}
|
||||
const childs = [] as Array<any>;
|
||||
let first = true;
|
||||
fields
|
||||
.map((e, idx) => {
|
||||
if (e.is_pk) return;
|
||||
let value = [] as Array<string>;
|
||||
if (["has-one", "has-many"].includes(e.type)) {
|
||||
value = get(e, "value.checked") as any;
|
||||
}
|
||||
const field = newField(e, { parent_table: table, value }, false);
|
||||
let tree_depth = "";
|
||||
let tree_depth_built = "";
|
||||
if (first) {
|
||||
tree_depth = `tree_depth={col.depth}`;
|
||||
tree_depth_built = `tree_depth:col.depth`;
|
||||
first = false;
|
||||
}
|
||||
childs.push({
|
||||
component: {
|
||||
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
props: {
|
||||
name: e.name,
|
||||
title: formatName(e.name),
|
||||
child: createItem({
|
||||
childs: [field],
|
||||
}),
|
||||
await Promise.all(
|
||||
fields
|
||||
.map(async (e, idx) => {
|
||||
if (e.is_pk) return;
|
||||
let value = [] as Array<string>;
|
||||
if (["has-one", "has-many"].includes(e.type)) {
|
||||
value = get(e, "value.checked") as any;
|
||||
}
|
||||
const field = await newField(
|
||||
e,
|
||||
{
|
||||
parent_table: table,
|
||||
value,
|
||||
on_change: `() => { ext_fm.change(); }`,
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
.filter((e) => e) as any;
|
||||
false
|
||||
);
|
||||
let tree_depth = "";
|
||||
let tree_depth_built = "";
|
||||
if (first) {
|
||||
tree_depth = `tree_depth={col.depth}`;
|
||||
tree_depth_built = `tree_depth:col.depth`;
|
||||
first = false;
|
||||
}
|
||||
childs.push({
|
||||
component: {
|
||||
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
props: {
|
||||
name: e.name,
|
||||
title: formatName(e.name),
|
||||
child: createItem({
|
||||
childs: [field],
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
.filter((e) => e)
|
||||
);
|
||||
childs.push({
|
||||
component: {
|
||||
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
props: {
|
||||
name: "option",
|
||||
title: "option",
|
||||
title: "",
|
||||
child: {
|
||||
id: createId(),
|
||||
name: "option",
|
||||
|
|
@ -133,7 +142,11 @@ export const genTableEdit = async (
|
|||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
layout: {
|
||||
dir: "col",
|
||||
gap: 0,
|
||||
align: "left",
|
||||
},
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
|
|
@ -240,7 +253,7 @@ export const genTableEdit = async (
|
|||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
layout: { dir: "col", gap: 0, align: "left" },
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
|
|
@ -285,7 +298,7 @@ export const genTableEdit = async (
|
|||
dir: "row",
|
||||
gap: 10,
|
||||
wrap: "flex-nowrap",
|
||||
align: "top-left",
|
||||
align: "left",
|
||||
},
|
||||
padding: { b: 0, l: 10, r: 10, t: 0 },
|
||||
},
|
||||
|
|
@ -304,6 +317,7 @@ export const genTableEdit = async (
|
|||
name: "btn-submit",
|
||||
type: "item",
|
||||
edit: null as any,
|
||||
padding: { b: 10, l: 10, r: 10, t: 0 },
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
|
|
@ -354,12 +368,17 @@ export const genTableEdit = async (
|
|||
const option = {
|
||||
id: createId(),
|
||||
name: "bottom",
|
||||
padding: { b: 10, l: 10, r: 10, t: 0 },
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
name: "bottom",
|
||||
name: "wrapper",
|
||||
type: "item",
|
||||
dim: {
|
||||
h: "fit",
|
||||
w: "fit",
|
||||
},
|
||||
childs: [
|
||||
{
|
||||
id: createId(),
|
||||
|
|
@ -380,7 +399,7 @@ export const genTableEdit = async (
|
|||
variant: { value: ' "primary";\n' },
|
||||
on_click: {
|
||||
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",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
layout: { dir: "col", gap: 0, align: "left" },
|
||||
script: {},
|
||||
},
|
||||
{
|
||||
|
|
@ -456,9 +475,9 @@ export const genTableEdit = async (
|
|||
],
|
||||
layout: {
|
||||
dir: "row",
|
||||
gap: 10,
|
||||
gap: 5,
|
||||
wrap: "flex-nowrap",
|
||||
align: "top-left",
|
||||
align: "left",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -488,9 +507,9 @@ export const genTableEdit = async (
|
|||
name: "prop_1",
|
||||
type: "string",
|
||||
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:
|
||||
' (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: {},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const get_value = ({
|
||||
pk,
|
||||
table,
|
||||
select
|
||||
select,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
|
|
@ -15,30 +15,32 @@ export const get_value = ({
|
|||
}
|
||||
}
|
||||
return `\
|
||||
(arg: {
|
||||
options: { label: string; value: string; item?: string }[];
|
||||
fm: FMLocal;
|
||||
name: string;
|
||||
type: string;
|
||||
}) => {
|
||||
const { options, fm, name, type } = arg;
|
||||
if(isEditor){
|
||||
return fm.data[name];
|
||||
(arg: {
|
||||
options: { label: string; value: string; item?: string }[];
|
||||
fm: FMLocal;
|
||||
name: string;
|
||||
type: string;
|
||||
}) => {
|
||||
const { options, fm, name, type } = arg;
|
||||
if(isEditor){
|
||||
return fm.data[name];
|
||||
}
|
||||
let result = null;
|
||||
result = fm.data[name];
|
||||
try{
|
||||
const data = fm.data["${table}"];
|
||||
if(typeof data === "object"){
|
||||
if(typeof data?.connect?.${pk} === "string"){
|
||||
result = data.connect.${pk};
|
||||
} else if (typeof data?.id === "string") {
|
||||
result = data.id;
|
||||
} else if (data?.disconnect === true) {
|
||||
result = undefined;
|
||||
}
|
||||
let result = null;
|
||||
result = fm.data[name];
|
||||
try{
|
||||
const data = fm.data["${table}"];
|
||||
if(typeof data === "object"){
|
||||
if(typeof data?.connect?.${pk} === "string"){
|
||||
result = data.connect.${pk};
|
||||
}else if (typeof data?.id === "string") {
|
||||
result = data.id;
|
||||
}
|
||||
}
|
||||
}catch(ex){
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}catch(ex){
|
||||
}
|
||||
return result;
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ export const on_load = ({
|
|||
select: any;
|
||||
pks: Record<string, string>;
|
||||
opt?: {
|
||||
before_load: string;
|
||||
after_load: string;
|
||||
before_load?: string;
|
||||
after_load?: string;
|
||||
};
|
||||
}) => {
|
||||
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 where = {
|
||||
${pk}: id,
|
||||
};
|
||||
if (id){
|
||||
item = await db.${table}.findFirst({
|
||||
where: {
|
||||
${pk}: id,
|
||||
},
|
||||
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
||||
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 : ""}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
export const on_load_rel = ({
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
}) => {
|
||||
const sample = {
|
||||
label: "sample",
|
||||
value: "sample",
|
||||
data: null
|
||||
} as any;
|
||||
const cols = [];
|
||||
for (const [k, v] of Object.entries(select) as any) {
|
||||
if(k !== pk && typeof v !== "object"){
|
||||
cols.push(k);
|
||||
}
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
}) => {
|
||||
const sample = {
|
||||
label: "sample",
|
||||
value: "sample",
|
||||
data: null,
|
||||
} as any;
|
||||
const cols = [];
|
||||
for (const [k, v] of Object.entries(select) as any) {
|
||||
if (k !== pk && typeof v !== "object") {
|
||||
cols.push(k);
|
||||
}
|
||||
|
||||
return `\
|
||||
}
|
||||
|
||||
return `\
|
||||
(arg: {
|
||||
reload: () => Promise<void>;
|
||||
orderBy?: Record<string, "asc" | "desc">;
|
||||
|
|
@ -35,8 +35,14 @@ export const on_load_rel = ({
|
|||
return await db.${table}.count();
|
||||
}
|
||||
|
||||
const fields = parseGenField(rel__gen_fields);
|
||||
const res = generateSelect(fields);
|
||||
|
||||
const items = await db.${table}.findMany({
|
||||
select: ${JSON.stringify(select)},
|
||||
select: {
|
||||
...${JSON.stringify(select)},
|
||||
...(res?.select || {})
|
||||
},
|
||||
orderBy: arg.orderBy || {
|
||||
${pk}: "desc"
|
||||
},
|
||||
|
|
@ -53,18 +59,27 @@ export const on_load_rel = ({
|
|||
})
|
||||
return result.join(" - ");
|
||||
}
|
||||
done(items.map((e) => {
|
||||
return {
|
||||
|
||||
let blank: any = undefined;
|
||||
if (ext__required !== "y") {
|
||||
blank = { value: undefined, label: "", data: {} };
|
||||
}
|
||||
done(
|
||||
[
|
||||
blank,
|
||||
...items.map((e) => {
|
||||
return {
|
||||
value: e.${pk},
|
||||
label: getLabel(e),
|
||||
data: e,
|
||||
}
|
||||
}))
|
||||
};
|
||||
}),
|
||||
].filter((e) => e),
|
||||
);
|
||||
} else {
|
||||
done([])
|
||||
}
|
||||
})
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,11 +24,17 @@ export const set_value = ({
|
|||
}) => {
|
||||
const { selected, options, fm, name, type } = arg;
|
||||
if (type === "single-option") {
|
||||
fm.data[name] = {
|
||||
connect: {
|
||||
${pk}: selected[0],
|
||||
},
|
||||
};
|
||||
if (selected[0]) {
|
||||
fm.data[name] = {
|
||||
connect: {
|
||||
${pk}: selected[0],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
fm.data[name] = {
|
||||
disconnect: true,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
fm.data[name] = selected.map((e) => e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ export type FMProps = {
|
|||
gen_fields: any;
|
||||
gen_table: string;
|
||||
on_load_deps?: any[];
|
||||
feature?: any[];
|
||||
sfd_field?: any;
|
||||
};
|
||||
|
||||
export type GenField =
|
||||
|
|
@ -87,7 +89,8 @@ export type FieldProp = {
|
|||
placeholder: string;
|
||||
show_label: boolean;
|
||||
msg_error: string;
|
||||
gen_table: string;
|
||||
gen_table?: string;
|
||||
gen_fields?: string;
|
||||
};
|
||||
|
||||
export type FMInternal = {
|
||||
|
|
@ -125,6 +128,9 @@ export type FMInternal = {
|
|||
height: number;
|
||||
field: "full" | "half";
|
||||
};
|
||||
soft_delete: {
|
||||
field: any;
|
||||
};
|
||||
};
|
||||
export type FMLocal = FMInternal & { render: () => void };
|
||||
|
||||
|
|
@ -150,6 +156,7 @@ export type FieldInternal<T extends FieldProp["type"]> = {
|
|||
options: {
|
||||
on_load?: () => Promise<{ value: string; label: string }[]>;
|
||||
};
|
||||
on_change?: (arg: { value: any, name: string, fm: FMLocal }) => void | Promise<void>;
|
||||
prop?: any;
|
||||
};
|
||||
export type FieldLocal = FieldInternal<any> & {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
}
|
||||
const { on_load, sonar } = fm.props;
|
||||
fm.error = formError(fm);
|
||||
|
||||
fm.field_def = {};
|
||||
const defs = parseGenField(fm.props.gen_fields);
|
||||
for (const d of defs) {
|
||||
|
|
@ -110,7 +109,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
};
|
||||
|
||||
if (typeof fm.props.on_submit === "function") {
|
||||
if (fm.props.sonar === "on") {
|
||||
if (fm.props.sonar === "on" && !isEditor) {
|
||||
toast.loading(
|
||||
<>
|
||||
<Loader2 className="c-h-4 c-w-4 c-animate-spin" />
|
||||
|
|
@ -126,7 +125,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
|
||||
toast.dismiss();
|
||||
done_all(success);
|
||||
if (fm.props.sonar === "on") {
|
||||
if (fm.props.sonar === "on" && !isEditor) {
|
||||
setTimeout(() => {
|
||||
toast.dismiss();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export const useField = (
|
|||
required: required === "y",
|
||||
required_msg: arg.required_msg,
|
||||
disabled: arg.disabled === "y",
|
||||
on_change: arg.on_change,
|
||||
};
|
||||
|
||||
if (field.status === "init" || isEditor) {
|
||||
|
|
|
|||
|
|
@ -4,19 +4,27 @@ import { fields_map } from "@/utils/format-value";
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import get from "lodash.get";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { ChangeEvent, FC, MouseEvent, ReactNode, useEffect } from "react";
|
||||
import {
|
||||
ChangeEvent,
|
||||
FC,
|
||||
MouseEvent,
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
useEffect,
|
||||
} from "react";
|
||||
import DataGrid, {
|
||||
ColumnOrColumnGroup,
|
||||
RenderCellProps,
|
||||
Row,
|
||||
SELECT_COLUMN_KEY,
|
||||
SortColumn,
|
||||
} from "react-data-grid";
|
||||
import "./TableList.css";
|
||||
import { createPortal } from "react-dom";
|
||||
import { Toaster, toast } from "sonner";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
import { sortTree } from "./utils/sort-tree";
|
||||
import { filterWhere } from "../filter/utils/filter-where";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
import "./TableList.css";
|
||||
import { sortTree } from "./utils/sort-tree";
|
||||
|
||||
type OnRowClick = (arg: {
|
||||
row: any;
|
||||
|
|
@ -38,7 +46,6 @@ type TableListProp = {
|
|||
}) => Promise<any[]>;
|
||||
on_init: (arg?: any) => any;
|
||||
mode: "table" | "list" | "grid" | "auto";
|
||||
// _meta: Record<string, any>;
|
||||
_item: PrasiItem;
|
||||
gen_fields: string[];
|
||||
row_click: OnRowClick;
|
||||
|
|
@ -47,10 +54,16 @@ type TableListProp = {
|
|||
feature?: Array<any>;
|
||||
filter_name: string;
|
||||
render_row?: (child: any, data: any) => ReactNode;
|
||||
rowHeight?: number;
|
||||
render_col?: (props: any) => ReactNode;
|
||||
soft_delete_field: string;
|
||||
|
||||
row_height?: number;
|
||||
render_col?: (arg: {
|
||||
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 selectCellClassname = css`
|
||||
|
|
@ -77,11 +90,12 @@ export const TableList: FC<TableListProp> = ({
|
|||
feature,
|
||||
filter_name,
|
||||
render_row,
|
||||
rowHeight,
|
||||
row_height: rowHeight,
|
||||
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");
|
||||
if (mode === "auto") {
|
||||
if (w.isMobile) {
|
||||
|
|
@ -124,13 +138,13 @@ export const TableList: FC<TableListProp> = ({
|
|||
}
|
||||
},
|
||||
},
|
||||
cached_row: new WeakMap<any, ReactElement>(),
|
||||
sort: {
|
||||
columns: [] as SortColumn[],
|
||||
on_change: (cols: SortColumn[]) => {
|
||||
if (feature?.find((e) => e === "sorting")) {
|
||||
local.sort.columns = cols;
|
||||
local.paging.skip = 0;
|
||||
|
||||
if (cols.length > 0) {
|
||||
const { columnKey, direction } = cols[0];
|
||||
|
||||
|
|
@ -179,14 +193,18 @@ export const TableList: FC<TableListProp> = ({
|
|||
"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
|
||||
const pk = local.pk?.name || "id";
|
||||
useEffect(() => {
|
||||
if (isEditor) return;
|
||||
if (isEditor || value) {
|
||||
on_init(local);
|
||||
return;
|
||||
}
|
||||
(async () => {
|
||||
on_init(local);
|
||||
if (local.status === "reload" && typeof on_load === "function") {
|
||||
|
|
@ -198,7 +216,10 @@ export const TableList: FC<TableListProp> = ({
|
|||
async reload() {},
|
||||
where,
|
||||
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) {
|
||||
load_args.paging = {};
|
||||
|
|
@ -218,6 +239,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
}
|
||||
})();
|
||||
}, [local.status, on_load, local.sort.orderBy]);
|
||||
|
||||
const raw_childs = get(
|
||||
child,
|
||||
"props.meta.item.component.props.child.content.childs"
|
||||
|
|
@ -341,7 +363,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
}
|
||||
for (const child of childs) {
|
||||
let key = getProp(child, "name", {});
|
||||
const name = getProp(child, "title", {});
|
||||
const name = getProp(child, "title", "");
|
||||
const width = parseInt(getProp(child, "width", {}));
|
||||
|
||||
columns.push({
|
||||
|
|
@ -352,7 +374,12 @@ export const TableList: FC<TableListProp> = ({
|
|||
sortable: true,
|
||||
renderCell(props) {
|
||||
if (typeof render_col === "function")
|
||||
return render_col({ props, tbl: local, child });
|
||||
return render_col({
|
||||
props,
|
||||
tbl: local,
|
||||
child,
|
||||
});
|
||||
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
|
|
@ -389,9 +416,6 @@ export const TableList: FC<TableListProp> = ({
|
|||
</>,
|
||||
{
|
||||
dismissible: true,
|
||||
className: css`
|
||||
background: #e4f7ff;
|
||||
`,
|
||||
}
|
||||
);
|
||||
} 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 (local.data.length === 0) {
|
||||
const load_args: any = {
|
||||
async reload() {},
|
||||
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 (typeof on_load === "function") {
|
||||
local.data = on_load({ ...load_args, mode: "query" }) as any;
|
||||
|
|
@ -430,9 +459,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
}
|
||||
local.status = "ready";
|
||||
}
|
||||
|
||||
|
||||
let selected_idx = -1;
|
||||
}
|
||||
|
||||
let data = local.data || [];
|
||||
if (id_parent && local.pk && local.sort.columns.length === 0) {
|
||||
|
|
@ -498,12 +525,20 @@ export const TableList: FC<TableListProp> = ({
|
|||
columns={columns}
|
||||
rows={data}
|
||||
onScroll={local.paging.scroll}
|
||||
selectedRows={new Set() as ReadonlySet<any>}
|
||||
onSelectedCellChange={() => {}}
|
||||
onSelectedRowsChange={() => {}}
|
||||
renderers={
|
||||
local.status !== "ready"
|
||||
? undefined
|
||||
: {
|
||||
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({
|
||||
idx: props.rowIdx,
|
||||
row: props.row,
|
||||
|
|
@ -533,16 +568,10 @@ export const TableList: FC<TableListProp> = ({
|
|||
)}
|
||||
/>
|
||||
);
|
||||
if (typeof render_row === "function") {
|
||||
return render_row(child_row, props.row);
|
||||
if (cache_row) {
|
||||
local.cached_row.set(props.row, child_row);
|
||||
}
|
||||
// return child_row;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="c-contents">{child_row}</div>
|
||||
</>
|
||||
);
|
||||
return child_row;
|
||||
},
|
||||
noRowsFallback: (
|
||||
<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 { mdRenderLoop } from "./utils/md-render-loop";
|
||||
import { parseGenField } from "lib/gen/utils";
|
||||
import { NDT } from "src/data/timezoneNames";
|
||||
import { mdBread } from "./utils/md-bread";
|
||||
|
||||
export const MasterDetail: FC<MDProps> = (arg) => {
|
||||
const {
|
||||
|
|
@ -34,10 +32,9 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
|||
name,
|
||||
status: isEditor ? "init" : "ready",
|
||||
actions: [],
|
||||
breadcrumb: {
|
||||
list: [],
|
||||
header: {
|
||||
breadcrumb: [],
|
||||
render: () => {},
|
||||
reload: () => {}
|
||||
},
|
||||
selected: null,
|
||||
tab: {
|
||||
|
|
@ -82,8 +79,8 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
|||
} else {
|
||||
md.status = "ready";
|
||||
const fields = parseGenField(gen_fields);
|
||||
const pk = fields.find((e) => e.is_pk);
|
||||
md.pk = pk
|
||||
const pk = fields.find((e) => e.is_pk);
|
||||
md.pk = pk;
|
||||
md.params.parse();
|
||||
if (pk) {
|
||||
const value = md.params.hash[md.name];
|
||||
|
|
@ -92,13 +89,12 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
|||
const tab = md.params.tabs[md.name];
|
||||
if (tab && md.tab.list.includes(tab)) {
|
||||
md.tab.active = tab;
|
||||
}else{
|
||||
md.tab.active = "detail"
|
||||
} else {
|
||||
md.tab.active = "detail";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
md.breadcrumb.reload();
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ export const generateTableList = async (
|
|||
) => {
|
||||
let table = "" as string;
|
||||
try {
|
||||
table = eval(data.gen_table.value);
|
||||
table = eval(data.gen__table.value);
|
||||
} 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
|
||||
| { value: string; checked: string[] }
|
||||
)[];
|
||||
|
|
@ -53,7 +53,7 @@ export const generateTableList = async (
|
|||
if (data["opt__on_load"]) {
|
||||
result.opt__on_load = {
|
||||
mode: "raw",
|
||||
value: on_load({ pk, table, select, pks }),
|
||||
value: on_load({ pk, table, select, pks,fields }),
|
||||
};
|
||||
}
|
||||
let first = true;
|
||||
|
|
@ -91,10 +91,10 @@ export const generateTableList = async (
|
|||
adv: {
|
||||
js: `\
|
||||
<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>`,
|
||||
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,
|
||||
},
|
||||
};
|
||||
generateForm(async (props: any) => {}, props, tablelist, false);
|
||||
generateForm(async (props: any) => {}, props, tablelist, false, true);
|
||||
tab_detail?.edit.setProp("breadcrumb", {
|
||||
mode: "raw",
|
||||
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([
|
||||
{
|
||||
type: "item",
|
||||
|
|
|
|||
|
|
@ -36,5 +36,4 @@ export const generateMasterDetail: GenFn<{ item: PrasiItem, table: string, field
|
|||
//
|
||||
// }
|
||||
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 get from "lodash.get";
|
||||
import { generateTableList } from "./gen-table-list";
|
||||
import { formatName } from "lib/comps/form/gen/fields";
|
||||
|
||||
export const generateList = async (
|
||||
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"
|
||||
);
|
||||
const props: Record<string, PropVal> = {
|
||||
gen_table: {
|
||||
gen__table: {
|
||||
mode: "string",
|
||||
value: `"${arg.table}"`,
|
||||
},
|
||||
|
|
@ -77,7 +77,7 @@ rows: any[];
|
|||
idx: any;
|
||||
}`,
|
||||
},
|
||||
gen_fields: {
|
||||
gen__fields: {
|
||||
mode: "raw",
|
||||
value: `${JSON.stringify(arg.fields)}`,
|
||||
},
|
||||
|
|
@ -117,22 +117,17 @@ idx: any;
|
|||
url?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
`
|
||||
})
|
||||
console.log({
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
`,
|
||||
});
|
||||
|
||||
tab_master?.edit.setChilds([
|
||||
{
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
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: {},
|
||||
};
|
||||
for (const r of f.relation.fields) {
|
||||
select[f.name].select[r.name] = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (f.is_pk) {
|
||||
pk = f.name;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pk,
|
||||
select,
|
||||
|
|
|
|||
|
|
@ -1,44 +1,67 @@
|
|||
export const on_load = ({
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
}) => {
|
||||
const sample = {} as any;
|
||||
|
||||
for (const [k, v] of Object.entries(select) as any) {
|
||||
if (typeof v === "object") {
|
||||
sample[k] = {};
|
||||
|
||||
Object.keys(v.select)
|
||||
.filter((e) => e !== pks[k])
|
||||
.map((e) => {
|
||||
sample[k][e] = "sample";
|
||||
});
|
||||
} else {
|
||||
sample[k] = "sample";
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
fields,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
fields: Array<any>;
|
||||
}) => {
|
||||
const sample = {} as any;
|
||||
|
||||
for (const [k, v] of Object.entries(select) as any) {
|
||||
if (typeof v === "object") {
|
||||
const val = {} as any;
|
||||
Object.keys(v.select)
|
||||
.filter((e) => e !== pks[k])
|
||||
.map((e) => {
|
||||
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 {
|
||||
sample[k] = "sample";
|
||||
}
|
||||
|
||||
return `\
|
||||
}
|
||||
|
||||
return `\
|
||||
(arg: TableOnLoad) => {
|
||||
if (isEditor) return [${JSON.stringify(sample)}];
|
||||
|
||||
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') {
|
||||
return await db.${table}.count();
|
||||
return await db.${table}.count({
|
||||
where: {
|
||||
...where,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const items = await db.${table}.findMany({
|
||||
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
||||
orderBy: arg.orderBy || {
|
||||
${pk}: "desc"
|
||||
},
|
||||
where: {
|
||||
...where,
|
||||
},
|
||||
...arg.paging,
|
||||
});
|
||||
|
||||
|
|
@ -54,5 +77,4 @@ export const on_load = ({
|
|||
where?: any
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ export const MDDetail: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
|||
if (!detail) {
|
||||
return null;
|
||||
}
|
||||
console.log(md.tab.list);
|
||||
return (
|
||||
<>
|
||||
{md.props.show_head === "only-child" && <MDHeader md={md} mdr={mdr} />}
|
||||
|
|
@ -116,10 +115,8 @@ export const MDRenderTab: FC<{
|
|||
}> = ({ child, on_init, breadcrumb }) => {
|
||||
useEffect(() => {
|
||||
let md = on_init();
|
||||
md.breadcrumb.list = breadcrumb();
|
||||
if (!isEditor) {
|
||||
md.breadcrumb.reload();
|
||||
}
|
||||
md.header.breadcrumb = breadcrumb();
|
||||
md.header.render();
|
||||
}, []);
|
||||
return <>{child}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { FC } from "react";
|
||||
import { FC, useState } from "react";
|
||||
import { MDLocal, MDRef } from "../utils/typings";
|
||||
|
||||
export const MDHeader: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
||||
const [_, set] = useState({});
|
||||
const head = mdr.item.edit.props?.header.value;
|
||||
const PassProp = mdr.PassProp;
|
||||
md.header.render = () => set({});
|
||||
return <PassProp md={md}>{head}</PassProp>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ export const MDRenderMaster: FC<{
|
|||
min_size: any;
|
||||
child: any;
|
||||
on_init: () => MDLocal;
|
||||
breadcrumb: () => Array<any>
|
||||
breadcrumb: () => Array<any>;
|
||||
}> = ({ child, on_init, min_size, size, breadcrumb }) => {
|
||||
useEffect(() => {
|
||||
console.log("master");
|
||||
let md = on_init();
|
||||
md.breadcrumb.list = breadcrumb();
|
||||
if(!isEditor){
|
||||
md.breadcrumb.reload();
|
||||
}
|
||||
md.header.breadcrumb = breadcrumb();
|
||||
md.header.render();
|
||||
|
||||
if (md) {
|
||||
let width = 0;
|
||||
let min_width = 0;
|
||||
|
|
@ -33,8 +33,8 @@ export const MDRenderMaster: FC<{
|
|||
md.panel.min_size = min_width;
|
||||
md.panel.size = width;
|
||||
}
|
||||
};
|
||||
}, [])
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <>{child}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
|
|||
md.props.gen_table = gen_table;
|
||||
md.props.on_init = on_init;
|
||||
if (!mdr.master || (mdr.master && !get(mdr, "master.edit.childs.0.childs.length"))) {
|
||||
md.breadcrumb.list = [
|
||||
md.header.breadcrumb = [
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
|
|
@ -39,7 +39,7 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
|
|||
];
|
||||
md.status = "unready";
|
||||
} else {
|
||||
md.breadcrumb.list = [];
|
||||
md.header.breadcrumb = [];
|
||||
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 = {
|
||||
name: string;
|
||||
status: "init" | "unready" | "ready";
|
||||
breadcrumb: {list:BreadItem[], render: () => void, reload: () => void};
|
||||
header: { breadcrumb: BreadItem[]; render: () => void };
|
||||
actions: MDActions;
|
||||
selected: any;
|
||||
tab: {
|
||||
|
|
@ -89,11 +89,13 @@ export type MDLocal = MDLocalInternal & { render: (force?: boolean) => void };
|
|||
export const MasterDetailType = `const md = {
|
||||
name: string;
|
||||
status: string;
|
||||
breadcrumb: {
|
||||
label: React.ReactNode;
|
||||
url?: string;
|
||||
onClick?: () => void;
|
||||
}[];
|
||||
header: {
|
||||
breadcrumb: {
|
||||
label: React.ReactNode;
|
||||
url?: string;
|
||||
onClick?: () => void;
|
||||
}[]
|
||||
};
|
||||
actions: (
|
||||
{
|
||||
action?: string;
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ const buttonVariants = cva(
|
|||
},
|
||||
size: {
|
||||
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",
|
||||
lg: "c-h-11 c-rounded-md c-px-8",
|
||||
icon: "c-h-10 c-w-10",
|
||||
nozise: ""
|
||||
nozise: "",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
|
@ -36,16 +37,16 @@ const buttonVariants = cva(
|
|||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
extends React.ButtonHTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
const Button = React.forwardRef<HTMLDivElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<Comp
|
||||
<div
|
||||
className={cn(
|
||||
buttonVariants({ variant, size, className }),
|
||||
`btn-${variant || "default"} btn c-transition-all c-duration-300`
|
||||
|
|
@ -58,10 +59,10 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
const FloatButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
const FloatButton = React.forwardRef<HTMLDivElement, ButtonProps>(
|
||||
({ variant, className, ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
<div
|
||||
className={cn(
|
||||
buttonVariants({ variant, className }),
|
||||
`btn-${
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ export const TypeaheadOptions: FC<{
|
|||
`
|
||||
: css`
|
||||
min-width: 150px;
|
||||
`
|
||||
`,
|
||||
css`
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{options.map((item, idx) => {
|
||||
|
|
@ -75,7 +79,7 @@ export const TypeaheadOptions: FC<{
|
|||
onSelect?.(item.value);
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
{item.label || <> </>}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Badge } from "./badge";
|
|||
import { TypeaheadOptions } from "./typeahead-opt";
|
||||
|
||||
export const Typeahead: FC<{
|
||||
value?: string[];
|
||||
value?: string[] | null;
|
||||
placeholder?: string;
|
||||
options?: (arg: {
|
||||
search: string;
|
||||
|
|
@ -90,6 +90,7 @@ export const Typeahead: FC<{
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!value) return;
|
||||
if (!isEditor) {
|
||||
if (local.options.length === 0) {
|
||||
loadOptions().then(() => {
|
||||
|
|
@ -105,6 +106,9 @@ export const Typeahead: FC<{
|
|||
if (typeof value === "object" && value) {
|
||||
local.value = value;
|
||||
local.render();
|
||||
} else {
|
||||
local.value = [];
|
||||
local.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +303,17 @@ export const Typeahead: FC<{
|
|||
if (local.mode === "single" && local.value.length > 1) {
|
||||
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);
|
||||
|
||||
if (local.mode === "single") {
|
||||
|
|
@ -341,7 +355,7 @@ export const Typeahead: FC<{
|
|||
}
|
||||
}}
|
||||
>
|
||||
<div>{e?.label}</div>
|
||||
<div>{e?.label || <> </>}</div>
|
||||
<X size={12} />
|
||||
</Badge>
|
||||
);
|
||||
|
|
@ -503,7 +517,7 @@ export const Typeahead: FC<{
|
|||
<div
|
||||
className={cx(
|
||||
"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"
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export { prasi_gen } from "@/gen/prasi_gen";
|
|||
export { password } from "@/utils/password";
|
||||
export { generateTableList } from "@/comps/md/gen/gen-table-list";
|
||||
export { generateForm } from "@/comps/form/gen/gen-form";
|
||||
export { generateSelect } from "@/comps/md/gen/md-select";
|
||||
|
||||
/** Session */
|
||||
export {
|
||||
|
|
@ -81,11 +82,9 @@ export {
|
|||
RG,
|
||||
UserSession,
|
||||
} from "@/preset/login/utils/register";
|
||||
export { prasi_user } from "@/preset/login/utils/user";
|
||||
export { Login } from "@/preset/login/Login";
|
||||
export { logout } from "@/preset/login/utils/logout";
|
||||
export { generateLogin } from "@/preset/login/utils/generate";
|
||||
export { select as generateSelect } from "@/preset/login/utils/select";
|
||||
|
||||
export { Card } from "@/comps/custom/Card";
|
||||
|
||||
|
|
@ -114,4 +113,4 @@ export { getPathname } from "./utils/pathname";
|
|||
|
||||
export * from "@/comps/ui/typeahead";
|
||||
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 `\
|
||||
async ({ form, error }: IForm) => {
|
||||
if (isEditor) return false;
|
||||
if (typeof form !== "object") return false;
|
||||
if (typeof error === "object" && Object.keys(error).length > 0) return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { FC, useEffect } from "react";
|
||||
import { prasi_user } from "./utils/user";
|
||||
import { loadSession } from "./utils/load";
|
||||
|
||||
const w = window as unknown as {
|
||||
user: any;
|
||||
prasi_home: Record<string, string>;
|
||||
};
|
||||
|
||||
|
|
@ -15,8 +16,11 @@ export const Login: FC<LGProps> = (props) => {
|
|||
w.prasi_home = props.url_home[0];
|
||||
useEffect(() => {
|
||||
try {
|
||||
const home = prasi_user.prasi_home[prasi_user.user.m_role.name];
|
||||
navigate(home);
|
||||
loadSession();
|
||||
if (w.user) {
|
||||
const home = w.prasi_home[w.user.m_role.name];
|
||||
navigate(home);
|
||||
}
|
||||
} catch (e: any) {}
|
||||
}, []);
|
||||
return <>{props.body}</>;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ export const generateLogin = async (
|
|||
});
|
||||
if (data_user) {
|
||||
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);
|
||||
}
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -4,27 +4,26 @@ import { logout } from "./logout";
|
|||
const w = window as any;
|
||||
const parse = parser.exportAsFunctionAny("en-US");
|
||||
export const loadSession = (url_login?: string) => {
|
||||
try {
|
||||
const user = localStorage.getItem("user");
|
||||
if (user) {
|
||||
const raw = JSON.parse(user);
|
||||
w.user = raw.data;
|
||||
if (typeof raw === "object") {
|
||||
const session: UserSession = raw;
|
||||
const expired = parse(session.expired);
|
||||
if (
|
||||
typeof expired === "object" &&
|
||||
expired instanceof Date
|
||||
) {
|
||||
if (new Date() > expired) {
|
||||
logout(url_login);
|
||||
if (!isEditor) {
|
||||
try {
|
||||
const user = localStorage.getItem("user");
|
||||
if (user) {
|
||||
const raw = JSON.parse(user);
|
||||
w.user = raw.data;
|
||||
if (typeof raw === "object") {
|
||||
const session: UserSession = raw;
|
||||
const expired = parse(session.expired);
|
||||
if (expired instanceof Date) {
|
||||
if (new Date() > expired) {
|
||||
if (url_login) logout(url_login);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (url_login) logout(url_login);
|
||||
}
|
||||
} else {
|
||||
logout(url_login);
|
||||
} catch (e) {
|
||||
if (url_login) logout(url_login);
|
||||
}
|
||||
} catch (e) {
|
||||
logout(url_login);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,5 @@ export const logout = (url_login?: string) => {
|
|||
if (localStorage.getItem("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;
|
||||
tablet?: ReactNode;
|
||||
child?: ReactNode;
|
||||
children: ReactNode;
|
||||
default_layout: ReactNode;
|
||||
exception?: Array<string>;
|
||||
defaultLayout: ReactNode;
|
||||
blank_layout: ReactNode;
|
||||
};
|
||||
|
||||
export const Layout: FC<LYTChild> = (props) => {
|
||||
|
|
@ -64,12 +64,18 @@ export const Layout: FC<LYTChild> = (props) => {
|
|||
const no_layout = props.exception;
|
||||
useEffect(() => {
|
||||
loadSession("/auth/login");
|
||||
render();
|
||||
}, []);
|
||||
if (Array.isArray(no_layout))
|
||||
|
||||
if (!isEditor && Array.isArray(no_layout)) {
|
||||
if (no_layout.length) {
|
||||
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 = (
|
||||
where: any,
|
||||
soft: {
|
||||
field: string;
|
||||
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 : {};
|
||||
if (isEmptyString(soft.field) || isEmptyString(soft.type))
|
||||
return defaultParam;
|
||||
const result = {
|
||||
AND: [
|
||||
typeof where === "object"
|
||||
? { ...defaultParam }
|
||||
: {
|
||||
[soft.field]:
|
||||
soft.type === "boolean"
|
||||
? true
|
||||
: {
|
||||
not: null,
|
||||
},
|
||||
},
|
||||
typeof defaultParam === "object" ? { ...defaultParam } : {},
|
||||
{
|
||||
[soft.field]:
|
||||
soft.type === "boolean"
|
||||
? false
|
||||
:null,
|
||||
},
|
||||
],
|
||||
};
|
||||
console.log(result);
|
||||
return result;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue