fix table list
This commit is contained in:
parent
66ce2ab145
commit
52105ef69c
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Skeleton } from "../ui/skeleton";
|
||||||
|
import { OnRowClick } from "./utils/type";
|
||||||
|
import { Sticker } from "lucide-react";
|
||||||
|
|
||||||
|
export const TLList: FC<{
|
||||||
|
local: Record<string, any> & {
|
||||||
|
el: null | HTMLDivElement;
|
||||||
|
render: () => void;
|
||||||
|
};
|
||||||
|
data: any[];
|
||||||
|
PassProp: any;
|
||||||
|
row_click: OnRowClick;
|
||||||
|
mode_child: any;
|
||||||
|
dataGridStyle: (local: { el: null | HTMLDivElement }) => string;
|
||||||
|
}> = ({ local, data, dataGridStyle, mode_child, PassProp, row_click }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-w-full c-h-full c-flex-1 c-relative c-overflow-hidden",
|
||||||
|
dataGridStyle(local)
|
||||||
|
)}
|
||||||
|
ref={(el) => {
|
||||||
|
if (!local.el && el) {
|
||||||
|
local.el = el;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{local.status !== "ready" ? (
|
||||||
|
<div className="c-flex c-flex-col c-space-y-2 c-m-4 c-absolute c-left-0 c-top-0">
|
||||||
|
<Skeleton className={cx("c-w-[200px] c-h-[11px]")} />
|
||||||
|
<Skeleton className={cx("c-w-[170px] c-h-[11px]")} />
|
||||||
|
<Skeleton className={cx("c-w-[180px] c-h-[11px]")} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-absolute c-inset-0",
|
||||||
|
!isEditor &&
|
||||||
|
css`
|
||||||
|
@keyframes flasher {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-row {
|
||||||
|
animation: flasher 0.5s;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{Array.isArray(data) && data.length > 0 ? (
|
||||||
|
<div
|
||||||
|
className="w-full h-full overflow-y-auto c-flex-col"
|
||||||
|
ref={(e) => {
|
||||||
|
local.grid_ref = e;
|
||||||
|
}}
|
||||||
|
onScroll={(e) => local.paging.scroll(e.currentTarget)}
|
||||||
|
>
|
||||||
|
{data.map((e, idx) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx("list-row c-flex-grow c-flex")}
|
||||||
|
onClick={(ev) => {
|
||||||
|
if (!isEditor && typeof row_click === "function") {
|
||||||
|
row_click({
|
||||||
|
event: ev,
|
||||||
|
idx: idx,
|
||||||
|
row: e,
|
||||||
|
rows: local.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PassProp idx={idx} row={e} col={{}} rows={local.data}>
|
||||||
|
{mode_child}
|
||||||
|
</PassProp>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="c-flex c-items-center c-justify-center c-flex-1 w-full h-full c-flex-col ">
|
||||||
|
<Sticker size={35} strokeWidth={1} />
|
||||||
|
<div className="c-pt-1 c-text-center">
|
||||||
|
No Data
|
||||||
|
<br />
|
||||||
|
{local.filtering && (
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
color: gray;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 90%;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{local.filtering}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Skeleton } from "../ui/skeleton";
|
||||||
|
import { OnRowClick } from "./utils/type";
|
||||||
|
import { Sticker } from "lucide-react";
|
||||||
|
|
||||||
|
export const TLSlider: FC<{
|
||||||
|
local: Record<string, any> & {
|
||||||
|
el: null | HTMLDivElement;
|
||||||
|
render: () => void;
|
||||||
|
};
|
||||||
|
data: any[];
|
||||||
|
PassProp: any;
|
||||||
|
row_click: OnRowClick;
|
||||||
|
mode_child: any;
|
||||||
|
item_w: string;
|
||||||
|
dataGridStyle: (local: { el: null | HTMLDivElement }) => string;
|
||||||
|
}> = ({
|
||||||
|
local,
|
||||||
|
data,
|
||||||
|
dataGridStyle,
|
||||||
|
item_w,
|
||||||
|
mode_child,
|
||||||
|
PassProp,
|
||||||
|
row_click,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{local.status !== "ready" ? (
|
||||||
|
<div className="c-flex c-flex-col c-space-y-2 c-m-4 c-absolute c-left-0 c-top-0">
|
||||||
|
<Skeleton className={cx("c-w-[200px] c-h-[11px]")} />
|
||||||
|
<Skeleton className={cx("c-w-[170px] c-h-[11px]")} />
|
||||||
|
<Skeleton className={cx("c-w-[180px] c-h-[11px]")} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{Array.isArray(data) && data.length > 0 ? (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-overflow-x-auto c-snap-x c-h-full c-w-full c-flex",
|
||||||
|
css`
|
||||||
|
padding-right: 50px;
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
ref={(e) => {
|
||||||
|
local.grid_ref = e;
|
||||||
|
}}
|
||||||
|
onScroll={(e) => local.paging.scroll(e.currentTarget)}
|
||||||
|
>
|
||||||
|
{data.map((e, idx) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"list-item c-snap-start c-flex c-shrink-0",
|
||||||
|
css`
|
||||||
|
width: ${item_w}px;
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
onClick={(ev) => {
|
||||||
|
if (!isEditor && typeof row_click === "function") {
|
||||||
|
row_click({
|
||||||
|
event: ev,
|
||||||
|
idx: idx,
|
||||||
|
row: e,
|
||||||
|
rows: local.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PassProp
|
||||||
|
idx={idx}
|
||||||
|
item_w={item_w}
|
||||||
|
is_last={idx == data.length - 1}
|
||||||
|
row={e}
|
||||||
|
col={{}}
|
||||||
|
rows={local.data}
|
||||||
|
>
|
||||||
|
{mode_child}
|
||||||
|
</PassProp>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="c-flex c-items-center c-justify-center c-flex-1 w-full h-full c-flex-col ">
|
||||||
|
<Sticker size={35} strokeWidth={1} />
|
||||||
|
<div className="c-pt-1 c-text-center">
|
||||||
|
No Data
|
||||||
|
<br />
|
||||||
|
{local.filtering && (
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
color: gray;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 90%;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{local.filtering}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -36,19 +36,17 @@ import { MDLocal } from "../md/utils/typings";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
import { toast } from "../ui/toast";
|
import { toast } from "../ui/toast";
|
||||||
import { sortTree } from "./utils/sort-tree";
|
import { sortTree } from "./utils/sort-tree";
|
||||||
|
import { TLList } from "./TLList";
|
||||||
|
import { OnRowClick } from "./utils/type";
|
||||||
|
import { TLSlider } from "./TLSlider";
|
||||||
|
|
||||||
type OnRowClick = (arg: {
|
|
||||||
row: any;
|
|
||||||
rows: any[];
|
|
||||||
idx: any;
|
|
||||||
event: React.MouseEvent<HTMLDivElement>;
|
|
||||||
}) => void;
|
|
||||||
let EMPTY_SET = new Set() as ReadonlySet<any>;
|
let EMPTY_SET = new Set() as ReadonlySet<any>;
|
||||||
|
|
||||||
type SelectedRow = (arg: { row: any; rows: any[]; idx: any }) => boolean;
|
type SelectedRow = (arg: { row: any; rows: any[]; idx: any }) => boolean;
|
||||||
type TableListProp = {
|
type TableListProp = {
|
||||||
child: any;
|
child: any;
|
||||||
PassProp: any;
|
PassProp: any;
|
||||||
|
list: { type: string; item_w: string };
|
||||||
name: string;
|
name: string;
|
||||||
value?: any[];
|
value?: any[];
|
||||||
on_load?: (arg: {
|
on_load?: (arg: {
|
||||||
|
|
@ -75,7 +73,6 @@ type TableListProp = {
|
||||||
tbl: any;
|
tbl: any;
|
||||||
child: any;
|
child: any;
|
||||||
}) => ReactNode;
|
}) => ReactNode;
|
||||||
softdel_field?: string;
|
|
||||||
gen_table?: string;
|
gen_table?: string;
|
||||||
softdel_type?: string;
|
softdel_type?: string;
|
||||||
paging?: boolean;
|
paging?: boolean;
|
||||||
|
|
@ -110,6 +107,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
row_height: rowHeight,
|
row_height: rowHeight,
|
||||||
render_col,
|
render_col,
|
||||||
show_header,
|
show_header,
|
||||||
|
list,
|
||||||
value,
|
value,
|
||||||
paging,
|
paging,
|
||||||
cache_row,
|
cache_row,
|
||||||
|
|
@ -163,6 +161,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
last_length: 0,
|
last_length: 0,
|
||||||
scroll: (currentTarget: HTMLDivElement) => {
|
scroll: (currentTarget: HTMLDivElement) => {
|
||||||
if (
|
if (
|
||||||
|
isEditor ||
|
||||||
local.data.length < local.paging.take ||
|
local.data.length < local.paging.take ||
|
||||||
local.data.length === 0 ||
|
local.data.length === 0 ||
|
||||||
local.status !== "ready" ||
|
local.status !== "ready" ||
|
||||||
|
|
@ -259,7 +258,11 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
const result = on_load({ ...load_args, mode: "query" });
|
const result = on_load({ ...load_args, mode: "query" });
|
||||||
const callback = (data: any[]) => {
|
const callback = (data: any[]) => {
|
||||||
if (!local.paging || (local.paging && !local.paging.take)) {
|
if (
|
||||||
|
id_parent ||
|
||||||
|
!local.paging ||
|
||||||
|
(local.paging && !local.paging.take)
|
||||||
|
) {
|
||||||
local.data = data;
|
local.data = data;
|
||||||
} else {
|
} else {
|
||||||
local.data = [...local.data, ...data];
|
local.data = [...local.data, ...data];
|
||||||
|
|
@ -414,6 +417,9 @@ export const TableList: FC<TableListProp> = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditor || value) {
|
if (isEditor || value) {
|
||||||
on_init(local);
|
on_init(local);
|
||||||
|
if (isEditor && local.data.length === 0 && local.status === "ready") {
|
||||||
|
reload();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
@ -935,107 +941,35 @@ export const TableList: FC<TableListProp> = ({
|
||||||
);
|
);
|
||||||
} else if (mode === "list") {
|
} else if (mode === "list") {
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
className={cx(
|
|
||||||
"c-w-full c-h-full c-flex-1 c-relative c-overflow-hidden",
|
|
||||||
dataGridStyle(local)
|
|
||||||
)}
|
|
||||||
ref={(el) => {
|
|
||||||
if (!local.el && el) {
|
|
||||||
local.el = el;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{toaster_el &&
|
{toaster_el &&
|
||||||
createPortal(
|
createPortal(
|
||||||
<Toaster position={toast.position} cn={cn} />,
|
<Toaster position={toast.position} cn={cn} />,
|
||||||
toaster_el
|
toaster_el
|
||||||
)}
|
)}
|
||||||
|
{list.type !== "slider" && list.type !== "grid" && (
|
||||||
{local.status !== "ready" ? (
|
<TLList
|
||||||
<div className="c-flex c-flex-col c-space-y-2 c-m-4 c-absolute c-left-0 c-top-0">
|
row_click={row_click}
|
||||||
<Skeleton className={cx("c-w-[200px] c-h-[11px]")} />
|
PassProp={PassProp}
|
||||||
<Skeleton className={cx("c-w-[170px] c-h-[11px]")} />
|
local={local}
|
||||||
<Skeleton className={cx("c-w-[180px] c-h-[11px]")} />
|
mode_child={mode_child}
|
||||||
</div>
|
data={data}
|
||||||
) : (
|
dataGridStyle={dataGridStyle}
|
||||||
<div
|
/>
|
||||||
className={cx(
|
|
||||||
"c-absolute c-inset-0",
|
|
||||||
css`
|
|
||||||
@keyframes flasher {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.list-row {
|
|
||||||
animation: flasher 0.5s;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
{Array.isArray(data) && data.length > 0 ? (
|
|
||||||
<div
|
|
||||||
className="w-full h-full overflow-y-auto c-flex-col"
|
|
||||||
ref={(e) => {
|
|
||||||
local.grid_ref = e;
|
|
||||||
}}
|
|
||||||
onScroll={(e) => local.paging.scroll(e.currentTarget)}
|
|
||||||
>
|
|
||||||
{data.map((e, idx) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cx("list-row c-flex-grow c-flex")}
|
|
||||||
onClick={(ev) => {
|
|
||||||
if (!isEditor && typeof row_click === "function") {
|
|
||||||
row_click({
|
|
||||||
event: ev,
|
|
||||||
idx: idx,
|
|
||||||
row: e,
|
|
||||||
rows: local.data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PassProp idx={idx} row={e} col={{}} rows={local.data}>
|
|
||||||
{mode_child}
|
|
||||||
</PassProp>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="c-flex c-items-center c-justify-center c-flex-1 w-full h-full c-flex-col ">
|
|
||||||
<Sticker size={35} strokeWidth={1} />
|
|
||||||
<div className="c-pt-1 c-text-center">
|
|
||||||
No Data
|
|
||||||
<br />
|
|
||||||
{local.filtering && (
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
color: gray;
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 90%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{local.filtering}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
{list.type === "slider" && (
|
||||||
|
<TLSlider
|
||||||
|
row_click={row_click}
|
||||||
|
PassProp={PassProp}
|
||||||
|
local={local}
|
||||||
|
mode_child={mode_child}
|
||||||
|
data={data}
|
||||||
|
item_w={list.item_w}
|
||||||
|
dataGridStyle={dataGridStyle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const CheckboxList: FC<{
|
const CheckboxList: FC<{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
export type OnRowClick = (arg: {
|
||||||
|
row: any;
|
||||||
|
rows: any[];
|
||||||
|
idx: any;
|
||||||
|
event: React.MouseEvent<HTMLDivElement>;
|
||||||
|
}) => void;
|
||||||
|
|
@ -16,7 +16,7 @@ export const generateTableList = async (
|
||||||
let table = "" as string;
|
let table = "" as string;
|
||||||
try {
|
try {
|
||||||
table = eval(data.gen__table.value);
|
table = eval(data.gen__table.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
table = data.gen__table?.value;
|
table = data.gen__table?.value;
|
||||||
}
|
}
|
||||||
const raw_fields = JSON.parse(data.gen__fields.value) as (
|
const raw_fields = JSON.parse(data.gen__fields.value) as (
|
||||||
|
|
@ -129,11 +129,11 @@ const genList = async (opt: GenOpt) => {
|
||||||
},
|
},
|
||||||
adv: {
|
adv: {
|
||||||
js: `\
|
js: `\
|
||||||
<div {...props} className={cx(props.className, \`s-\${_item?.edit?.parent?.item?.id}\` , "list-field")}>
|
<div {...props} className={cx(props.className, _item?.edit?.parent?.item?.id && \`s-\${_item?.edit?.parent?.item?.id}\` , "list-field")}>
|
||||||
<FormatValue value={_get(row, name)} name={name} gen_fields={gen__fields} />
|
<FormatValue value={_get(row, name)} name={name} gen_fields={gen__fields} />
|
||||||
</div>`,
|
</div>`,
|
||||||
jsBuilt: `\
|
jsBuilt: `\
|
||||||
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, \`s-\${_item?.edit?.parent?.item?.id}\` , "") }),React.createElement(FormatValue, { value: _get(row, name), name: name, gen_fields: gen__fields })));
|
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, _item?.edit?.parent?.item?.id && \`s-\${_item?.edit?.parent?.item?.id}\` , "") }),React.createElement(FormatValue, { value: _get(row, name), name: name, gen_fields: gen__fields })));
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -189,25 +189,25 @@ const genTable = async (opt: GenOpt) => {
|
||||||
title: formatName(e.name),
|
title: formatName(e.name),
|
||||||
child: createItem({
|
child: createItem({
|
||||||
name: "cell",
|
name: "cell",
|
||||||
"layout": {
|
layout: {
|
||||||
"dir": "col",
|
dir: "col",
|
||||||
"align": "left",
|
align: "left",
|
||||||
"gap": 0,
|
gap: 0,
|
||||||
"wrap": "flex-nowrap"
|
wrap: "flex-nowrap",
|
||||||
},
|
},
|
||||||
padding: {
|
padding: {
|
||||||
l: 8,
|
l: 8,
|
||||||
b: 0,
|
b: 0,
|
||||||
t: 0,
|
t: 0,
|
||||||
r: 8,
|
r: 8,
|
||||||
},
|
},
|
||||||
adv: {
|
adv: {
|
||||||
js: `\
|
js: `\
|
||||||
<div {...props} className={cx(props.className, \`s-\${_item?.edit?.parent?.item?.id}\` , "table-col")}>
|
<div {...props} className={cx(props.className, _item?.edit?.parent?.item?.id && \`s-\${_item?.edit?.parent?.item?.id}\` , "table-col")}>
|
||||||
<FormatValue value={col.value} name={col.name} gen_fields={gen__fields} />
|
<FormatValue value={col.value} name={col.name} gen_fields={gen__fields} />
|
||||||
</div>`,
|
</div>`,
|
||||||
jsBuilt: `\
|
jsBuilt: `\
|
||||||
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, \`s-\${_item?.edit?.parent?.item?.id}\` , "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen__fields })));
|
render(React.createElement("div", Object.assign({}, props, { className: cx(props.className, _item?.edit?.parent?.item?.id && \`s-\${_item?.edit?.parent?.item?.id}\` , "") }),React.createElement(FormatValue, { value: col.value, name: col.name, gen_fields: gen__fields })));
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ async (arg: TableOnLoad) => {
|
||||||
if (isEditor)
|
if (isEditor)
|
||||||
return [${JSON.stringify(sample)}];
|
return [${JSON.stringify(sample)}];
|
||||||
|
|
||||||
let where = arg.where;
|
let where = arg.where as Prisma.${table}WhereInput;
|
||||||
if (arg.mode === "count") {
|
if (arg.mode === "count") {
|
||||||
return await db.${table}.count({
|
return await db.${table}.count({
|
||||||
where: {
|
where: {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ export const Layout: FC<LYTChild> = (props) => {
|
||||||
const newurl = new URL(`${url.protocol}//${url.host}${_href}`);
|
const newurl = new URL(`${url.protocol}//${url.host}${_href}`);
|
||||||
const pathname = newurl.pathname;
|
const pathname = newurl.pathname;
|
||||||
|
|
||||||
|
_href = baseurl(_href);
|
||||||
if (params) {
|
if (params) {
|
||||||
const prefix: LinkParam["prefix"] =
|
const prefix: LinkParam["prefix"] =
|
||||||
params.breads?.map((e) => {
|
params.breads?.map((e) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue