mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 04:46:05 +00:00
updated admin to use swr hooks instead of react-query
This commit is contained in:
@@ -2,12 +2,11 @@ import { ucFirst } from "core/utils";
|
||||
import type { Entity, EntityData, EntityRelation } from "data";
|
||||
import { Fragment, useState } from "react";
|
||||
import { TbDots } from "react-icons/tb";
|
||||
import { useClient } from "ui/client";
|
||||
import { useClient, useEntityQuery } from "ui/client";
|
||||
import { useBkndData } from "ui/client/schema/data/use-bknd-data";
|
||||
import { Button } from "ui/components/buttons/Button";
|
||||
import { IconButton } from "ui/components/buttons/IconButton";
|
||||
import { Dropdown } from "ui/components/overlay/Dropdown";
|
||||
import { useEntity } from "ui/container";
|
||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
import { Breadcrumbs2 } from "ui/layouts/AppShell/Breadcrumbs2";
|
||||
@@ -25,22 +24,23 @@ export function DataEntityUpdate({ params }) {
|
||||
const [navigate] = useNavigate();
|
||||
useBrowserTitle(["Data", entity.label, `#${entityId}`]);
|
||||
const targetRelations = relations.listableRelationsOf(entity);
|
||||
//console.log("targetRelations", targetRelations, relations.relationsOf(entity));
|
||||
// filter out polymorphic for now
|
||||
//.filter((r) => r.type() !== "poly");
|
||||
|
||||
const local_relation_refs = relations
|
||||
.sourceRelationsOf(entity)
|
||||
?.map((r) => r.other(entity).reference);
|
||||
|
||||
const container = useEntity(entity.name, entityId, {
|
||||
fetch: {
|
||||
query: {
|
||||
with: local_relation_refs
|
||||
}
|
||||
const $q = useEntityQuery(
|
||||
entity.name,
|
||||
entityId,
|
||||
{
|
||||
with: local_relation_refs
|
||||
},
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
function goBack(state?: Record<string, any>) {
|
||||
function goBack() {
|
||||
window.history.go(-1);
|
||||
}
|
||||
|
||||
@@ -52,43 +52,39 @@ export function DataEntityUpdate({ params }) {
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await container.actions.update(changeSet);
|
||||
console.log("update:res", res);
|
||||
if (res.data?.error) {
|
||||
setError(res.data.error);
|
||||
} else {
|
||||
error && setError(null);
|
||||
try {
|
||||
await $q.update(changeSet);
|
||||
if (error) setError(null);
|
||||
goBack();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to update");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete() {
|
||||
if (confirm("Are you sure to delete?")) {
|
||||
const res = await container.actions.remove();
|
||||
if (res.error) {
|
||||
setError(res.error);
|
||||
} else {
|
||||
error && setError(null);
|
||||
try {
|
||||
await $q._delete();
|
||||
if (error) setError(null);
|
||||
goBack();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to delete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = $q.data;
|
||||
const { Form, handleSubmit } = useEntityForm({
|
||||
action: "update",
|
||||
entity,
|
||||
initialData: container.data,
|
||||
initialData: $q.data?.toJSON(),
|
||||
onSubmitted
|
||||
});
|
||||
//console.log("form.data", Form.state.values, container.data);
|
||||
|
||||
const makeKey = (key: string | number = "") =>
|
||||
`${params.entity.name}_${entityId}_${String(key)}`;
|
||||
|
||||
const fieldsDisabled =
|
||||
container.raw.fetch?.isLoading ||
|
||||
container.status.fetch.isUpdating ||
|
||||
Form.state.isSubmitting;
|
||||
const fieldsDisabled = $q.isLoading || $q.isValidating || Form.state.isSubmitting;
|
||||
|
||||
return (
|
||||
<Fragment key={makeKey()}>
|
||||
@@ -103,7 +99,7 @@ export function DataEntityUpdate({ params }) {
|
||||
onClick: () => {
|
||||
bkndModals.open("debug", {
|
||||
data: {
|
||||
data: container.data as any,
|
||||
data: data as any,
|
||||
entity: entity.toJSON(),
|
||||
schema: entity.toSchema(true),
|
||||
form: Form.state.values,
|
||||
@@ -165,7 +161,7 @@ export function DataEntityUpdate({ params }) {
|
||||
entityId={entityId}
|
||||
handleSubmit={handleSubmit}
|
||||
fieldsDisabled={fieldsDisabled}
|
||||
data={container.data ?? undefined}
|
||||
data={data ?? undefined}
|
||||
Form={Form}
|
||||
action="update"
|
||||
className="flex flex-grow flex-col gap-3 p-3"
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { Type } from "core/utils";
|
||||
import { useState } from "react";
|
||||
import { useEntityMutate, useEntityQuery } from "ui/client";
|
||||
import { useBknd } from "ui/client/BkndProvider";
|
||||
import { Button } from "ui/components/buttons/Button";
|
||||
import { type EntityData, useEntity } from "ui/container";
|
||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import { useSearch } from "ui/hooks/use-search";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
import { Breadcrumbs2 } from "ui/layouts/AppShell/Breadcrumbs2";
|
||||
import { routes } from "ui/lib/routes";
|
||||
import { EntityForm } from "ui/modules/data/components/EntityForm";
|
||||
import { useEntityForm } from "ui/modules/data/hooks/useEntityForm";
|
||||
import { useBknd } from "../../client/BkndProvider";
|
||||
import { Button } from "../../components/buttons/Button";
|
||||
import { type EntityData, useEntity } from "../../container";
|
||||
import { useBrowserTitle } from "../../hooks/use-browser-title";
|
||||
import { useSearch } from "../../hooks/use-search";
|
||||
import * as AppShell from "../../layouts/AppShell/AppShell";
|
||||
import { Breadcrumbs2 } from "../../layouts/AppShell/Breadcrumbs2";
|
||||
import { routes } from "../../lib/routes";
|
||||
|
||||
export function DataEntityCreate({ params }) {
|
||||
const { app } = useBknd();
|
||||
@@ -17,40 +18,37 @@ export function DataEntityCreate({ params }) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
useBrowserTitle(["Data", entity.label, "Create"]);
|
||||
|
||||
const container = useEntity(entity.name);
|
||||
const $q = useEntityMutate(entity.name);
|
||||
|
||||
// @todo: use entity schema for prefilling
|
||||
const search = useSearch(Type.Object({}), {});
|
||||
console.log("search", search.value);
|
||||
|
||||
function goBack(state?: Record<string, any>) {
|
||||
function goBack() {
|
||||
window.history.go(-1);
|
||||
}
|
||||
|
||||
async function onSubmitted(changeSet?: EntityData) {
|
||||
console.log("create:changeSet", changeSet);
|
||||
//return;
|
||||
const res = await container.actions.create(changeSet);
|
||||
console.log("create:res", res);
|
||||
if (res.data?.error) {
|
||||
setError(res.data.error);
|
||||
} else {
|
||||
error && setError(null);
|
||||
if (!changeSet) return;
|
||||
|
||||
try {
|
||||
await $q.create(changeSet);
|
||||
if (error) setError(null);
|
||||
// @todo: navigate to created?
|
||||
goBack();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to create");
|
||||
}
|
||||
}
|
||||
|
||||
const { Form, handleSubmit, values } = useEntityForm({
|
||||
const { Form, handleSubmit } = useEntityForm({
|
||||
action: "create",
|
||||
entity,
|
||||
initialData: search.value,
|
||||
onSubmitted
|
||||
});
|
||||
|
||||
const fieldsDisabled =
|
||||
container.raw.fetch?.isLoading ||
|
||||
container.status.fetch.isUpdating ||
|
||||
Form.state.isSubmitting;
|
||||
const fieldsDisabled = $q.isLoading || $q.isValidating || Form.state.isSubmitting;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Type } from "core/utils";
|
||||
import { querySchema } from "data";
|
||||
import { TbDots } from "react-icons/tb";
|
||||
import { useApiQuery } from "ui/client";
|
||||
import { useBkndData } from "ui/client/schema/data/use-bknd-data";
|
||||
import { Button } from "ui/components/buttons/Button";
|
||||
import { IconButton } from "ui/components/buttons/IconButton";
|
||||
import { Message } from "ui/components/display/Message";
|
||||
import { Dropdown } from "ui/components/overlay/Dropdown";
|
||||
import { EntitiesContainer } from "ui/container";
|
||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import { useSearch } from "ui/hooks/use-search";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
@@ -25,19 +25,33 @@ const searchSchema = Type.Composite(
|
||||
{ additionalProperties: false }
|
||||
);
|
||||
|
||||
const PER_PAGE_OPTIONS = [5, 10, 25];
|
||||
|
||||
export function DataEntityList({ params }) {
|
||||
const { $data, relations } = useBkndData();
|
||||
const entity = $data.entity(params.entity as string);
|
||||
const { $data } = useBkndData();
|
||||
const entity = $data.entity(params.entity as string)!;
|
||||
useBrowserTitle(["Data", entity?.label ?? params.entity]);
|
||||
const [navigate] = useNavigate();
|
||||
const search = useSearch(searchSchema, {
|
||||
select: entity?.getSelect(undefined, "table") ?? [],
|
||||
sort: entity?.getDefaultSort()
|
||||
});
|
||||
console.log("search", search.value);
|
||||
useBrowserTitle(["Data", entity?.label ?? params.entity]);
|
||||
const PER_PAGE_OPTIONS = [5, 10, 25];
|
||||
|
||||
//console.log("search", search.value);
|
||||
const $q = useApiQuery(
|
||||
(api) =>
|
||||
api.data.readMany(entity.name, {
|
||||
select: search.value.select,
|
||||
limit: search.value.perPage,
|
||||
offset: (search.value.page - 1) * search.value.perPage,
|
||||
sort: search.value.sort
|
||||
}),
|
||||
{
|
||||
revalidateOnFocus: true,
|
||||
keepPreviousData: true
|
||||
}
|
||||
);
|
||||
const data = $q.data?.data;
|
||||
const meta = $q.data?.body.meta;
|
||||
|
||||
function handleClickRow(row: Record<string, any>) {
|
||||
if (entity) navigate(routes.data.entity.edit(entity.name, row.id));
|
||||
@@ -65,6 +79,8 @@ export function DataEntityList({ params }) {
|
||||
return <Message.NotFound description={`Entity "${params.entity}" doesn't exist.`} />;
|
||||
}
|
||||
|
||||
const isUpdating = $q.isLoading && $q.isValidating;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppShell.SectionHeader
|
||||
@@ -103,45 +119,25 @@ export function DataEntityList({ params }) {
|
||||
<SearchInput placeholder={`Filter ${entity.label}`} />
|
||||
</div>*/}
|
||||
|
||||
<EntitiesContainer
|
||||
entity={entity.name}
|
||||
query={{
|
||||
select: search.value.select,
|
||||
limit: search.value.perPage,
|
||||
offset: (search.value.page - 1) * search.value.perPage,
|
||||
sort: search.value.sort
|
||||
}}
|
||||
<div
|
||||
data-updating={isUpdating ? 1 : undefined}
|
||||
className="data-[updating]:opacity-50 transition-opacity pb-10"
|
||||
>
|
||||
{(params) => {
|
||||
if (params.status.fetch.isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isUpdating = params.status.fetch.isUpdating;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-updating={isUpdating ? 1 : undefined}
|
||||
className="data-[updating]:opacity-50 transition-opacity pb-10"
|
||||
>
|
||||
<EntityTable2
|
||||
data={params.data ?? []}
|
||||
entity={entity}
|
||||
select={search.value.select}
|
||||
onClickRow={handleClickRow}
|
||||
page={search.value.page}
|
||||
sort={search.value.sort}
|
||||
onClickSort={handleSortClick}
|
||||
perPage={search.value.perPage}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
total={params.meta?.count}
|
||||
onClickPage={handleClickPage}
|
||||
onClickPerPage={handleClickPerPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</EntitiesContainer>
|
||||
<EntityTable2
|
||||
data={data ?? null}
|
||||
entity={entity}
|
||||
/*select={search.value.select}*/
|
||||
onClickRow={handleClickRow}
|
||||
page={search.value.page}
|
||||
sort={search.value.sort}
|
||||
onClickSort={handleSortClick}
|
||||
perPage={search.value.perPage}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
total={meta?.count}
|
||||
onClickPage={handleClickPage}
|
||||
onClickPerPage={handleClickPerPage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppShell.Scrollable>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user