This commit is contained in:
rizky 2024-07-19 23:50:21 -07:00
parent ebc3e19935
commit ac74e0770b
21 changed files with 371 additions and 81 deletions

View File

@ -1,7 +1,5 @@
import { useLocal } from "@/utils/use-local"; import { useLocal } from "@/utils/use-local";
import { FC, ReactNode, useEffect } from "react"; import { FC, ReactNode, useEffect } from "react";
import { Skeleton } from "../ui/skeleton";
import get from "lodash.get";
import { FieldLoading } from "../ui/field-loading"; import { FieldLoading } from "../ui/field-loading";
export type BreadItem = { export type BreadItem = {

View File

@ -47,9 +47,7 @@ export const BaseField = (prop: {
w === "½" && "c-w-1/2", w === "½" && "c-w-1/2",
w === "⅓" && "c-w-1/3", w === "⅓" && "c-w-1/3",
w === "¼" && "c-w-1/4", w === "¼" && "c-w-1/4",
field.type === "link" "c-flex-col c-space-y-1",
? "c-flex-row c-items-stretch c-min-h-[78px]"
: "c-flex-col c-space-y-1",
field.focused && "focused", field.focused && "focused",
field.disabled && "disabled", field.disabled && "disabled",
typeof fm.data[name] !== "undefined" && typeof fm.data[name] !== "undefined" &&
@ -65,9 +63,7 @@ export const BaseField = (prop: {
!["toogle", "button", "radio", "checkbox"].includes(arg.sub_type) !["toogle", "button", "radio", "checkbox"].includes(arg.sub_type)
? cx( ? cx(
"field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white", "field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white",
field.type === "link" "c-border c-rounded "
? " c-items-center"
: "c-border c-rounded "
) )
: "", : "",
fm.status === "loading" fm.status === "loading"
@ -105,7 +101,6 @@ export const BaseField = (prop: {
<div <div
className={cx( className={cx(
"field-inner c-flex-1 c-flex c-items-center", "field-inner c-flex-1 c-flex c-items-center",
field.type === "link" && "c-justify-end",
field.focused && "focused", field.focused && "focused",
field.disabled && "c-pointer-events-none" field.disabled && "c-pointer-events-none"
)} )}

View File

@ -54,9 +54,7 @@ export const Field: FC<FieldProp> = (arg) => {
w === "½" && "c-w-1/2", w === "½" && "c-w-1/2",
w === "⅓" && "c-w-1/3", w === "⅓" && "c-w-1/3",
w === "¼" && "c-w-1/4", w === "¼" && "c-w-1/4",
field.type === "link" "c-flex-col c-space-y-1"
? "c-flex-row c-items-stretch c-min-h-[78px]"
: "c-flex-col c-space-y-1"
)} )}
{...props} {...props}
ref={typeof arg.field_ref === "function" ? arg.field_ref : undefined} ref={typeof arg.field_ref === "function" ? arg.field_ref : undefined}

View File

@ -6,6 +6,7 @@ import { TableEdit } from "./table-edit/TableEdit";
import { FieldTypeInput, PropTypeInput } from "./type/TypeInput"; import { FieldTypeInput, PropTypeInput } from "./type/TypeInput";
import { MultiOption } from "./type/TypeMultiOption"; import { MultiOption } from "./type/TypeMultiOption";
import { SingleOption } from "./type/TypeSingleOption"; import { SingleOption } from "./type/TypeSingleOption";
import { FieldLink } from "./type/TypeLink";
const modify = { const modify = {
timeout: null as any, timeout: null as any,
@ -108,7 +109,7 @@ export const FieldInput: FC<{
!["toogle", "button", "radio", "checkbox"].includes(arg.sub_type) !["toogle", "button", "radio", "checkbox"].includes(arg.sub_type)
? cx( ? cx(
"field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white", "field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white",
field.type === "link" ? " c-items-center" : "c-border c-rounded " "c-border c-rounded "
) )
: "", : "",
fm.status === "loading" fm.status === "loading"
@ -145,7 +146,6 @@ export const FieldInput: FC<{
<div <div
className={cx( className={cx(
"field-inner c-flex-1 c-flex c-items-center", "field-inner c-flex-1 c-flex c-items-center",
field.type === "link" && "c-justify-end",
field.focused && "focused", field.focused && "focused",
disabled && "c-pointer-events-none c-bg-gray-50" disabled && "c-pointer-events-none c-bg-gray-50"
)} )}
@ -158,7 +158,9 @@ export const FieldInput: FC<{
<>{custom}</> <>{custom}</>
) : ( ) : (
<> <>
{type_field === "link" && <>ini link</>} {type_field === "link" && (
<FieldLink field={field} fm={fm} arg={arg} />
)}
{["date", "input"].includes(type_field) ? ( {["date", "input"].includes(type_field) ? (
<FieldTypeInput <FieldTypeInput
field={field} field={field}

View File

@ -8,12 +8,7 @@ export const Label: FC<{ field: FieldLocal; fm: FMLocal }> = ({
const errors = fm.error.get(field.name); const errors = fm.error.get(field.name);
return ( return (
<div <div className={cx("label c-text-sm c-flex c-items-center", "c-mt-3")}>
className={cx(
"label c-text-sm c-flex c-items-center",
field.type === "link" ? "" : "c-mt-3"
)}
>
<span className={cx(errors.length > 0 && `c-text-red-600`)}> <span className={cx(errors.length > 0 && `c-text-red-600`)}>
{field.label} {field.label}
</span> </span>

View File

@ -0,0 +1,196 @@
import { FieldLoading, Spinner } from "lib/comps/ui/field-loading";
import { hashSum } from "lib/utils/hash-sum";
import { getPathname } from "lib/utils/pathname";
import { useLocal } from "lib/utils/use-local";
import { ArrowUpRight } from "lucide-react";
import { FC, ReactNode, useEffect } from "react";
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
export const FieldLink: FC<{
field: FieldLocal;
fm: FMLocal;
arg: FieldProp;
}> = ({ field, fm, arg }) => {
const local = useLocal({
text: "",
init: false,
navigating: false,
custom: false,
});
const Link = ({
children,
}: {
children: (arg: { icon: any }) => ReactNode;
}) => {
return (
<div
className={cx(
"c-flex-1 c-my-1 c-px-2 c-rounded-md c-flex c-items-center cursor-pointer c-space-x-1 c-transition-all",
css`
border: 1px solid #aaa;
&:hover {
background-color: #dcedfc;
}
`
)}
onClick={async () => {
if (!isEditor) {
local.navigating = true;
local.render();
if (!(await navigateLink(arg.link, field))) {
local.navigating = false;
local.render();
}
}
}}
>
{children({
icon: local.navigating ? (
<Spinner
className={cx(
css`
padding-left: 4px;
`
)}
/>
) : (
<ArrowUpRight size={15} />
),
})}
</div>
);
};
useEffect(() => {
if (arg.link && !local.init) {
if (typeof arg.link.text === "string") {
local.text = arg.link.text;
local.init = true;
} else if (typeof arg.link.text === "function") {
const res = arg.link.text({
field,
Link,
});
if (res instanceof Promise) {
res.then((text) => {
local.text = text;
local.init = true;
local.render();
});
} else {
local.text = res;
local.init = true;
}
}
}
local.render();
}, []);
return (
<div className={cx("c-px-2")}>
{!local.init ? (
<FieldLoading height="short" />
) : (
<Link>
{({ icon }) => {
return (
<>
<div>{local.text}</div>
{icon}
</>
);
}}
</Link>
)}
</div>
);
};
export type LinkParam = {
url: string;
where: any;
hash: any;
prefix: {
label: any;
url: string;
md?: { name: string; value: any };
}[];
};
const navigateLink = async (link: FieldProp["link"], field: FieldLocal) => {
let params = link.params(field);
if (typeof params === "object") {
if (params instanceof Promise) {
params = await params;
}
}
const md = params.md;
const where = params.where;
const prefix: LinkParam["prefix"] = [];
if (md) {
md.header.render();
if (md.header.breadcrumb.length > 0) {
const path = getPathname({ hash: false });
let i = 0;
for (const b of md.header.breadcrumb) {
prefix.push({
label: b.label,
url: `${path}`,
md:
i > 0
? { name: md.name, value: md.selected[md.pk?.name || ""] }
: undefined,
});
i++;
}
}
}
const values: LinkParam = {
url: getPathname({ hash: false }),
where,
prefix,
hash: "",
};
const vhash = hashSum(values);
values.hash = vhash;
if (!link.url) {
alert("No URL defined!");
return false;
}
await api._kv("set", vhash, values);
const lnk = location.hash.split("#").find((e) => e.startsWith("lnk="));
let prev_link = "";
if (lnk) {
prev_link = lnk.split("=").pop() || "";
if (prev_link) prev_link = prev_link + "+";
}
navigate(`${link.url}#lnk=${prev_link + vhash}`);
return true;
};
export const parseLink = () => {
const lnk = location.hash.split("#").find((e) => e.startsWith("lnk="));
if (lnk) {
const res = lnk.split("=").pop() || "";
if (res) {
return res.split("+");
}
}
return [];
};
export const fetchLinkParams = async (
parsed_link?: ReturnType<typeof parseLink>
) => {
const parsed = parsed_link || parseLink();
return await Promise.all(parsed.map((e) => api._kv("get", e)));
};

View File

@ -60,11 +60,7 @@ export const generateForm = async (
after_load: ` after_load: `
if (typeof md === "object") { if (typeof md === "object") {
opt.fm.status = "ready"; opt.fm.status = "ready";
if (item) { md.selected = opt.fm.data;
for (const [k,v] of Object.entries(item)) {
md.selected[k] = v;
}
}
md.header.render(); md.header.render();
md.render(); md.render();
} }

View File

@ -1,6 +1,7 @@
import { GFCol } from "@/gen/utils"; import { GFCol } from "@/gen/utils";
import { MutableRefObject, ReactElement, ReactNode } from "react"; import { FC, MutableRefObject, ReactElement, ReactNode } from "react";
import { editorFormData } from "./utils/ed-data"; import { editorFormData } from "./utils/ed-data";
import { MDLocal } from "../md/utils/typings";
export type FMProps = { export type FMProps = {
on_init: (arg: { fm: FMLocal; submit: any; reload: any }) => any; on_init: (arg: { fm: FMLocal; submit: any; reload: any }) => any;
@ -46,6 +47,18 @@ export type FieldProp = {
label: string; label: string;
desc?: string; desc?: string;
props?: any; props?: any;
link: {
text:
| string
| ((arg: {
field: FieldLocal;
Link: FC<{ children: any; }>;
}) => Promise<string> | string);
url: string;
params: (
field: FieldLocal
) => { md: MDLocal; where: any } | Promise<{ md: MDLocal; where: any }>;
};
fm: FMLocal; fm: FMLocal;
type: FieldType | (() => FieldType); type: FieldType | (() => FieldType);
required: ("y" | "n") | (() => "y" | "n"); required: ("y" | "n") | (() => "y" | "n");
@ -142,7 +155,7 @@ export type FMInternal = {
soft_delete: { soft_delete: {
field: any; field: any;
}; };
has_fields_container: boolean, has_fields_container: boolean;
}; };
export type FMLocal = FMInternal & { render: () => void }; export type FMLocal = FMInternal & { render: () => void };

View File

@ -12,7 +12,6 @@ import {
} from "./utils/md-hash"; } from "./utils/md-hash";
import { mdRenderLoop } from "./utils/md-render-loop"; import { mdRenderLoop } from "./utils/md-render-loop";
import { MDLocalInternal, MDProps } from "./utils/typings"; import { MDLocalInternal, MDProps } from "./utils/typings";
import { any } from "zod";
export const MasterDetail: FC<MDProps> = (arg) => { export const MasterDetail: FC<MDProps> = (arg) => {
const { const {
@ -36,8 +35,8 @@ export const MasterDetail: FC<MDProps> = (arg) => {
status: isEditor ? "init" : "ready", status: isEditor ? "init" : "ready",
actions: [], actions: [],
header: { header: {
loading: false,
breadcrumb: [], breadcrumb: [],
internalRender() {},
render: () => {}, render: () => {},
master: { prefix: null, suffix: null }, master: { prefix: null, suffix: null },
child: { prefix: null, suffix: null }, child: { prefix: null, suffix: null },
@ -60,6 +59,7 @@ export const MasterDetail: FC<MDProps> = (arg) => {
item: _item, item: _item,
}, },
params: { params: {
links: [],
hash: {}, hash: {},
tabs: {}, tabs: {},
parse: () => { parse: () => {
@ -93,7 +93,9 @@ export const MasterDetail: FC<MDProps> = (arg) => {
if (pk) { if (pk) {
const value = md.params.hash[md.name]; const value = md.params.hash[md.name];
if (value) { if (value) {
if (!md.selected) {
md.selected = { [pk.name]: value }; md.selected = { [pk.name]: value };
}
const tab = md.params.tabs[md.name]; const tab = md.params.tabs[md.name];
if (tab && md.tab.list.includes(tab)) { if (tab && md.tab.list.includes(tab)) {
md.tab.active = tab; md.tab.active = tab;

View File

@ -78,7 +78,7 @@ export const generateMDForm = async (
if (Object.keys(md.selected).length === 0){ if (Object.keys(md.selected).length === 0){
breads.push({ label: "Add New" }); breads.push({ label: "Add New" });
} else { } else {
breads.push({ label: "Edit" }); breads.push({ label: guessLabel(md.selected) || "Detail" });
} }
} }
} }

View File

@ -1,7 +1,7 @@
import { GenFn } from "lib/gen/utils"; import { GenFn } from "lib/gen/utils";
import { generateMDForm } from "./md-form"; import { generateMDForm } from "./md-form";
import { generateMDList } from "./md-list"; import { generateMDList } from "./md-list";
import capitalize from "lodash.capitalize";
const w = window as any; const w = window as any;
export const generateMasterDetail: GenFn<{ export const generateMasterDetail: GenFn<{
item: PrasiItem; item: PrasiItem;
@ -16,7 +16,9 @@ export const generateMasterDetail: GenFn<{
); );
const title = fn_title(); const title = fn_title();
if (!title && item.edit.props?.gen_table) { if (!title && item.edit.props?.gen_table) {
item.edit.setProp('title', item.edit.props?.gen_table) const table = { ...item.edit.props?.gen_table };
table.value = `${capitalize(table.value as string)}`;
item.edit.setProp("title", table);
} }
} catch (e) {} } catch (e) {}

View File

@ -1,7 +1,8 @@
import { useLocal } from "lib/utils/use-local";
import { FC, useEffect } from "react"; import { FC, useEffect } from "react";
import { breadcrumbPrefix } from "../utils/md-hash";
import { MDLocal, MDRef } from "../utils/typings"; import { MDLocal, MDRef } from "../utils/typings";
import { MDHeader } from "./MDHeader"; import { MDHeader } from "./MDHeader";
import { useLocal } from "lib/utils/use-local";
export const should_show_tab = (md: MDLocal) => { export const should_show_tab = (md: MDLocal) => {
if (isEditor) { if (isEditor) {
@ -114,19 +115,8 @@ export const MDRenderTab: FC<{
on_init: () => MDLocal; on_init: () => MDLocal;
breadcrumb: () => Array<any>; breadcrumb: () => Array<any>;
}> = ({ child, on_init, breadcrumb }) => { }> = ({ child, on_init, breadcrumb }) => {
const local = useLocal({ md: null as null | MDLocal }); const md = on_init();
if (!local.md) { md.header.child.breadcrumb = breadcrumb;
local.md = on_init();
}
const md = local.md;
md.header.render = () => {
md.header.breadcrumb = breadcrumb();
md.header.internalRender();
};
useEffect(() => {
md.header.render();
}, Object.values(md.deps || {}) || []);
return <>{child}</>; return <>{child}</>;
}; };

View File

@ -1,11 +1,19 @@
import { FC, useState } from "react"; import { FC, useState } from "react";
import { breadcrumbPrefix } from "../utils/md-hash";
import { MDLocal, MDRef } from "../utils/typings"; import { MDLocal, MDRef } from "../utils/typings";
export const MDHeader: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => { export const MDHeader: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => {
const [_, set] = useState({}); const [_, set] = useState({});
const head = mdr.item.edit.props?.header.value; const head = mdr.item.edit.props?.header.value;
const PassProp = mdr.PassProp; const PassProp = mdr.PassProp;
md.header.internalRender = () => set({});
md.header.render = () => set({}); md.header.render = () => set({});
const prefix = breadcrumbPrefix(md);
if (md.selected && md.header.child.breadcrumb) {
md.header.breadcrumb = [...prefix, ...md.header.child.breadcrumb()];
} else if (!md.selected && md.header.master.breadcrumb) {
md.header.breadcrumb = [...prefix, ...md.header.master.breadcrumb()];
}
return <PassProp md={md}>{head}</PassProp>; return <PassProp md={md}>{head}</PassProp>;
}; };

View File

@ -1,7 +1,7 @@
import { useLocal } from "lib/utils/use-local";
import { FC, useEffect } from "react"; import { FC, useEffect } from "react";
import { MDLocal, MDRef } from "../utils/typings"; import { MDLocal, MDRef } from "../utils/typings";
import { MDHeader } from "./MDHeader"; import { MDHeader } from "./MDHeader";
import { useLocal } from "lib/utils/use-local";
const w = window as unknown as { const w = window as unknown as {
md_panel_master: any; md_panel_master: any;
@ -18,14 +18,9 @@ export const MDRenderMaster: FC<{
local.md = on_init(); local.md = on_init();
} }
const md = local.md; const md = local.md;
md.header.master.breadcrumb = breadcrumb;
md.header.render = () => {
md.header.breadcrumb = breadcrumb();
md.header.internalRender();
};
useEffect(() => { useEffect(() => {
md.header.render();
if (md) { if (md) {
let width = 0; let width = 0;
let min_width = 0; let min_width = 0;

View File

@ -40,7 +40,6 @@ export const editorMDInit = (md: MDLocal, mdr: MDRef, arg: MDProps) => {
]; ];
md.status = "unready"; md.status = "unready";
} else { } else {
// md.header.breadcrumb = [];
md.status = "ready"; md.status = "ready";
} }
}; };

View File

@ -1,4 +1,6 @@
import { fetchLinkParams, parseLink } from "lib/comps/form/field/type/TypeLink";
import { MDLocal } from "./typings"; import { MDLocal } from "./typings";
import { BreadItem } from "lib/comps/custom/Breadcrumb";
export const masterDetailParseHash = (md: MDLocal) => { export const masterDetailParseHash = (md: MDLocal) => {
let raw_hash = decodeURIComponent(location.hash); let raw_hash = decodeURIComponent(location.hash);
@ -21,6 +23,27 @@ export const masterDetailParseHash = (md: MDLocal) => {
} }
} }
} }
const parsed_link = parseLink();
let changed = parsed_link.length !== md.params.links.length;
if (!changed) {
for (let i = 0; i < parsed_link.length; i++) {
if (parsed_link[i] !== md.params.links[i].hash) {
changed = true;
}
}
}
if (changed) {
md.params.links = [];
md.header.loading = true;
fetchLinkParams(parsed_link).then((links) => {
md.params.links = links;
md.header.loading = false;
md.header.render();
});
}
}; };
export const masterDetailApplyParams = (md: MDLocal) => { export const masterDetailApplyParams = (md: MDLocal) => {
@ -56,3 +79,40 @@ export const masterDetailApplyParams = (md: MDLocal) => {
location.hash = hash; location.hash = hash;
} }
}; };
export const breadcrumbPrefix = (md: MDLocal) => {
const prefix: BreadItem[] = [];
if (md.params.links && md.params.links.length > 0) {
const hashes: string[] = [];
for (const link of md.params.links) {
if (!hashes.includes(link.hash)) {
hashes.push(link.hash);
}
}
for (const link of md.params.links) {
for (const p of link.prefix) {
prefix.push({
label: p.label,
onClick(ev) {
let url = "";
const hashIndex = hashes.indexOf(link.hash);
const link_hashes = hashes.slice(0, hashIndex).join("+");
const lnk = link_hashes ? `#lnk=${link_hashes}` : ``;
if (p.md) {
url = `${link.url}#${p.md.name}=${p.md.value}${lnk}`;
} else {
url = `${link.url}${lnk}`;
}
if (url) {
navigate(url);
}
},
});
}
}
}
return prefix;
};

View File

@ -1,6 +1,7 @@
import { BreadItem } from "@/comps/custom/Breadcrumb"; import { BreadItem } from "@/comps/custom/Breadcrumb";
import { FMLocal } from "@/comps/form/typings"; import { FMLocal } from "@/comps/form/typings";
import { GFCol } from "@/gen/utils"; import { GFCol } from "@/gen/utils";
import { LinkParam } from "lib/comps/form/field/type/TypeLink";
import { ReactNode } from "react"; import { ReactNode } from "react";
type ID_MASTER_DETAIL = string; type ID_MASTER_DETAIL = string;
@ -38,11 +39,11 @@ export type MDLocalInternal = {
title: string; title: string;
status: "init" | "unready" | "ready"; status: "init" | "unready" | "ready";
header: { header: {
loading: boolean;
breadcrumb: BreadItem[]; breadcrumb: BreadItem[];
internalRender: () => void;
render: () => void; render: () => void;
master: { prefix: any; suffix: any }; master: { prefix: any; suffix: any; breadcrumb?: () => BreadItem[] };
child: { prefix: any; suffix: any }; child: { prefix: any; suffix: any; breadcrumb?: () => BreadItem[] };
}; };
actions: MDActions; actions: MDActions;
selected: any; selected: any;
@ -53,7 +54,8 @@ export type MDLocalInternal = {
internal: { action_should_refresh: boolean }; internal: { action_should_refresh: boolean };
master: { render: () => void }; master: { render: () => void };
params: { params: {
hash: any; links: LinkParam[];
hash: Record<string, any>;
tabs: any; tabs: any;
parse: () => void; parse: () => void;
apply: () => void; apply: () => void;

View File

@ -1,28 +1,41 @@
import { Skeleton } from "@/comps/ui/skeleton"; import { Skeleton } from "@/comps/ui/skeleton";
import { cn } from "lib/utils";
import { Loader2 } from "lucide-react";
import { FC } from "react";
export const FieldLoading = () => { export const FieldLoading: FC<{ height?: "normal" | "short" }> = (prop) => {
let height = "10px";
if (prop.height === "short") height = "6px";
return ( return (
<div className="field-inner c-flex c-flex-col c-space-y-1 c-p-1 c-justify-center"> <div className="field-inner c-flex c-flex-col c-space-y-1 c-p-1 c-justify-center">
<div className="c-flex c-space-x-1"> <div className="c-flex c-space-x-1">
<Skeleton <Skeleton
className={css` className={css`
width: 50px; width: 50px;
height: 10px; height: ${height};
`} `}
/> />
<Skeleton <Skeleton
className={css` className={css`
width: 50px; width: 50px;
height: 10px; height: ${height};
`} `}
/> />
</div> </div>
<Skeleton <Skeleton
className={css` className={css`
width: 80px; width: 80px;
height: 10px; height: ${height};
`} `}
/> />
</div> </div>
); );
}; };
export const Spinner = ({ className }: { className?: string }) => {
return (
<div className={className}>
<Loader2 className={cx("c-h-4 c-w-4 c-animate-spin")} />
</div>
);
};

View File

@ -1,5 +1,7 @@
export { FieldLoading } from "@/comps/ui/field-loading"; export { FieldLoading } from "@/comps/ui/field-loading";
import { lazify, lazifyMany } from "@/utils/lazify"; import { lazify, lazifyMany } from "@/utils/lazify";
export { guessLabel } from "./utils/guess-label";
export { fetchLinkParams } from "./comps/form/field/type/TypeLink";
export { prasi_gen } from "./gen/prasi_gen"; export { prasi_gen } from "./gen/prasi_gen";
export const Popover = lazify( export const Popover = lazify(

27
utils/guess-label.ts Executable file
View File

@ -0,0 +1,27 @@
import { validate } from "uuid";
export const guessLabel = (_obj: Record<string, any>, key?: string) => {
let label = "";
let obj = _obj;
if (key) obj = _obj[key];
const label_key =
Object.keys(obj)
.map((e) => e.toLowerCase())
.find((e) => e.includes("name") || e.includes("nama")) || "";
label = obj[label_key];
if (obj.length > 1) {
for (const v of Object.values(obj)) {
if (typeof v === "string" && v.length >= 2 && !validate(v)) {
label = v;
}
}
}
if (typeof label === "string" && label.length > 10) {
label = label.substring(0, 10) + "…";
}
return label;
};

View File

@ -1,4 +1,4 @@
export const getPathname = (url?: string) => { export const getPathname = (opt?: { hash?: boolean }) => {
if ( if (
["prasi.avolut.com"].includes(location.hostname) || ["prasi.avolut.com"].includes(location.hostname) ||
location.host === "localhost:4550" location.host === "localhost:4550"
@ -9,11 +9,8 @@ export const getPathname = (url?: string) => {
location.pathname.startsWith("/deploy") location.pathname.startsWith("/deploy")
) { ) {
const hash = location.hash; const hash = location.hash;
if (url?.startsWith("/prod")) {
return "/" + url.split("/").slice(3).join("/");
}
if (hash !== "") { if (hash !== "" && opt?.hash !== false) {
return "/" + location.pathname.split("/").slice(3).join("/") + hash; return "/" + location.pathname.split("/").slice(3).join("/") + hash;
} else { } else {
return "/" + location.pathname.split("/").slice(3).join("/"); return "/" + location.pathname.split("/").slice(3).join("/");