Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checklist #2168

Merged
merged 9 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading