nitropage
Version:
A free and open source, extensible visual page builder based on SolidStart.
264 lines (240 loc) • 6.13 kB
text/typescript
import { State } from "#../types";
import { NitroPage, NitroPageRevision } from "@prisma/client";
import { isEqual } from "es-toolkit";
import { error } from "../../../response";
import { updateFonts } from "../../font";
import updateLayoutSlots from "../../layout/update";
import { logger } from "../../log";
import { useDatabase } from "../../prisma";
import {
setDefaultFont,
setFavicon,
setMetaDescription,
setMetaImage,
setNotFoundPage,
setPageBackgroundColor,
Settings,
} from "../../settings";
import { DEBUG_PAGE_UPDATE } from "../../util";
import { publishPage } from "../publish";
import updateBlueprintDefaults from "./blueprintDefaults";
import { updateColors, updateRteColors } from "./colors";
import updatePresets from "./presets";
import createPageRevision from "./revision";
const updateSettings = async ({
page,
state,
prevState,
settings,
prevSettings,
}: {
state: State;
prevState?: State;
page: NitroPage;
settings: {
pages: Partial<Settings>;
projects: Partial<Settings>;
};
prevSettings?: {
pages: Partial<Settings>;
projects: Partial<Settings>;
};
}) => {
const db = useDatabase();
if (state.defaultFont !== prevState?.defaultFont) {
if (DEBUG_PAGE_UPDATE) logger.info("Update default font");
if (state.defaultFont) {
const font = await db.nitroFont.findUnique({
where: {
publicId: state.defaultFont,
},
});
await setDefaultFont(font?.id, {
projectId: page.projectId,
});
} else {
await setDefaultFont(undefined, {
projectId: page.projectId,
});
}
}
if (state.metaDescription !== prevState?.metaDescription) {
if (DEBUG_PAGE_UPDATE) logger.info("Update meta description");
await setMetaDescription(
state.metaDescription !== "" ? state.metaDescription : undefined,
{
pageId: page.id,
},
);
}
if (
!isEqual(
settings.pages.metaImage?.value,
prevSettings?.pages.metaImage?.value,
)
) {
if (DEBUG_PAGE_UPDATE) logger.info("Update page meta image");
await setMetaImage(settings.pages.metaImage?.value, {
pageId: page.id,
});
}
if (
!isEqual(
settings.projects.metaImage?.value,
prevSettings?.projects.metaImage?.value,
)
) {
if (DEBUG_PAGE_UPDATE)
logger.info("Update project meta image", {
prev: prevSettings?.projects.metaImage?.value,
next: settings.projects.metaImage?.value,
});
await setMetaImage(settings.projects.metaImage?.value, {
projectId: page.projectId,
});
}
if (
!isEqual(
settings.projects.favicon?.value,
prevSettings?.projects.favicon?.value,
)
) {
if (DEBUG_PAGE_UPDATE) logger.info("Update project favicon");
await setFavicon(settings.projects.favicon?.value, {
projectId: page.projectId,
});
}
if (!isEqual(state.backgroundColor, prevState?.backgroundColor)) {
if (DEBUG_PAGE_UPDATE) logger.info("Update background color");
await setPageBackgroundColor(state.backgroundColor, {
projectId: page.projectId,
});
}
await updateColors({ page, state, prevState });
await updateRteColors({ page, state, prevState });
await updateBlueprintDefaults({ page, state, prevState });
if (!isEqual(state.notFound, prevState?.notFound)) {
if (DEBUG_PAGE_UPDATE) logger.info("Update not found");
await setNotFoundPage(state.notFound ? page.id : undefined, {
projectId: page.projectId,
});
}
};
export const updatePage = async ({
publish,
pageRevisionId,
prevState,
state,
prevSettings,
settings,
pageId,
}: {
publish?: boolean;
pageRevisionId?: string;
prevState?: State;
state: State;
prevSettings?: {
pages: Partial<Settings>;
projects: Partial<Settings>;
};
settings: {
pages: Partial<Settings>;
projects: Partial<Settings>;
};
pageId: string;
}) => {
const startTime = performance.now();
const db = useDatabase();
const page = await db.nitroPage.findUnique({
include: {
layoutSlots: true,
},
where: {
id: pageId,
},
});
if (!page) {
return error({
message: "Page not found",
status: 410,
});
}
let pageRevision: NitroPageRevision | undefined | null = undefined;
if (pageRevisionId) {
pageRevision = await db.nitroPageRevision.findFirst({
where: {
id: pageRevisionId,
page: { id: pageId },
},
});
}
if (!pageRevision) {
pageRevision = await db.nitroPageRevision.findFirst({
where: {
page: { id: pageId },
},
orderBy: {
savedAt: "desc",
},
});
}
if (!pageRevision) {
return error({
message: "No page revision found",
status: 410,
});
}
const parallelWork: Promise<any>[] = [];
parallelWork.push(
updateSettings({ state, prevState, page, settings, prevSettings }),
);
parallelWork.push(
updateFonts({
fonts: state.fonts,
prevFonts: prevState?.fonts,
}),
);
if (state.includeInFeed !== prevState?.includeInFeed) {
await db.nitroPage.update({
select: {
id: true,
},
where: {
id: pageId,
},
data: {
includeInFeed: state.includeInFeed,
},
});
}
await updateLayoutSlots({ page, state, prevState });
const { deletedIds: deletedPresets } = await updatePresets({
projectId: page.projectId,
presets: state.presets,
prevPresets: prevState?.presets,
});
if (state.pendingDeletes) {
await db.nitroPreset.deleteMany({
where: {
id: { in: state.pendingDeletes.presets },
},
});
}
pageRevision =
(await createPageRevision({
page,
state,
prevState,
deletedPresets,
})) ?? pageRevision;
await Promise.all(parallelWork);
if (publish) {
await publishPage(pageRevision.id);
}
const endTime = performance.now();
if (DEBUG_PAGE_UPDATE)
logger.info("Update page took", (endTime - startTime).toFixed(3) + "ms");
return {
revisionId: pageRevision.id,
};
};