mirror of
https://github.com/ajnart/homarr.git
synced 2026-01-17 04:52:15 +01:00
✨ Make notebook editable with database
This commit is contained in:
@@ -1,46 +1,52 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
import { getConfig } from '~/tools/config/getConfig';
|
||||
import { BackendConfigType } from '~/types/config';
|
||||
import { INotebookWidget } from '~/widgets/notebook/NotebookWidgetTile';
|
||||
import { db } from '~/server/db';
|
||||
import { items, widgetOptions } from '~/server/db/schema';
|
||||
|
||||
import { createTRPCRouter, publicProcedure } from '../trpc';
|
||||
|
||||
export const notebookRouter = createTRPCRouter({
|
||||
update: publicProcedure
|
||||
.input(z.object({ widgetId: z.string(), content: z.string(), configName: z.string() }))
|
||||
.input(z.object({ widgetId: z.string(), content: z.string(), boardName: z.string() }))
|
||||
.mutation(async ({ input }) => {
|
||||
//TODO: #1305 Remove use of DISABLE_EDIT_MODE for auth update
|
||||
if (process.env.DISABLE_EDIT_MODE?.toLowerCase() === 'true') {
|
||||
throw new TRPCError({
|
||||
code: 'METHOD_NOT_SUPPORTED',
|
||||
message: 'Edit is not allowed, because edit mode is disabled',
|
||||
});
|
||||
}
|
||||
const item = await db.query.items.findFirst({
|
||||
where: and(eq(items.id, input.widgetId), eq(items.type, 'widget')),
|
||||
with: {
|
||||
widget: {
|
||||
with: {
|
||||
options: {
|
||||
where: eq(widgetOptions.path, 'content'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const config = getConfig(input.configName);
|
||||
const widget = config.widgets.find((widget) => widget.id === input.widgetId) as
|
||||
| INotebookWidget
|
||||
| undefined;
|
||||
|
||||
if (!widget) {
|
||||
if (!item?.widget) {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
code: 'NOT_FOUND',
|
||||
message: 'Specified widget was not found',
|
||||
});
|
||||
}
|
||||
|
||||
widget.options.content = input.content;
|
||||
// Update existing content
|
||||
if (item.widget.options.some((o) => o.path === 'content')) {
|
||||
await db
|
||||
.update(widgetOptions)
|
||||
.set({ value: input.content })
|
||||
.where(
|
||||
and(eq(widgetOptions.widgetId, item.widget.id), eq(widgetOptions.path, 'content'))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Make this work
|
||||
/*const newConfig: BackendConfigType = {
|
||||
...config,
|
||||
widgets: [...config.widgets.filter((w) => w.id !== widget.id), widget],
|
||||
};
|
||||
|
||||
const targetPath = path.join('data/configs', `${input.configName}.json`);
|
||||
fs.writeFileSync(targetPath, JSON.stringify(newConfig, null, 2), 'utf8');*/
|
||||
// Or create new content
|
||||
await db.insert(widgetOptions).values({
|
||||
widgetId: item.widget.id,
|
||||
path: 'content',
|
||||
value: input.content,
|
||||
type: 'string',
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ import StarterKit from '@tiptap/starter-kit';
|
||||
import { useState } from 'react';
|
||||
import { useRequiredBoard } from '~/components/Board/context';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useConfigStore } from '~/config/store';
|
||||
import { useColorTheme } from '~/tools/color';
|
||||
import { api } from '~/utils/api';
|
||||
|
||||
@@ -25,7 +24,7 @@ export function Editor({ widget }: { widget: INotebookWidget }) {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
||||
const board = useRequiredBoard();
|
||||
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||
const utils = api.useContext();
|
||||
const { primaryColor } = useColorTheme();
|
||||
|
||||
const { mutateAsync } = api.notebook.update.useMutation();
|
||||
@@ -45,26 +44,34 @@ export function Editor({ widget }: { widget: INotebookWidget }) {
|
||||
const current = !previous;
|
||||
if (!editor) return current;
|
||||
editor.setEditable(current);
|
||||
if (current) return current;
|
||||
|
||||
updateConfig(
|
||||
board.name!,
|
||||
(previous) => {
|
||||
const currentWidget = previous.widgets.find((x) => x.id === widget.id);
|
||||
currentWidget!.properties.content = debouncedContent;
|
||||
|
||||
return {
|
||||
...previous,
|
||||
widgets: [
|
||||
...previous.widgets.filter((iterationWidget) => iterationWidget.id !== widget.id),
|
||||
currentWidget!,
|
||||
],
|
||||
};
|
||||
},
|
||||
true
|
||||
);
|
||||
utils.boards.byName.setData({ boardName: board.name }, (previous) => {
|
||||
if (!previous) return previous;
|
||||
return {
|
||||
...previous,
|
||||
sections: previous.sections.map((section) => {
|
||||
if (!section.items.some((item) => item.id === widget.id)) return section;
|
||||
return {
|
||||
...section,
|
||||
items: section.items.map((item) => {
|
||||
if (item.id !== widget.id) return item;
|
||||
const notebookEditor = item as INotebookWidget;
|
||||
return {
|
||||
...notebookEditor,
|
||||
options: {
|
||||
...notebookEditor.options,
|
||||
content: debouncedContent,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
void mutateAsync({
|
||||
configName: board.name!,
|
||||
boardName: board.name!,
|
||||
content: debouncedContent,
|
||||
widgetId: widget.id,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user