wip fix filter
This commit is contained in:
parent
13bd7e3858
commit
4433f5fcd1
|
|
@ -0,0 +1,32 @@
|
|||
import capitalize from "lodash.capitalize";
|
||||
import { FC } from "react";
|
||||
import { FilterFieldType, modifiers } from "./utils/types";
|
||||
|
||||
export const FieldModifier: FC<{
|
||||
type: FilterFieldType;
|
||||
modifier: string;
|
||||
onChange: (modifier: string) => void;
|
||||
}> = ({ type, modifier, onChange }) => {
|
||||
if (!modifier && modifiers[type]) {
|
||||
onChange(Object.keys(modifiers[type])[0]);
|
||||
}
|
||||
|
||||
return (
|
||||
<select
|
||||
onChange={(e) => {
|
||||
const val = e.currentTarget.value;
|
||||
onChange(val);
|
||||
}}
|
||||
>
|
||||
{modifiers[type]
|
||||
? Object.entries(modifiers[type]).map(([value, label]) => {
|
||||
return (
|
||||
<option selected={modifier === value} value={value}>
|
||||
{label}
|
||||
</option>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import get from "lodash.get";
|
||||
import { FC, ReactNode, useEffect, useRef } from "react";
|
||||
import { FMLocal } from "../form/Form";
|
||||
import { createPortal, render } from "react-dom";
|
||||
import { Label } from "@/comps/ui/label";
|
||||
import { Input } from "@/comps/ui/input";
|
||||
|
||||
type FilterPosition = 'regular' | 'inline' | 'popup';
|
||||
|
||||
type FilterForm = {
|
||||
gen_fields: GenField[];
|
||||
gen_table: string;
|
||||
name: string;
|
||||
value: any;
|
||||
position: FilterPosition;
|
||||
children?: ReactNode;
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
type GenField = {
|
||||
name: string,
|
||||
is_pk: boolean,
|
||||
type: string,
|
||||
optional: boolean
|
||||
};
|
||||
|
||||
export const MasterFilter: FC<FilterForm> = ({ gen_fields, gen_table, name, value, position, children, onClose }): ReactNode => {
|
||||
const local = useLocal({
|
||||
data: [] as any[],
|
||||
columns: [] as string[],
|
||||
fields: [] as GenField[],
|
||||
tableName: "",
|
||||
isGenerated: false,
|
||||
// fm: {} as FMLocal,
|
||||
argInit: {} as { fm: FMLocal; submit: any; reload: any },
|
||||
argOnLoad: {} as { arg: { fm: FMLocal } },
|
||||
argOnSubmit: {} as {
|
||||
arg: {
|
||||
fm: FMLocal;
|
||||
form: any;
|
||||
error: any;
|
||||
}
|
||||
}
|
||||
});
|
||||
useEffect(() => {
|
||||
if (!isEditor) {
|
||||
const w = window as any;
|
||||
if (typeof w["prasi_filter"] !== "object") w["prasi_filter"] = {};
|
||||
if (typeof w["prasi_filter"][name] !== "object")
|
||||
w["prasi_filter"][name] = {};
|
||||
const val = value();
|
||||
w["prasi_filter"][name] = {
|
||||
...w["prasi_filter"][name],
|
||||
...val
|
||||
};
|
||||
w.prasiContext.render();
|
||||
}
|
||||
}, [])
|
||||
|
||||
const renderContent = (): ReactNode => (
|
||||
<div className={`filter-content filter-${position}`}>
|
||||
<h3>Filter</h3>
|
||||
<form>
|
||||
{local.fields.map((field) => (
|
||||
<div>
|
||||
{field.type === 'varchar' && (
|
||||
<div className="grid w-full max-w-sm items-center gap-1.5" >
|
||||
<Label htmlFor={field.name}>{field.name}</Label>
|
||||
<Input id={field.name} type="text" />
|
||||
</div>
|
||||
)}
|
||||
{field.type === "number" && (
|
||||
<div className="grid w-full max-w-sm items-center gap-1.5" >
|
||||
<Label htmlFor={field.name}>{field.name}</Label>
|
||||
<Input id={field.name} type="number" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</form >
|
||||
</div >
|
||||
);
|
||||
|
||||
const generateFilter = () => {
|
||||
local.isGenerated = true;
|
||||
local.tableName = gen_table;
|
||||
gen_fields.forEach((data: any) => {
|
||||
local.fields.push(JSON.parse(data));
|
||||
});
|
||||
local.render();
|
||||
console.log('tableName', local.tableName);
|
||||
console.log('fields', local.fields);
|
||||
};
|
||||
|
||||
if (position === 'popup') {
|
||||
let popup = document.querySelector(".main-content-preview > .portal");
|
||||
if (!popup) {
|
||||
popup = document.createElement("div");
|
||||
popup.classList.add("portal");
|
||||
|
||||
const main = document.querySelector(".main-content-preview");
|
||||
if (main) {
|
||||
main.appendChild(popup);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{createPortal(
|
||||
<div
|
||||
onClick={onClose}
|
||||
className={cx(
|
||||
css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background: white;
|
||||
z-index: 100;
|
||||
`,
|
||||
"c-flex c-flex-col"
|
||||
)}
|
||||
>
|
||||
{renderContent()}
|
||||
</div>,
|
||||
popup
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (local.isGenerated) {
|
||||
return renderContent();
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
onClick={generateFilter}
|
||||
style={{
|
||||
backgroundColor: "#4CAF50",
|
||||
border: "none",
|
||||
color: "white",
|
||||
padding: "15px 32px",
|
||||
textAlign: "center",
|
||||
textDecoration: "none",
|
||||
display: "inline-block",
|
||||
fontSize: "16px",
|
||||
margin: "4px 2px",
|
||||
cursor: "pointer",
|
||||
borderRadius: "10px",
|
||||
}}
|
||||
>
|
||||
Generate
|
||||
</button>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { FC } from "react";
|
||||
import { BaseForm } from "../form/base/BaseForm";
|
||||
import { FilterLocal } from "./utils/types";
|
||||
import { useLocal } from "lib/utils/use-local";
|
||||
|
||||
export const FilterContent: FC<{
|
||||
mode: string;
|
||||
filter: FilterLocal;
|
||||
PassProp: any;
|
||||
child: any;
|
||||
_item: PrasiItem;
|
||||
}> = ({ mode, filter, PassProp, child, _item }) => {
|
||||
const internal = useLocal({});
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
`c-flex c-flex-1 filter-content filter-${mode}`,
|
||||
css`
|
||||
&.filter-content {
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
&.filter-regular {
|
||||
width: 100%;
|
||||
/* Styles specific to sidebar */
|
||||
}
|
||||
|
||||
&.filter-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* Styles specific to topbar */
|
||||
}
|
||||
|
||||
&.filter-popup {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1000;
|
||||
/* Styles specific to popup */
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
<BaseForm
|
||||
data={filter.data}
|
||||
on_submit={(form) => {
|
||||
console.log("skrg nyubmit");
|
||||
}}
|
||||
render={internal.render}
|
||||
>
|
||||
{(form) => {
|
||||
filter.form = form;
|
||||
return (
|
||||
<>
|
||||
{!!(PassProp && child) && (
|
||||
<PassProp filter={filter}>{child}</PassProp>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</BaseForm>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import { FC, useEffect } from "react";
|
||||
import { BaseField } from "../form/base/BaseField";
|
||||
import { FilterLocal, filter_window } from "./utils/types";
|
||||
import { FieldTypeText } from "../form/field/type/TypeText";
|
||||
import { FieldModifier } from "./FieldModifier";
|
||||
import { useLocal } from "lib/utils/use-local";
|
||||
|
||||
export const FilterField: FC<{
|
||||
filter: FilterLocal;
|
||||
name?: string;
|
||||
label?: string;
|
||||
type: "text" | "number" | "boolean";
|
||||
}> = ({ filter, name, label, type }) => {
|
||||
const internal = useLocal({ render_timeout: null as any });
|
||||
if (!name) return <>No Name</>;
|
||||
if (!filter.form) return <div>Loading...</div>;
|
||||
|
||||
filter.types[name] = type;
|
||||
|
||||
useEffect(() => {
|
||||
clearTimeout(internal.render_timeout);
|
||||
internal.render_timeout = setTimeout(() => {
|
||||
filter_window.prasiContext.render();
|
||||
}, 500);
|
||||
}, [filter.form?.data[name]]);
|
||||
|
||||
return (
|
||||
<BaseField
|
||||
{...filter.form.fieldProps({
|
||||
name: name || "",
|
||||
label: label || name || "",
|
||||
render: internal.render,
|
||||
prefix: () => (
|
||||
<FieldModifier
|
||||
onChange={(modifier) => {
|
||||
filter.modifiers[name] = modifier;
|
||||
filter.render();
|
||||
filter_window.prasiContext.render();
|
||||
}}
|
||||
modifier={filter.modifiers[name]}
|
||||
type={type}
|
||||
/>
|
||||
),
|
||||
})}
|
||||
>
|
||||
{(field) => (
|
||||
<>
|
||||
{type === "text" && (
|
||||
<FieldTypeText
|
||||
{...field}
|
||||
prop={{
|
||||
type: "text",
|
||||
sub_type: "text",
|
||||
prefix: "",
|
||||
suffix: "",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{type === "number" && (
|
||||
<FieldTypeText
|
||||
{...field}
|
||||
prop={{
|
||||
type: "text",
|
||||
sub_type: "number",
|
||||
prefix: "",
|
||||
suffix: "",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</BaseField>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import { FC, ReactNode } from "react";
|
||||
|
||||
export const Label: FC<{ children: ReactNode; text: string }> = ({
|
||||
children,
|
||||
text,
|
||||
}) => {
|
||||
return (
|
||||
<label className="field c-flex c-w-full c-flex-col c-space-y-1 c-px-2">
|
||||
<div className="label c-text-sm c-flex c-items-center c-mt-3 c-capitalize">
|
||||
{text}
|
||||
</div>
|
||||
<div className="field-inner c-flex c-flex-1 c-flex-col">
|
||||
<div
|
||||
className={cx(
|
||||
"field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm c-flex-wrap",
|
||||
css`
|
||||
> * {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import { FC, ReactNode, useEffect } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { GenField } from "../form/typings";
|
||||
import { default_filter_local, filter_window } from "./utils/types";
|
||||
import { FilterContent } from "./FilterContent";
|
||||
import { getPathname } from "lib/utils/pathname";
|
||||
|
||||
type FilterMode = "regular" | "inline" | "popup";
|
||||
|
||||
type FilterProps = {
|
||||
gen_fields: GenField[];
|
||||
gen_table: string;
|
||||
name: string;
|
||||
value: any;
|
||||
mode: FilterMode;
|
||||
children?: ReactNode;
|
||||
onClose?: () => void;
|
||||
PassProp: any;
|
||||
child: any;
|
||||
_item: PrasiItem;
|
||||
};
|
||||
|
||||
export const MasterFilter: FC<FilterProps> = ({
|
||||
gen_fields,
|
||||
gen_table,
|
||||
name,
|
||||
value,
|
||||
mode,
|
||||
PassProp,
|
||||
child,
|
||||
onClose,
|
||||
_item,
|
||||
}): ReactNode => {
|
||||
const filter = useLocal({ ...default_filter_local });
|
||||
filter.name = name;
|
||||
|
||||
if (!isEditor) {
|
||||
if (!filter_window.prasi_filter) {
|
||||
filter_window.prasi_filter = {};
|
||||
}
|
||||
const pf = filter_window.prasi_filter;
|
||||
if (pf) {
|
||||
const pathname = getPathname();
|
||||
if (!pf[pathname]) pf[pathname] = {};
|
||||
if (!pf[pathname][name]) pf[pathname][name] = {};
|
||||
pf[pathname][name][_item.id] = filter;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode === "popup") {
|
||||
let popup = document.querySelector(".main-content-preview > .portal");
|
||||
if (!popup) {
|
||||
popup = document.createElement("div");
|
||||
popup.classList.add("portal");
|
||||
|
||||
const main = document.querySelector(".main-content-preview");
|
||||
if (main) {
|
||||
main.appendChild(popup);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{createPortal(
|
||||
<div
|
||||
onClick={onClose}
|
||||
className={cx(
|
||||
css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background: white;
|
||||
z-index: 100;
|
||||
`,
|
||||
"c-flex c-flex-col"
|
||||
)}
|
||||
>
|
||||
<FilterContent
|
||||
PassProp={PassProp}
|
||||
child={child}
|
||||
mode={mode}
|
||||
_item={_item}
|
||||
filter={filter}
|
||||
/>
|
||||
</div>,
|
||||
popup
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FilterContent
|
||||
PassProp={PassProp}
|
||||
_item={_item}
|
||||
child={child}
|
||||
mode={mode}
|
||||
filter={filter}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
.filter-content {
|
||||
padding: 1rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.filter-regular {
|
||||
width: 250px;
|
||||
/* Styles specific to sidebar */
|
||||
}
|
||||
|
||||
.filter-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* Styles specific to topbar */
|
||||
}
|
||||
|
||||
.filter-popup {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1000;
|
||||
/* Styles specific to popup */
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import { getPathname } from "lib/utils/pathname";
|
||||
import { filter_window } from "./types";
|
||||
|
||||
export const filterWhere = (filter_name: string) => {
|
||||
const pf = filter_window.prasi_filter?.[getPathname()]?.[filter_name];
|
||||
const where: any = {};
|
||||
const AND: any[] = [];
|
||||
|
||||
if (pf) {
|
||||
for (const [k, filter] of Object.entries(pf)) {
|
||||
for (const [name, value] of Object.entries(filter.data)) {
|
||||
const type = filter.types[name];
|
||||
const modifier = filter.modifiers[name];
|
||||
|
||||
switch (type) {
|
||||
case "text":
|
||||
{
|
||||
if (modifier === "contains")
|
||||
where[name] = {
|
||||
contains: value,
|
||||
mode: "insensitive",
|
||||
};
|
||||
}
|
||||
break;
|
||||
case "date": {
|
||||
let is_value_valid = false;
|
||||
// TODO: pastikan value bisa diparse pakai any-date-parser
|
||||
if (is_value_valid) {
|
||||
if (modifier === "between") {
|
||||
AND.push({ [name]: { gt: value } });
|
||||
AND.push({ [name]: { lt: value } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AND.length > 0) where.AND = AND;
|
||||
}
|
||||
return where;
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { BaseFormLocal } from "../../form/base/types";
|
||||
import { GenField } from "../../form/typings";
|
||||
|
||||
export type FilterFieldType = "text" | "number" | "boolean" | "date";
|
||||
export const default_filter_local = {
|
||||
data: {} as any,
|
||||
columns: [] as string[],
|
||||
fields: [] as GenField[],
|
||||
tableName: "",
|
||||
form: null as null | BaseFormLocal<any>,
|
||||
modifiers: {} as Record<string, string>,
|
||||
types: {} as Record<string, FilterFieldType>,
|
||||
name: "",
|
||||
};
|
||||
|
||||
export const modifiers = {
|
||||
text: { contains: "Contains", ends_with: "Ends With" },
|
||||
boolean: {},
|
||||
number: {},
|
||||
date: {
|
||||
between: "Between",
|
||||
},
|
||||
};
|
||||
export type FilterModifier = typeof modifiers;
|
||||
|
||||
export type FilterLocal = typeof default_filter_local & { render: () => void };
|
||||
|
||||
export const filter_window = window as unknown as {
|
||||
prasi_filter: Record<string, Record<string, Record<string, FilterLocal>>>;
|
||||
prasiContext: {
|
||||
render: () => void;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
import { ReactNode } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../typings";
|
||||
import { Label } from "../field/Label";
|
||||
import { FieldLoading } from "../field/raw/FieldLoading";
|
||||
|
||||
export const BaseField = (prop: {
|
||||
field: FieldLocal;
|
||||
fm: FMLocal;
|
||||
arg: FieldProp;
|
||||
children: (arg: {
|
||||
field: FieldLocal;
|
||||
fm: FMLocal;
|
||||
arg: FieldProp;
|
||||
}) => ReactNode;
|
||||
}) => {
|
||||
const { field, fm, arg } = prop;
|
||||
const w = field.width;
|
||||
const mode = fm.props.label_mode;
|
||||
const prefix =
|
||||
typeof field.prefix === "function"
|
||||
? field.prefix()
|
||||
: typeof field.prefix === "string"
|
||||
? field.prefix
|
||||
: null;
|
||||
const suffix =
|
||||
typeof field.suffix === "function"
|
||||
? field.suffix()
|
||||
: typeof field.suffix === "string"
|
||||
? field.prefix
|
||||
: null;
|
||||
const name = field.name;
|
||||
const errors = fm.error.get(name);
|
||||
let type_field = typeof arg.type === "function" ? arg.type() : arg.type; // tipe field
|
||||
|
||||
return (
|
||||
<label
|
||||
className={cx(
|
||||
"field",
|
||||
"c-flex",
|
||||
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",
|
||||
w === "⅓" && "c-w-1/3",
|
||||
w === "¼" && "c-w-1/4",
|
||||
mode === "horizontal" && "c-flex-row c-items-center",
|
||||
mode === "vertical" && "c-flex-col c-space-y-1"
|
||||
)}
|
||||
>
|
||||
{mode !== "hidden" && <Label field={field} fm={fm} />}
|
||||
<div className="field-inner c-flex c-flex-1 c-flex-col">
|
||||
<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 c-flex-wrap"
|
||||
: "",
|
||||
fm.status === "loading"
|
||||
? css`
|
||||
border-color: transparent;
|
||||
`
|
||||
: field.disabled
|
||||
? "c-border-gray-100"
|
||||
: errors.length > 0
|
||||
? field.focused
|
||||
? "c-border-red-600 c-bg-red-50 c-outline c-outline-red-700"
|
||||
: "c-border-red-600 c-bg-red-50"
|
||||
: field.focused &&
|
||||
"c-border-blue-700 c-outline c-outline-blue-700",
|
||||
css`
|
||||
& > .field-inner {
|
||||
min-height: 35px;
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
{prefix && prefix !== "" ? (
|
||||
<div
|
||||
className="
|
||||
c-px-2 c-bg-gray-200 c-flex c-flex-row c-items-center"
|
||||
>
|
||||
{prefix}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{fm.status === "loading" ? (
|
||||
<FieldLoading />
|
||||
) : (
|
||||
<div
|
||||
className={cx(
|
||||
"field-inner c-flex-1 c-flex c-items-center",
|
||||
field.disabled && "c-pointer-events-none"
|
||||
)}
|
||||
>
|
||||
{prop.children(prop)}
|
||||
</div>
|
||||
)}
|
||||
{suffix && suffix !== "" ? (
|
||||
<div
|
||||
className="
|
||||
c-px-2 c-bg-gray-200 c-flex c-flex-row c-items-center"
|
||||
>
|
||||
{suffix}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
import { ReactNode, useCallback, useEffect, useState } from "react";
|
||||
import { BaseFormLocal, default_base_form_local } from "./types";
|
||||
import { useLocal } from "lib/utils/use-local";
|
||||
import { FieldLocal, FieldProp } from "../typings";
|
||||
|
||||
export type BaseFormProps<T> = {
|
||||
data: T;
|
||||
className?: string;
|
||||
on_submit?: (form: BaseFormLocal<T>) => Promise<any> | any;
|
||||
children: ReactNode | ((form: BaseFormLocal<T>) => ReactNode);
|
||||
render?: () => void;
|
||||
};
|
||||
export const BaseForm = <T extends Record<string, any>>(
|
||||
props: BaseFormProps<T>
|
||||
) => {
|
||||
const { data, children, className, on_submit, render } = props;
|
||||
const form = useLocal({ ...default_base_form_local }) as BaseFormLocal<T>;
|
||||
|
||||
if (render) {
|
||||
form.render = render;
|
||||
}
|
||||
|
||||
form.submit = useCallback(async () => {
|
||||
if (form.status === "ready") {
|
||||
form.status = "submitting";
|
||||
form.render();
|
||||
|
||||
const result = await on_submit?.(form);
|
||||
|
||||
setTimeout(() => {
|
||||
form.status = "ready";
|
||||
form.render();
|
||||
}, 1000);
|
||||
|
||||
return result;
|
||||
}
|
||||
}, [on_submit]);
|
||||
|
||||
form.createArg = (arg) => {
|
||||
const prop: FieldProp = { name: arg.name } as any;
|
||||
if (arg.onChange) prop.on_change = arg.onChange;
|
||||
return prop;
|
||||
};
|
||||
|
||||
form.createField = (arg) => {
|
||||
const prop: FieldLocal = {
|
||||
name: arg.name,
|
||||
label: typeof arg.label !== "undefined" ? arg.label : arg.name,
|
||||
render: arg.render || form.render,
|
||||
width: "auto",
|
||||
prefix: arg.prefix,
|
||||
} as any;
|
||||
return prop;
|
||||
};
|
||||
|
||||
form.createFm = () => {
|
||||
return {
|
||||
data: form.data,
|
||||
props: { label_mode: "vertical" },
|
||||
error: {
|
||||
get: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
size: { field: "full" },
|
||||
render: form.render,
|
||||
} as any;
|
||||
};
|
||||
|
||||
form.fieldProps = (arg) => {
|
||||
return {
|
||||
fm: form.createFm(),
|
||||
arg: form.createArg(arg),
|
||||
field: form.createField(arg),
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.data = data;
|
||||
form.render();
|
||||
}, [data]);
|
||||
|
||||
if (form.status === "init") {
|
||||
form.status = "ready";
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.submit();
|
||||
}}
|
||||
className={cx(
|
||||
"form c-flex-1 c-flex-col c-w-full c-h-full c-relative c-overflow-auto",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
"form-inner c-flex c-flex-1 c-flex-wrap c-items-start c-content-start c-absolute c-inset-0",
|
||||
css`
|
||||
padding-right: 10px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{typeof children === "function" ? children(form) : children}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { ReactNode } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../typings";
|
||||
|
||||
export const default_base_form_local = {
|
||||
status: "init" as "init" | "submitting" | "ready",
|
||||
data: {} as any,
|
||||
};
|
||||
|
||||
type CreateFieldArg = {
|
||||
name: string;
|
||||
label?: string;
|
||||
prefix?: ReactNode | (() => ReactNode);
|
||||
onChange?: (value: any) => void;
|
||||
render?: () => void;
|
||||
};
|
||||
|
||||
export type BaseFormLocal<T> = Omit<typeof default_base_form_local, "data"> & {
|
||||
data: T;
|
||||
createArg: (arg: CreateFieldArg) => FieldProp;
|
||||
createField: (arg: CreateFieldArg) => FieldLocal;
|
||||
createFm: () => FMLocal;
|
||||
fieldProps: (arg: CreateFieldArg) => {
|
||||
fm: FMLocal;
|
||||
field: FieldLocal;
|
||||
arg: FieldProp;
|
||||
};
|
||||
submit: () => Promise<any> | any;
|
||||
render: () => void;
|
||||
};
|
||||
|
|
@ -55,7 +55,6 @@ export const TypeDropdown: FC<{
|
|||
} else {
|
||||
selected = value;
|
||||
}
|
||||
console.log({selected})
|
||||
return (
|
||||
<>
|
||||
{field.status === "loading" ? (
|
||||
|
|
@ -75,7 +74,6 @@ export const TypeDropdown: FC<{
|
|||
if (item[input.pk] === val) {
|
||||
fm.data[field.name] = val;
|
||||
fm.render();
|
||||
arg.on_change({value: item})
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import { FC } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||
import { AutoHeightTextarea } from "@/comps/custom/AutoHeightTextarea";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import parser from "any-date-parser";
|
||||
import { AutoHeightTextarea } from "@/comps/custom/AutoHeightTextarea";
|
||||
import { M } from "src/data/unitShortcuts";
|
||||
import { format } from "date-fns";
|
||||
import get from "lodash.get";
|
||||
import { FC } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||
import { FieldMoney } from "./TypeMoney";
|
||||
import { FieldUpload } from "./TypeUpload";
|
||||
import { FieldRichText } from "./TypeRichText";
|
||||
import { FieldUpload } from "./TypeUpload";
|
||||
|
||||
export type PropTypeText = {
|
||||
type: "text" | "date";
|
||||
|
|
@ -45,9 +43,11 @@ export const FieldTypeText: FC<{
|
|||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const input = useLocal({});
|
||||
let display: any = null;
|
||||
let value: any = fm.data[field.name];
|
||||
|
||||
// let value: any = "2024-05-14T05:58:01.376Z" // case untuk date time
|
||||
field.input = input;
|
||||
field.prop = prop;
|
||||
|
|
@ -75,6 +75,7 @@ export const FieldTypeText: FC<{
|
|||
} else if (["number"].includes(type_field)) {
|
||||
value = Number(value) || null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{type_field === "textarea" ? (
|
||||
|
|
@ -153,7 +154,6 @@ export const FieldTypeText: FC<{
|
|||
<input
|
||||
type={type_field}
|
||||
onChange={(ev) => {
|
||||
console.log("onchange");
|
||||
if (["date", "datetime", "datetime-local"].includes(type_field)) {
|
||||
let result = null;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,16 @@ export type FMProps = {
|
|||
on_load_deps?: any[];
|
||||
};
|
||||
|
||||
export type GenField = {
|
||||
name: string,
|
||||
is_pk: boolean,
|
||||
type: string,
|
||||
optional: boolean,
|
||||
} | {
|
||||
checked: GenField[],
|
||||
value: GFCol
|
||||
};
|
||||
|
||||
type FieldType =
|
||||
| "-"
|
||||
| "relation"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ type TableListProp = {
|
|||
}) => Promise<any[]>;
|
||||
on_init: (arg?: any) => any;
|
||||
mode: "table" | "list" | "grid" | "auto";
|
||||
_meta: Record<string, any>;
|
||||
// _meta: Record<string, any>;
|
||||
_item: PrasiItem;
|
||||
gen_fields: string[];
|
||||
row_click: OnRowClick;
|
||||
selected: SelectedRow;
|
||||
|
|
@ -61,7 +62,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
PassProp,
|
||||
mode,
|
||||
on_init,
|
||||
_meta,
|
||||
_item,
|
||||
gen_fields,
|
||||
row_click,
|
||||
selected,
|
||||
|
|
@ -247,7 +248,6 @@ export const TableList: FC<TableListProp> = ({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const checked = !!local.selectedRows.find((data) => data.pk === rowId);
|
||||
console.log(checked);
|
||||
if (!checked) {
|
||||
// jika checkbox tercheck, maka rowData akan diambil jika memiliki id yang sama dengan rowId yang dikirim
|
||||
const checkedRowData = rowData.filter((row) => row[pk] === rowId);
|
||||
|
|
@ -256,14 +256,12 @@ export const TableList: FC<TableListProp> = ({
|
|||
rows: checkedRowData,
|
||||
});
|
||||
local.render();
|
||||
console.log("selected", local.selectedRows);
|
||||
} else {
|
||||
// jika tidak, maka akan dihapus
|
||||
local.selectedRows = local.selectedRows.filter(
|
||||
(data) => data.pk !== rowId
|
||||
);
|
||||
local.render();
|
||||
console.log("deselected", local.selectedRows);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -271,9 +269,12 @@ export const TableList: FC<TableListProp> = ({
|
|||
(e: any) => e.name === sub_name || e.name === mode
|
||||
);
|
||||
if (mode_child) {
|
||||
const meta = _meta[mode_child.id];
|
||||
if (meta && meta.item.childs) {
|
||||
childs = meta.item.childs;
|
||||
const tbl = _item.edit.childs[0].edit.childs.find(
|
||||
(e) => get(e, "id") === mode_child.id
|
||||
);
|
||||
const meta = tbl;
|
||||
if (meta && meta.childs) {
|
||||
childs = meta.childs;
|
||||
}
|
||||
}
|
||||
let columns: ColumnOrColumnGroup<any>[] = [];
|
||||
|
|
@ -322,37 +323,36 @@ export const TableList: FC<TableListProp> = ({
|
|||
cellClass: selectCellClassname,
|
||||
});
|
||||
}
|
||||
// for (const child of childs) {
|
||||
// const key = getProp(child, "name", {});
|
||||
// const name = getProp(child, "title", {});
|
||||
// const width = parseInt(getProp(child, "width", {}));
|
||||
for (const child of childs) {
|
||||
const key = getProp(child, "name", {});
|
||||
const name = getProp(child, "title", {});
|
||||
const width = parseInt(getProp(child, "width", {}));
|
||||
|
||||
// columns.push({
|
||||
// key,
|
||||
// name,
|
||||
// width: width > 0 ? width : undefined,
|
||||
// resizable: true,
|
||||
// sortable: true,
|
||||
// renderCell(props) {
|
||||
// return (
|
||||
// <PassProp
|
||||
// idx={props.rowIdx}
|
||||
// row={props.row}
|
||||
// col={{
|
||||
// name: props.column.key,
|
||||
// value: props.row[props.column.key],
|
||||
// depth: props.row.__depth || 0,
|
||||
// }}
|
||||
// rows={local.data}
|
||||
// >
|
||||
// {child}
|
||||
// </PassProp>
|
||||
// );
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: width > 0 ? width : undefined,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
renderCell(props) {
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: props.column.key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={local.data}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (mode === "list") {
|
||||
// ambil satu index saja;
|
||||
if (columns.length > 1) columns = columns.slice(0, 0 + 1);
|
||||
}
|
||||
|
||||
|
|
@ -420,12 +420,19 @@ export const TableList: FC<TableListProp> = ({
|
|||
if (id_parent && local.pk && local.sort.columns.length === 0) {
|
||||
data = sortTree(local.data, id_parent, local.pk.name);
|
||||
}
|
||||
console.log("render?")
|
||||
// return "123"
|
||||
if (mode === "table") {
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
"c-w-full c-h-full c-flex-1 c-relative c-overflow-hidden",
|
||||
dataGridStyle(local)
|
||||
dataGridStyle(local),
|
||||
css`
|
||||
.rdg {
|
||||
display: grid !important;
|
||||
}
|
||||
`
|
||||
)}
|
||||
ref={(el) => {
|
||||
if (!local.el && el) {
|
||||
|
|
@ -485,7 +492,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
row: props.row,
|
||||
rows: local.data,
|
||||
});
|
||||
// return "halo"
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={key}
|
||||
|
|
@ -651,3 +658,11 @@ function isAtBottom({ currentTarget }: React.UIEvent<HTMLDivElement>): boolean {
|
|||
currentTarget.scrollHeight - currentTarget.clientHeight
|
||||
);
|
||||
}
|
||||
|
||||
function getProp(child: IItem, name: string, defaultValue?: any) {
|
||||
const fn = new Function(
|
||||
`return ${get(child, `component.props.${name}.valueBuilt`) || `null`}`
|
||||
);
|
||||
|
||||
return fn() || defaultValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ export const MasterDetail: FC<MDProps> = (arg) => {
|
|||
if (isEditor) {
|
||||
editorMDInit(md, mdr, arg);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
import { createItem } from "lib/gen/utils";
|
||||
import capitalize from "lodash.capitalize";
|
||||
import { ArrowBigDown } from "lucide-react";
|
||||
export type GFCol = {
|
||||
name: string;
|
||||
type: string;
|
||||
is_pk: boolean;
|
||||
optional: boolean;
|
||||
relation?: {
|
||||
from: { table: string; fields: string[] };
|
||||
to: { table: string; fields: string[] };
|
||||
fields: GFCol[];
|
||||
};
|
||||
};
|
||||
export const newField = (arg: GFCol, opt: { parent_table: string, value: Array<string> }) => {
|
||||
console.log({ arg, opt });
|
||||
let type = "input";
|
||||
if (["int", "string", "text"].includes(arg.type)) {
|
||||
if (["int"].includes(arg.type)) {
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type,
|
||||
sub_type: "number",
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type,
|
||||
sub_type: "text",
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (["timestamptz", "date"].includes(arg.type) && arg.relation) {
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type: "date",
|
||||
sub_type: "datetime",
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} else if (["has-many", "has-one"].includes(arg.type) && arg.relation) {
|
||||
if(["has-one"].includes(arg.type)){
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type: "single-option",
|
||||
sub_type: "dropdown",
|
||||
rel__gen_table: arg.name,
|
||||
rel__gen_fields: [`[${opt.value.join(",")}]`],
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// return {
|
||||
// name: "item",
|
||||
// type: "item",
|
||||
// component: {
|
||||
// id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
// props: {
|
||||
// name: {
|
||||
// mode: "string",
|
||||
// value: arg.name
|
||||
// },
|
||||
// label: {
|
||||
// mode: "string",
|
||||
// value: formatName(arg.name)
|
||||
// },
|
||||
// type: {
|
||||
// mode: "string",
|
||||
// value: "single-option"
|
||||
// },
|
||||
// sub_type: {
|
||||
// mode: "string",
|
||||
// value: "dropdown"
|
||||
// },
|
||||
// rel__gen_table: {
|
||||
// mode: "string",
|
||||
// value: arg.name
|
||||
// },
|
||||
// rel__gen_fields: {
|
||||
// mode: "raw",
|
||||
// value: `${JSON.stringify(opt.val)}`
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
}else{
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type: "date",
|
||||
sub_type: "datetime",
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// type not found,
|
||||
return createItem({
|
||||
component: {
|
||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||
props: {
|
||||
name: arg.name,
|
||||
label: formatName(arg.name),
|
||||
type,
|
||||
sub_type: "text",
|
||||
child: {
|
||||
childs: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
export const formatName = (name: string) => {
|
||||
return (name || "")
|
||||
.split("_")
|
||||
.filter((e) => e.length > 1)
|
||||
.map((e) => capitalize(e))
|
||||
.join(" ");
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { GFCol } from "./fields";
|
||||
|
||||
export const on_load = ({
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
opt,
|
||||
}: {
|
||||
pk: GFCol;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
opt?: {
|
||||
before_load: string;
|
||||
after_load: string;
|
||||
};
|
||||
}) => {
|
||||
const sample: any = {};
|
||||
for (const [k, v] of Object.entries(select) as any) {
|
||||
if (typeof v === "object") {
|
||||
sample[k] = {};
|
||||
|
||||
Object.keys(v.select).map((e) => {
|
||||
sample[k][e] = "sample";
|
||||
});
|
||||
} else {
|
||||
sample[k] = "sample";
|
||||
}
|
||||
}
|
||||
|
||||
return `\
|
||||
async (opt) => {
|
||||
if (isEditor) return ${JSON.stringify(sample)};
|
||||
|
||||
let raw_id = params.id;
|
||||
if (typeof md === 'object' && md.selected && md.pk) {
|
||||
const pk = md.pk?.name;
|
||||
if (md.selected[pk]) {
|
||||
raw_id = md.selected[pk];
|
||||
}
|
||||
}
|
||||
|
||||
${
|
||||
opt?.before_load
|
||||
? opt.before_load
|
||||
: `let id = ${pk.type === "int" ? "parseInt(raw_id)" : "raw_id"};`
|
||||
}
|
||||
|
||||
let item = {};
|
||||
if (id){
|
||||
item = await db.${table}.findFirst({
|
||||
where: {
|
||||
${pk.name}: id,
|
||||
},
|
||||
select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")},
|
||||
});
|
||||
|
||||
${opt?.after_load ? opt?.after_load : ""}
|
||||
|
||||
return item;
|
||||
} else {
|
||||
${opt?.after_load ? opt?.after_load : ""}
|
||||
}
|
||||
}`;
|
||||
};
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import { createItem, parseGenField } from "lib/gen/utils";
|
||||
import get from "lodash.get";
|
||||
import { generateTableList } from "./gen-table-list";
|
||||
import { generateSelect } from "./md-select";
|
||||
import { on_load } from "./tbl-list/on_load";
|
||||
import { on_submit } from "./tbl-list/on_submit";
|
||||
import { newField } from "./form/fields";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
|
||||
export const generateForm = async (
|
||||
modify: (data: any) => void,
|
||||
data: any,
|
||||
item: PrasiItem,
|
||||
commit: boolean
|
||||
) => {
|
||||
const table = JSON.parse(data.gen_table.value);
|
||||
console.log("halo");
|
||||
console.log(table);
|
||||
const raw_fields = JSON.parse(data.gen_fields.value) as (
|
||||
| string
|
||||
| { value: string; checked: string[] }
|
||||
)[];
|
||||
let pk = "";
|
||||
console.log({ raw_fields });
|
||||
let pks: Record<string, string> = {};
|
||||
const fields = parseGenField(raw_fields);
|
||||
// convert ke bahasa prisma untuk select
|
||||
const res = generateSelect(fields);
|
||||
pk = res.pk;
|
||||
const select = res.select as any;
|
||||
const result: Record<string, PropVal> = {};
|
||||
if (!pk) {
|
||||
alert("Failed to generate! Primary Key not found. ");
|
||||
return;
|
||||
}
|
||||
if (pk) {
|
||||
console.log("masuk");
|
||||
if (data["on_load"]) {
|
||||
result.on_load = {
|
||||
mode: "raw",
|
||||
value: on_load({ pk, table, select, pks }),
|
||||
};
|
||||
}
|
||||
if (data["on_submit"]) {
|
||||
result.on_submit = {
|
||||
mode: "raw",
|
||||
value: on_submit({ pk, table, select, pks }),
|
||||
};
|
||||
}
|
||||
result.body = data["body"];
|
||||
|
||||
console.log({ fields, result });
|
||||
const childs = [];
|
||||
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 });
|
||||
childs.push(field);
|
||||
}
|
||||
if (commit) {
|
||||
const body = item.edit.childs[0] as PrasiItem;
|
||||
item.edit.setProp("body", {
|
||||
mode: "jsx",
|
||||
value: createItem({
|
||||
childs: childs,
|
||||
}),
|
||||
});
|
||||
// await item.edit.commit();
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import capitalize from "lodash.capitalize";
|
||||
import { GFCol, createItem, parseGenField } from "../../../gen/utils";
|
||||
import { generateSelect } from "./md-select";
|
||||
import { on_load } from "./tbl-list/on_load";
|
||||
import { modeTableList } from "./mode-table-list";
|
||||
import get from "lodash.get";
|
||||
import set from "lodash.set";
|
||||
|
||||
export const generateTableList = async (
|
||||
modify: (data: any) => void,
|
||||
data: any,
|
||||
item: PrasiItem,
|
||||
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string },
|
||||
commit: boolean
|
||||
) => {
|
||||
const table = JSON.parse(data.gen_table.value) as string;
|
||||
const raw_fields = JSON.parse(data.gen_fields.value) as (
|
||||
| string
|
||||
| { value: string; checked: string[] }
|
||||
)[];
|
||||
let pk = "";
|
||||
let pks: Record<string, string> = {};
|
||||
const fields = parseGenField(raw_fields);
|
||||
// convert ke bahasa prisma untuk select
|
||||
const res = generateSelect(fields);
|
||||
pk = res.pk;
|
||||
const select = res.select as any;
|
||||
const result: Record<string, PropVal> = {};
|
||||
if (arg.id_parent) {
|
||||
select[arg.id_parent] = true;
|
||||
}
|
||||
if (!pk) {
|
||||
alert("Failed to generate! Primary Key not found. ");
|
||||
return;
|
||||
}
|
||||
let childs = [] as any;
|
||||
if (pk) {
|
||||
let sub_name = modeTableList(arg.mode);
|
||||
let rows = Array.isArray(get(data, "child.content.childs"))
|
||||
? get(data, "child.content.childs")
|
||||
: Array.isArray(get(data, "child.childs"))
|
||||
? get(data, "child.childs")
|
||||
: [];
|
||||
|
||||
rows = rows.filter((e: PrasiItem) => e.name !== sub_name);
|
||||
childs = childs.concat(rows);
|
||||
|
||||
if (data["on_load"]) {
|
||||
result.on_load = {
|
||||
mode: "raw",
|
||||
value: on_load({ pk, table, select, pks }),
|
||||
};
|
||||
}
|
||||
let first = true;
|
||||
|
||||
const child_sub_name = createItem({
|
||||
name: sub_name,
|
||||
childs: fields
|
||||
.map((e, idx) => {
|
||||
if (idx >= 1 && arg.mode === "list") {
|
||||
return;
|
||||
}
|
||||
if (e.is_pk && arg.mode === "table") return;
|
||||
let tree_depth = "";
|
||||
let tree_depth_built = "";
|
||||
if (first) {
|
||||
tree_depth = `tree_depth={col.depth}`;
|
||||
tree_depth_built = `tree_depth:col.depth`;
|
||||
first = false;
|
||||
}
|
||||
return {
|
||||
component: {
|
||||
id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
props: {
|
||||
name: e.name,
|
||||
title: formatName(e.name),
|
||||
child: createItem({
|
||||
childs: [
|
||||
createItem({
|
||||
name: "cell",
|
||||
padding: {
|
||||
l: 8,
|
||||
b: 0,
|
||||
t: 0,
|
||||
r: 8,
|
||||
},
|
||||
adv: {
|
||||
js: `\
|
||||
<div {...props} className={cx(props.className, "")}>
|
||||
<FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
|
||||
</div>`,
|
||||
jsBuilt: `\
|
||||
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
|
||||
`,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
})
|
||||
.filter((e) => e) as any,
|
||||
});
|
||||
childs.push(child_sub_name);
|
||||
|
||||
if (commit) {
|
||||
Object.keys(result).map((e) => {
|
||||
item.edit.setProp(e, result[e]);
|
||||
});
|
||||
console.log({ childs });
|
||||
item.edit.setChilds(childs);
|
||||
await item.edit.commit();
|
||||
} else {
|
||||
set(data, "child.value.childs", childs);
|
||||
Object.keys(result).map((e) => {
|
||||
set(data, e, result[e]);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const formatName = (name: string) => {
|
||||
return name
|
||||
.split("_")
|
||||
.filter((e) => e.length > 1)
|
||||
.map((e) => capitalize(e))
|
||||
.join(" ");
|
||||
};
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
import { createItem } from "lib/gen/utils";
|
||||
import get from "lodash.get";
|
||||
import { generateTableList } from "./gen-table-list";
|
||||
|
||||
export const generateMDForm = async (
|
||||
arg: { item: PrasiItem; table: string; fields: any },
|
||||
data: any,
|
||||
commit: boolean
|
||||
) => {
|
||||
const item = arg.item;
|
||||
const tab_master = item.edit.childs[0].edit.childs.find(
|
||||
(e) => get(e, "component.id") === "c68415ca-dac5-44fe-aeb6-936caf8cc491"
|
||||
);
|
||||
const props: Record<string, PropVal> = {
|
||||
gen_table: {
|
||||
mode: "string",
|
||||
value: arg.table,
|
||||
},
|
||||
name: {
|
||||
mode: "string",
|
||||
value: arg.table,
|
||||
},
|
||||
generate: {
|
||||
mode: "string",
|
||||
value: "y",
|
||||
},
|
||||
on_load: {
|
||||
mode: "string",
|
||||
value: "",
|
||||
},
|
||||
row_click: {
|
||||
mode: "raw",
|
||||
value: `\
|
||||
({ row, rows, idx, event }: OnRowClick) => {
|
||||
md.selected = row;
|
||||
md.internal.action_should_refresh = true;
|
||||
md.params.apply();
|
||||
md.render();
|
||||
};
|
||||
|
||||
type OnRowClick = {
|
||||
row: any;
|
||||
rows: any[];
|
||||
idx: any;
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>;
|
||||
}
|
||||
`,
|
||||
},
|
||||
selected: {
|
||||
mode: "raw",
|
||||
value: `\
|
||||
({ row, rows, idx }: SelectedRow) => {
|
||||
try {
|
||||
if (typeof md === "object") {
|
||||
if (Array.isArray(md.selected)) {
|
||||
if (md.selected.length) {
|
||||
let select = md.selected.find((e) => e === row)
|
||||
if(select) return true
|
||||
}
|
||||
} else {
|
||||
if (md.selected === row) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
type SelectedRow = {
|
||||
row: any;
|
||||
rows: any[];
|
||||
idx: any;
|
||||
}`,
|
||||
},
|
||||
gen_fields: {
|
||||
mode: "raw",
|
||||
value: `${JSON.stringify(arg.fields)}`,
|
||||
},
|
||||
child: {
|
||||
mode: "jsx",
|
||||
value: createItem({
|
||||
name: "halo",
|
||||
childs: [],
|
||||
}),
|
||||
},
|
||||
};
|
||||
const tablelist: any = {
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
},
|
||||
};
|
||||
generateTableList(
|
||||
async (props: any) => {},
|
||||
props,
|
||||
tablelist,
|
||||
{ mode: "table" },
|
||||
false
|
||||
);
|
||||
tab_master?.edit.setChilds([ {
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
},
|
||||
}]);
|
||||
console.log({
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
},
|
||||
})
|
||||
// console.log(tablelist);
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { createItem } from "lib/gen/utils";
|
||||
import get from "lodash.get";
|
||||
import { generateTableList } from "./md-table-list";
|
||||
import { generateTableList } from "./gen-table-list";
|
||||
|
||||
export const generateList = async (
|
||||
arg: { item: PrasiItem; table: string; fields: any },
|
||||
|
|
@ -82,47 +82,32 @@ idx: any;
|
|||
child: {
|
||||
mode: "jsx",
|
||||
value: createItem({
|
||||
name: "halo"
|
||||
})
|
||||
}
|
||||
name: "halo",
|
||||
childs: [],
|
||||
}),
|
||||
},
|
||||
};
|
||||
// console.log(true);
|
||||
console.log({ tab_master });
|
||||
const tablelist = tab_master?.childs[0];
|
||||
// generateTableList(
|
||||
// async (props: any) => {},
|
||||
// props,
|
||||
// tablelist,
|
||||
// { mode: "table" },
|
||||
// false
|
||||
// );
|
||||
// // console.log({modify: async (props: any) => {}, data, item, arg: { mode: "table" }});
|
||||
// const tablelist: PrasiItem= get(item,"edit.childs[0].edit.childs[0].edit.childs[0]");
|
||||
// const data_tbl = get(tablelist, "component.props")
|
||||
// console.log({tablelist, data_tbl})
|
||||
// if(typeof tab_master === "object"){
|
||||
// // const master_child: PrasiItem= tab_master;
|
||||
// // const prop_tablelist = get(tablelist, "component.props")
|
||||
// // console.log({tablelist})
|
||||
// //
|
||||
// }
|
||||
|
||||
// tab_master?.edit.setChilds([
|
||||
// {
|
||||
// type: "item",
|
||||
// name: "item",
|
||||
// component: {
|
||||
// id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
// props,
|
||||
// },
|
||||
// },
|
||||
// ]);
|
||||
console.log({
|
||||
const tablelist: any = {
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
},
|
||||
})
|
||||
};
|
||||
generateTableList(
|
||||
async (props: any) => {},
|
||||
props,
|
||||
tablelist,
|
||||
{ mode: "table" },
|
||||
false
|
||||
);
|
||||
tab_master?.edit.setChilds([ {
|
||||
type: "item",
|
||||
name: "item",
|
||||
component: {
|
||||
id: "567d5362-2cc8-4ca5-a531-f771a5c866c2",
|
||||
props,
|
||||
},
|
||||
}]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,241 +0,0 @@
|
|||
import capitalize from "lodash.capitalize";
|
||||
import { GFCol, createItem, parseGenField } from "../../../gen/utils";
|
||||
import { generateSelect } from "./md-select";
|
||||
import { on_load } from "./tbl-list/on_load";
|
||||
import { modeTableList } from "./mode-table-list";
|
||||
import get from "lodash.get";
|
||||
import set from "lodash.set";
|
||||
|
||||
export const generateTableList = async (
|
||||
modify: (data: any) => void,
|
||||
data: any,
|
||||
item: PrasiItem,
|
||||
arg: { mode: "table" | "list" | "grid" | "auto"; id_parent?: string },
|
||||
commit: boolean
|
||||
) => {
|
||||
|
||||
item.edit.setChilds([
|
||||
{
|
||||
type: "item",
|
||||
name: "1",
|
||||
},
|
||||
{
|
||||
type: "item",
|
||||
name: "2",
|
||||
},
|
||||
]);
|
||||
await item.edit.commit();
|
||||
// console.log({ data, item, arg });
|
||||
// const table = data.gen_table.value as string;
|
||||
// const raw_fields = JSON.parse(data.gen_fields.value) as (
|
||||
// | string
|
||||
// | { value: string; checked: string[] }
|
||||
// )[];
|
||||
// let pk = "";
|
||||
// let pks: Record<string, string> = {};
|
||||
// const fields = parseGenField(raw_fields);
|
||||
// // const result = {} as any;
|
||||
// // generate value dari raw_field array string convert ke value selected prisma
|
||||
// const res = generateSelect(fields);
|
||||
// pk = res.pk;
|
||||
// const select = res.select as any;
|
||||
// const result: Record<string, PropVal> = {};
|
||||
// if (arg.id_parent) {
|
||||
// select[arg.id_parent] = true;
|
||||
// }
|
||||
// if (!pk) {
|
||||
// alert("Failed to generate! Primary Key not found. ");
|
||||
// return;
|
||||
// }
|
||||
// let childs = [] as any;
|
||||
// if (pk) {
|
||||
// let sub_name = modeTableList(arg.mode);
|
||||
// let rows = Array.isArray(get(data, "child.content.childs"))
|
||||
// ? get(data, "child.content.childs")
|
||||
// : Array.isArray(get(data, "child.childs"))
|
||||
// ? get(data, "child.childs")
|
||||
// : [];
|
||||
|
||||
// rows = rows.filter((e: PrasiItem) => e.name !== sub_name);
|
||||
// childs = childs.concat(rows);
|
||||
|
||||
// if (data["on_load"]) {
|
||||
// result.on_load = {
|
||||
// mode: "raw",
|
||||
// value: on_load({ pk, table, select, pks }),
|
||||
// };
|
||||
// }
|
||||
// let first = true;
|
||||
|
||||
// const child_sub_name = createItem({
|
||||
// name: sub_name,
|
||||
// childs: fields
|
||||
// .map((e, idx) => {
|
||||
// if (idx >= 1 && arg.mode === "list") {
|
||||
// return;
|
||||
// }
|
||||
// if (e.is_pk && arg.mode === "table") return;
|
||||
// let tree_depth = "";
|
||||
// let tree_depth_built = "";
|
||||
// if (first) {
|
||||
// tree_depth = `tree_depth={col.depth}`;
|
||||
// tree_depth_built = `tree_depth:col.depth`;
|
||||
// first = false;
|
||||
// }
|
||||
// return {
|
||||
// component: {
|
||||
// id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
// props: {
|
||||
// name: e.name,
|
||||
// title: formatName(e.name),
|
||||
// child: createItem({
|
||||
// childs: [
|
||||
// createItem({
|
||||
// name: "cell",
|
||||
// padding: {
|
||||
// l: 8,
|
||||
// b: 0,
|
||||
// t: 0,
|
||||
// r: 8,
|
||||
// },
|
||||
// adv: {
|
||||
// js: `\
|
||||
// <div {...props} className={cx(props.className, "")}>
|
||||
// <FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
|
||||
// </div>`,
|
||||
// jsBuilt: `\
|
||||
// render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
|
||||
// `,
|
||||
// },
|
||||
// }),
|
||||
// ],
|
||||
// }),
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// })
|
||||
// .filter((e) => e) as any,
|
||||
// });
|
||||
// childs.push(child_sub_name);
|
||||
|
||||
// // result.child = {
|
||||
// // mode: "jsx",
|
||||
// // value: createItem({ name: "child", childs: [child] }),
|
||||
// // };
|
||||
// // item.edit.setChilds([child]);
|
||||
|
||||
// if (commit) {
|
||||
// Object.keys(result).map((e) => {
|
||||
// item.edit.setProp(e, result[e]);
|
||||
// });
|
||||
// console.log({ childs });
|
||||
// item.edit.setChilds([
|
||||
// {
|
||||
// name: sub_name,
|
||||
// },
|
||||
// {
|
||||
// name: "123",
|
||||
// },
|
||||
// ]);
|
||||
// await item.edit.commit();
|
||||
// } else {
|
||||
// set(item, "childs", childs);
|
||||
// Object.keys(result).map((e) => {
|
||||
// set(data, e, result[e]);
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log({ res, item });
|
||||
// console.log({ data });
|
||||
// console.log({ result });
|
||||
// }
|
||||
// return;
|
||||
// if (pk) {
|
||||
// console.log("pk");
|
||||
// const code = {} as any;
|
||||
// if (data["on_load"]) {
|
||||
// result["on_load"] = data["on_load"];
|
||||
// result["on_load"].value = on_load({ pk, table, select, pks });
|
||||
// delete result["on_load"].valueBuilt;
|
||||
// code.on_load = result["on_load"].value;
|
||||
// }
|
||||
// let sub_name = "fields";
|
||||
// switch (arg.mode) {
|
||||
// case "table":
|
||||
// sub_name = "tbl-col";
|
||||
// break;
|
||||
// case "list":
|
||||
// sub_name = "md-list";
|
||||
// break;
|
||||
// }
|
||||
// let first = true;
|
||||
// console.log(sub_name);
|
||||
// const child = {
|
||||
// name: sub_name,
|
||||
// childs: fields
|
||||
// .map((e, idx) => {
|
||||
// if (idx >= 1 && arg.mode === "list") {
|
||||
// return;
|
||||
// }
|
||||
// if (e.is_pk && arg.mode === "table") return;
|
||||
// let tree_depth = "";
|
||||
// let tree_depth_built = "";
|
||||
// if (first) {
|
||||
// tree_depth = `tree_depth={col.depth}`;
|
||||
// tree_depth_built = `tree_depth:col.depth`;
|
||||
// first = false;
|
||||
// }
|
||||
// return {
|
||||
// component: {
|
||||
// id: "297023a4-d552-464a-971d-f40dcd940b77",
|
||||
// props: {
|
||||
// name: {
|
||||
// mode: "string",
|
||||
// value: e.name
|
||||
// },
|
||||
// title: {
|
||||
// mode: "string",
|
||||
// value: formatName(e.name)
|
||||
// },
|
||||
// child: createItem({
|
||||
// childs: [
|
||||
// createItem({
|
||||
// name: "cell",
|
||||
// padding: {
|
||||
// l: 8,
|
||||
// b: 0,
|
||||
// t: 0,
|
||||
// r: 8,
|
||||
// },
|
||||
// adv: {
|
||||
// js: `\
|
||||
// <div {...props} className={cx(props.className, "")}>
|
||||
// <FormatValue value={col.value} name={col.name} gen_fields={gen_fields} ${tree_depth} />
|
||||
// </div>`,
|
||||
// jsBuilt: `\
|
||||
// render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen_fields, ${tree_depth_built} })));
|
||||
// `,
|
||||
// },
|
||||
// }),
|
||||
// ],
|
||||
// }),
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// })
|
||||
// .filter((e) => e) as any,
|
||||
// };
|
||||
// data.child.value = child;
|
||||
// result["child"] = data.child
|
||||
// }
|
||||
// modify(result);
|
||||
// console.log({ child: data["child"] });
|
||||
};
|
||||
|
||||
const formatName = (name: string) => {
|
||||
return name
|
||||
.split("_")
|
||||
.filter((e) => e.length > 1)
|
||||
.map((e) => capitalize(e))
|
||||
.join(" ");
|
||||
};
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import { GFCol } from "lib/gen/utils";
|
||||
|
||||
|
||||
export const on_submit = ({
|
||||
pk,
|
||||
table,
|
||||
select,
|
||||
pks,
|
||||
}: {
|
||||
pk: string;
|
||||
table: string;
|
||||
select: any;
|
||||
pks: Record<string, string>;
|
||||
}) => {
|
||||
const id = pk;
|
||||
|
||||
return `\
|
||||
async ({ form, error }: IForm) => {
|
||||
if (typeof form !== "object") return false;
|
||||
if (typeof error === "object" && Object.keys(error).length > 0) return false;
|
||||
|
||||
let original_actions = [];
|
||||
if (typeof md === "object") {
|
||||
original_actions = md.actions;
|
||||
md.actions = [{ label: <>...</> }];
|
||||
md.render();
|
||||
}
|
||||
|
||||
let result = false;
|
||||
try {
|
||||
const data = { ...form };
|
||||
delete data.${id};
|
||||
|
||||
if (data) {
|
||||
const pks = ${JSON.stringify(pks)};
|
||||
for (const [k, v] of Object.entries(pks)) {
|
||||
if (typeof data[k] === 'object') {
|
||||
if (data[k] === null) {
|
||||
data[k] = {
|
||||
disconnect: true
|
||||
}
|
||||
}
|
||||
if (data[k][v]) {
|
||||
data[k] = {
|
||||
connect: {
|
||||
[v]: data[k][v]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (form.${id}) {
|
||||
await db.${table}.update({
|
||||
where: {
|
||||
${id}: form.${id},
|
||||
},
|
||||
data,
|
||||
});
|
||||
} else {
|
||||
const res = await db.${table}.create({
|
||||
data,
|
||||
select: { ${id}: true },
|
||||
});
|
||||
if (res) form.${id} = res.${id};
|
||||
}
|
||||
|
||||
result = true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (typeof md === "object") {
|
||||
md.actions = original_actions;
|
||||
md.selected = null;
|
||||
md.render();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
type IForm = { form: any; error: Record<string, string> }`;
|
||||
};
|
||||
|
|
@ -38,7 +38,18 @@ export const MDMaster: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
|
|||
return (
|
||||
<>
|
||||
{md.props.show_head === "only-master" && <MDHeader md={md} mdr={mdr} />}
|
||||
<div
|
||||
className={cx(
|
||||
css`
|
||||
> div {
|
||||
flex: 1;
|
||||
}
|
||||
`,
|
||||
"c-flex c-flex-1"
|
||||
)}
|
||||
>
|
||||
<PassProp md={md}>{mdr.master}</PassProp>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
|
|||
md.props.gen_table = gen_table;
|
||||
md.props.on_init = on_init;
|
||||
|
||||
console.log(get(mdr, "master.edit.childs.0"));
|
||||
if (!mdr.master || (mdr.master && !get(mdr, "master.edit.childs.0.childs.length"))) {
|
||||
md.breadcrumb = [
|
||||
{
|
||||
|
|
|
|||
10
exports.ts
10
exports.ts
|
|
@ -34,13 +34,18 @@ export const ExportExcel = lazify(
|
|||
|
||||
/** Filter */
|
||||
export const MasterFilter = lazify(
|
||||
async () => (await import("@/comps/filter/Filter")).MasterFilter
|
||||
async () => (await import("@/comps/filter/MasterFilter")).MasterFilter
|
||||
);
|
||||
|
||||
export const FilterField = lazify(
|
||||
async () => (await import("@/comps/filter/FilterField")).FilterField
|
||||
);
|
||||
|
||||
/** Generator */
|
||||
export { generateMasterDetail } from "lib/comps/md/gen/md-gen";
|
||||
|
||||
/** ETC */
|
||||
export { filterWhere } from "@/comps/filter/utils/filter-where";
|
||||
export {
|
||||
FMLocal,
|
||||
FieldTypeCustom,
|
||||
|
|
@ -54,7 +59,8 @@ export { TableListType } from "lib/comps/list/utils/typings";
|
|||
export { Button, FloatButton } from "@/comps/ui/button";
|
||||
export { prasi_gen } from "@/gen/prasi_gen";
|
||||
export { password } from "@/utils/password";
|
||||
export {generateTableList} from "@/comps/md/gen/md-table-list"
|
||||
export { generateTableList } from "@/comps/md/gen/gen-table-list";
|
||||
export { generateForm } from "@/comps/md/gen/gen-form";
|
||||
|
||||
/** Session */
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ export const parseGenField = (fields: PropOptRaw) => {
|
|||
if (typeof f === "string") {
|
||||
try {
|
||||
const field = JSON.parse(f);
|
||||
field["value"] = f
|
||||
result.push(field);
|
||||
} catch (e) {}
|
||||
} else {
|
||||
const field = JSON.parse(f.value);
|
||||
field.relation.fields = parseGenField(f.checked);
|
||||
field["value"] = f
|
||||
result.push(field);
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +48,7 @@ export type GFCol = {
|
|||
to: { table: string; fields: string[] };
|
||||
fields: GFCol[];
|
||||
};
|
||||
value: Array<string> | string;
|
||||
};
|
||||
|
||||
export const formatName = (name: string) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { FC } from "react";
|
||||
import { prasi_user } from "./utils/user";
|
||||
|
||||
const w = window as unknown as {
|
||||
prasi_home: Record<string, string>;
|
||||
|
|
@ -7,11 +8,15 @@ const w = window as unknown as {
|
|||
export type LGProps = {
|
||||
salt: string;
|
||||
url_home: Array<Record<string, string>>;
|
||||
body: any
|
||||
body: any;
|
||||
};
|
||||
|
||||
export const Login: FC<LGProps> = (props) => {
|
||||
w.prasi_home = props.url_home[0];
|
||||
console.log(w.prasi_home)
|
||||
try {
|
||||
const home = prasi_user.prasi_home[prasi_user.user.m_role.name];
|
||||
navigate(home);
|
||||
} catch (e: any) {
|
||||
}
|
||||
return <>{props.body}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ export const prasi_user = window as unknown as {
|
|||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
name: string;
|
||||
fullname: string;
|
||||
m_role: {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -62,12 +62,12 @@ export const Layout: FC<LYTChild> = (props) => {
|
|||
fn();
|
||||
const path = getPathname();
|
||||
const no_layout = props.exception;
|
||||
loadSession("/auth/login");
|
||||
if (Array.isArray(no_layout))
|
||||
if (no_layout.length) {
|
||||
if (no_layout.includes(path)) {
|
||||
return <>{props.defaultLayout}</>;
|
||||
}
|
||||
}
|
||||
loadSession("/dev/auth");
|
||||
return <>{props.children}</>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ export const FormatValue: FC<{
|
|||
return {
|
||||
...JSON.parse(e.value),
|
||||
checked: e.checked.map((ex: any) => {
|
||||
if(typeof ex === "string"){
|
||||
return JSON.parse(e.value)
|
||||
if (typeof ex === "string") {
|
||||
return JSON.parse(e.value);
|
||||
}
|
||||
try{
|
||||
try {
|
||||
return JSON.parse(ex["value"]);
|
||||
}catch(em){
|
||||
return null
|
||||
} catch (em) {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
|
@ -42,19 +42,20 @@ export const FormatValue: FC<{
|
|||
if (typeof value === "object" && value) {
|
||||
const rel = fields?.find((e) => e.name === name);
|
||||
if (rel && rel.checked) {
|
||||
const result = rel.checked
|
||||
.filter((e) => !e.is_pk)
|
||||
.map((e) => {
|
||||
return value[e.name];
|
||||
})
|
||||
.join(" - ");
|
||||
|
||||
if (rel.type === "has-one") {
|
||||
const result = [];
|
||||
for (const [k,v] of Object.entries(value) as any ) {
|
||||
if (!k.toLowerCase().includes('id')) result.push(v);
|
||||
}
|
||||
return result.join(' - ');
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const len = value.length;
|
||||
if (len === 0) return ` - `;
|
||||
return `${len} item${len > 1 ? "s" : ""}`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return JSON.stringify(value);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { GFCol } from "lib/gen/utils";
|
||||
|
||||
export const parseGenFields = (gen_fields: any) => {
|
||||
const fields_map = new Map<string, (GFCol & { checked?: GFCol[] })[]>();
|
||||
if (gen_fields) {
|
||||
const gf = JSON.stringify(gen_fields);
|
||||
if (!fields_map.has(gf)) {
|
||||
fields_map.set(
|
||||
gf,
|
||||
gen_fields.map((e: any) => {
|
||||
if (typeof e === "string") {
|
||||
return JSON.parse(e);
|
||||
} else {
|
||||
return {
|
||||
...JSON.parse(e.value),
|
||||
checked: e.checked.map((ex: any) => {
|
||||
if (typeof ex === "string") {
|
||||
return JSON.parse(e.value);
|
||||
}
|
||||
try {
|
||||
return JSON.parse(ex["value"]);
|
||||
} catch (em) {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
return fields_map;
|
||||
};
|
||||
Loading…
Reference in New Issue