Skip to content

Commit

Permalink
Checklist (#2168)
Browse files Browse the repository at this point in the history
* Checklist

* Reload attempt

* Fetch data at page and pass merged widget data down props

* Fix

* Required type fix

* Fix

* Fix type

* Fix editor types

* Preload and fix editor
  • Loading branch information
timmo001 authored May 27, 2023
1 parent 6a580fe commit 0c84618
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 169 deletions.
16 changes: 16 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,27 @@ model Widget {
homeAssistant WidgetHomeAssistant[]
image WidgetImage[]
markdown WidgetMarkdown[]
checklist WidgetChecklist[]
@@index([id, sectionId], name: "id_sectionId_unique")
@@index([sectionId, position], name: "sectionId_position_unique")
}

model WidgetChecklist {
widgetId String @id
widget Widget @relation(fields: [widgetId], references: [id], onDelete: Cascade)
items WidgetChecklistItem[]
}

model WidgetChecklistItem {
id String @id @default(cuid())
position Int @default(10)
content String
checked Boolean @default(false)
checklist WidgetChecklist @relation(fields: [checklistWidgetId], references: [widgetId])
checklistWidgetId String
}

model WidgetFrame {
widgetId String @id
widget Widget @relation(fields: [widgetId], references: [id], onDelete: Cascade)
Expand Down
22 changes: 19 additions & 3 deletions src/app/dashboards/[dashboardId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import type { Metadata } from "next";
import { notFound } from "next/navigation";

import type { DashboardModel } from "@/types/dashboard.type";
import type { SectionModel } from "@/types/section.type";
import { Dashboard } from "@/components/dashboard/views/Dashboard";
import { prisma } from "@/utils/prisma";
import { Section } from "@/components/dashboard/views/Section";
import { widgetGetData } from "@/utils/serverActions/widget";

export const metadata: Metadata = {
title: "Dashboard | Home Panel",
Expand All @@ -23,7 +26,7 @@ export default async function Page({
* The dashboard object retrieved from the database.
* Contains all the sections and widgets associated with the dashboard.
*/
const dashboard: DashboardModel | null = await prisma.dashboard.findUnique({
let dashboard: DashboardModel | null = (await prisma.dashboard.findUnique({
where: {
id: params.dashboardId,
},
Expand All @@ -40,9 +43,22 @@ export default async function Page({
orderBy: { position: "asc" },
},
},
});
})) as DashboardModel | null;

if (!dashboard) return notFound();

return <Dashboard dashboard={dashboard} />;
// Fetch data for all widgets
for (const section of dashboard.sections) {
for (const widget of section.widgets) {
widget.data = await widgetGetData(widget.id, widget.type);
}
}

return (
<Dashboard dashboard={dashboard}>
{dashboard.sections.map((section: SectionModel) => (
<Section key={section.id} data={section} />
))}
</Dashboard>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";

import type { WidgetWithSectionModel } from "@/types/widget.type";
import type { SectionModel } from "@/types/section.type";
import type { WidgetModel } from "@/types/widget.type";
import { EditWidget } from "@/components/dashboard/editors/Widget";
import { HomeAssistantProvider } from "@/providers/HomeAssistantProvider";
import { prisma } from "@/utils/prisma";
import { widgetGetData } from "@/utils/serverActions/widget";

export const metadata: Metadata = {
title: "Edit Widget | Home Panel",
Expand All @@ -20,20 +22,28 @@ export default async function Page({
}): Promise<JSX.Element> {
console.log("Edit Widget:", params);

let data: WidgetWithSectionModel | null = await prisma.widget.findUnique({
where: {
id: params.widgetId,
},
const section: SectionModel | null = (await prisma.section.findUnique({
include: {
section: true,
widgets: {
where: {
id: params.widgetId,
},
},
},
});
where: {
id: params.sectionId,
},
})) as SectionModel | null;

if (!section) return notFound();

if (!data) return notFound();
for (const widget of section.widgets) {
widget.data = await widgetGetData(widget.id, widget.type);
}

return (
<HomeAssistantProvider dashboardId={params.dashboardId}>
<EditWidget dashboardId={params.dashboardId} data={data} />
<EditWidget dashboardId={params.dashboardId} section={section} />
</HomeAssistantProvider>
);
}
54 changes: 37 additions & 17 deletions src/components/dashboard/editors/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
Unstable_Grid2 as Grid2,
} from "@mui/material";

import type { WidgetWithSectionModel } from "@/types/widget.type";
import type { SectionModel } from "@/types/section.type";
import type { WidgetModel } from "@/types/widget.type";
import { EditWidgetBase } from "@/components/dashboard/editors/widgets/Base";
import { EditWidgetFrame } from "@/components/dashboard/editors/widgets/Frame";
import { EditWidgetHomeAssistant } from "./widgets/HomeAssistant";
Expand All @@ -20,59 +21,61 @@ import { WidgetType } from "@/types/widget.type";

export function EditWidget({
dashboardId,
data,
section,
}: {
dashboardId: string;
data: WidgetWithSectionModel;
section: SectionModel;
}): JSX.Element {
const widget: WidgetModel = section.widgets[0];
const { id, position, sectionId, title, type, width } = widget;
const [widgetData, setWidgetData] = useState<any>(null);

useEffect(() => {
(async () => {
const newData = await widgetGetData(data.id, data.type);
const newData = await widgetGetData(id, type);
setWidgetData(newData);
})();
}, [data.id, data.type]);
}, [id, type]);

const widgetView: JSX.Element = useMemo(() => {
if (!widgetData) return <Skeleton variant="text" />;
switch (data.type) {
switch (type) {
case WidgetType.Frame:
return (
<EditWidgetFrame
dashboardId={dashboardId}
sectionId={data.sectionId}
data={widgetData}
sectionId={sectionId}
widgetData={widgetData}
/>
);
case WidgetType.HomeAssistant:
return (
<EditWidgetHomeAssistant
dashboardId={dashboardId}
sectionId={data.sectionId}
data={widgetData}
sectionId={sectionId}
widgetData={widgetData}
/>
);
case WidgetType.Image:
return (
<EditWidgetImage
dashboardId={dashboardId}
sectionId={data.sectionId}
data={widgetData}
sectionId={sectionId}
widgetData={widgetData}
/>
);
case WidgetType.Markdown:
return (
<EditWidgetMarkdown
dashboardId={dashboardId}
sectionId={data.sectionId}
data={widgetData}
sectionId={sectionId}
widgetData={widgetData}
/>
);
default:
return <div>Unknown widget type</div>;
}
}, [dashboardId, data.type, data.sectionId, widgetData]);
}, [dashboardId, type, sectionId, widgetData]);

return (
<Grid2
Expand All @@ -90,14 +93,31 @@ export function EditWidget({
<CardContent sx={{ flexGrow: 1 }}>
<Typography variant="h5">Edit Widget</Typography>
<Grid2 container direction="column" sx={{ marginTop: "1rem" }}>
<EditWidgetBase dashboardId={dashboardId} data={data} />
<EditWidgetBase dashboardId={dashboardId} widget={widget} />
{widgetView}
</Grid2>
</CardContent>
</Card>
</Grid2>
<Grid2 xs>
<Section data={{ ...data.section, widgets: [data] }} />
{widgetData && (
<Section
data={{
...section,
widgets: [
{
id,
position,
type,
title,
width,
sectionId,
data: widgetData,
},
],
}}
/>
)}
</Grid2>
</Grid2>
);
Expand Down
27 changes: 9 additions & 18 deletions src/components/dashboard/editors/widgets/Base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,34 @@ import { WidgetType } from "@/types/widget.type";

export function EditWidgetBase({
dashboardId,
data,
widget,
}: {
dashboardId: string;
data: Widget;
widget: Widget;
}): JSX.Element {
const { id, title, type, width } = widget;
return (
<>
<TextField
name="title"
label="Title"
margin="dense"
defaultValue={data.title || ""}
defaultValue={title || ""}
onChange={async (e) =>
await widgetUpdate(
dashboardId,
data.id,
e.target.name,
e.target.value
)
await widgetUpdate(dashboardId, id, e.target.name, e.target.value)
}
/>
<TextField
name="width"
label="Width"
margin="dense"
defaultValue={data.width || ""}
defaultValue={width || ""}
onChange={async (e) =>
await widgetUpdate(
dashboardId,
data.id,
e.target.name,
e.target.value
)
await widgetUpdate(dashboardId, id, e.target.name, e.target.value)
}
/>
<Autocomplete
defaultValue={data.type}
defaultValue={type}
options={Object.values(WidgetType)}
getOptionLabel={(option) => {
// Split camelCase to words and capitalize first letter
Expand All @@ -62,7 +53,7 @@ export function EditWidgetBase({
)}
onChange={async (_, value: string | null) => {
if (!value) return;
await widgetUpdate(dashboardId, data.id, "type", value);
await widgetUpdate(dashboardId, id, "type", value);
}}
/>
</>
Expand Down
12 changes: 6 additions & 6 deletions src/components/dashboard/editors/widgets/Frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ import { widgetFrameUpdate } from "@/utils/serverActions/widget";
export function EditWidgetFrame({
dashboardId,
sectionId,
data,
widgetData,
}: {
dashboardId: string;
sectionId: string;
data: WidgetFrame;
widgetData: WidgetFrame;
}): JSX.Element {
return (
<>
<TextField
name="url"
label="URL"
margin="dense"
defaultValue={data.url || ""}
defaultValue={widgetData.url || ""}
onChange={async (e) =>
await widgetFrameUpdate(
dashboardId,
sectionId,
data.widgetId,
widgetData.widgetId,
e.target.name,
e.target.value
)
Expand All @@ -34,12 +34,12 @@ export function EditWidgetFrame({
name="height"
label="Height"
margin="dense"
defaultValue={data.height || ""}
defaultValue={widgetData.height || ""}
onChange={async (e) =>
await widgetFrameUpdate(
dashboardId,
sectionId,
data.widgetId,
widgetData.widgetId,
e.target.name,
e.target.value
)
Expand Down
Loading

0 comments on commit 0c84618

Please sign in to comment.