feat: Store updated state in the source YAML file

This commit is contained in:
Lewis England 2023-05-22 10:00:33 +00:00
parent d4c764e854
commit f5f5721cf0
6 changed files with 63 additions and 27 deletions

View File

@ -1,12 +1,22 @@
import { useState } from "react";
import ErrorBoundary from "components/errorboundry"; import ErrorBoundary from "components/errorboundry";
import List from "components/tasklist/list"; import List from "components/tasklist/list";
export default function TaskListGroup({ group }) { export default function TaskListGroup({groupDetail, groupUpdate}) {
const [group, setGroup] = useState(groupDetail)
const groupName = Object.keys(group)[0]
const groupTasks = Object.values(group)[0]
const listUpdate = () => {
setGroup(group)
groupUpdate()
}
return ( return (
<div key={group.name} className="flex-1"> <div key={groupName} className="flex-1">
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2> <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{groupName}</h2>
<ErrorBoundary> <ErrorBoundary>
<List tasklist={group.tasklist} /> <List listDetail={groupTasks} listUpdate={listUpdate} />
</ErrorBoundary> </ErrorBoundary>
</div> </div>
); );

View File

@ -1,9 +1,19 @@
export default function Item({ task }) { import {useState} from "react";
export default function Item({taskDetail, taskUpdate}) {
const [task, setTask] = useState(taskDetail)
const toggleComplete = () => {
task.checked = !task.checked;
setTask(task)
taskUpdate()
}
return ( return (
<li key={task.title}> <li key={task.title}>
<div className="flex block w-full text-left transition-all h-15 mb-3 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10"> <div className="flex block w-full text-left transition-all h-15 mb-3 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10">
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md"> <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
<input type="checkbox" className="checkbox bg-theme-500/10 text-theme-200 dark:text-theme-700" id={task.title} defaultChecked={task.checked}/> <input type="checkbox" className="checkbox bg-theme-500/10 text-theme-200 dark:text-theme-700" id={task.title} defaultChecked={task.checked} onChange={toggleComplete}/>
</div> </div>
<div className="flex-1 flex items-center justify-between rounded-r-md "> <div className="flex-1 flex items-center justify-between rounded-r-md ">
<div className="flex-1 grow pl-3 py-2 text-xs">{task.title}</div> <div className="flex-1 grow pl-3 py-2 text-xs">{task.title}</div>

View File

@ -1,10 +1,19 @@
import { useState } from "react";
import Item from "components/tasklist/item"; import Item from "components/tasklist/item";
export default function List({ tasklist }) { export default function List({listDetail, listUpdate}) {
const [tasks, setTasks] = useState(listDetail)
const taskUpdate = () => {
setTasks(tasks)
listUpdate()
}
return ( return (
<ul className="mt-3 flex flex-col"> <ul className="mt-3 flex flex-col">
{tasklist.map((task) => ( {tasks.map((task) => (
<Item key={task.title} task={task} /> <Item key={Object.values(task)[0]} taskDetail={task} taskUpdate={taskUpdate} />
))} ))}
</ul> </ul>
); );

View File

@ -0,0 +1,5 @@
import { tasklistPersist } from "utils/config/api-response";
export default async function handler(req, res) {
res.send(await tasklistPersist(req.body));
}

View File

@ -19,7 +19,7 @@ import { getSettings } from "utils/config/config";
import { ColorContext } from "utils/contexts/color"; import { ColorContext } from "utils/contexts/color";
import { ThemeContext } from "utils/contexts/theme"; import { ThemeContext } from "utils/contexts/theme";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
import { bookmarksResponse, servicesResponse, widgetsResponse } from "utils/config/api-response"; import { bookmarksResponse, servicesResponse, tasklistResponse, widgetsResponse } from "utils/config/api-response";
import ErrorBoundary from "components/errorboundry"; import ErrorBoundary from "components/errorboundry";
import themes from "utils/styles/themes"; import themes from "utils/styles/themes";
import QuickLaunch from "components/quicklaunch"; import QuickLaunch from "components/quicklaunch";
@ -46,6 +46,7 @@ export async function getStaticProps() {
const { providers, ...settings } = getSettings(); const { providers, ...settings } = getSettings();
const services = await servicesResponse(); const services = await servicesResponse();
const tasklist = await tasklistResponse();
const bookmarks = await bookmarksResponse(); const bookmarks = await bookmarksResponse();
const widgets = await widgetsResponse(); const widgets = await widgetsResponse();
@ -54,6 +55,7 @@ export async function getStaticProps() {
initialSettings: settings, initialSettings: settings,
fallback: { fallback: {
"/api/services": services, "/api/services": services,
"/api/tasklist": tasklist,
"/api/bookmarks": bookmarks, "/api/bookmarks": bookmarks,
"/api/widgets": widgets, "/api/widgets": widgets,
"/api/hash": false, "/api/hash": false,
@ -70,6 +72,7 @@ export async function getStaticProps() {
initialSettings: {}, initialSettings: {},
fallback: { fallback: {
"/api/services": [], "/api/services": [],
"/api/tasklist": [],
"/api/bookmarks": [], "/api/bookmarks": [],
"/api/widgets": [], "/api/widgets": [],
"/api/hash": false, "/api/hash": false,
@ -174,8 +177,8 @@ function Home({ initialSettings }) {
}, [initialSettings, setSettings]); }, [initialSettings, setSettings]);
const { data: services } = useSWR("/api/services"); const { data: services } = useSWR("/api/services");
const { data: bookmarks } = useSWR("/api/bookmarks");
const { data: tasklist } = useSWR("/api/tasklist"); const { data: tasklist } = useSWR("/api/tasklist");
const { data: bookmarks } = useSWR("/api/bookmarks");
const { data: widgets } = useSWR("/api/widgets"); const { data: widgets } = useSWR("/api/widgets");
const servicesAndBookmarks = [...services.map(sg => sg.services).flat(), ...bookmarks.map(bg => bg.bookmarks).flat()] const servicesAndBookmarks = [...services.map(sg => sg.services).flat(), ...bookmarks.map(bg => bg.bookmarks).flat()]
@ -229,6 +232,11 @@ function Home({ initialSettings }) {
document.removeEventListener('keydown', handleKeyDown); document.removeEventListener('keydown', handleKeyDown);
} }
}) })
const [taskList, setTaskList] = useState(tasklist)
const taskListUpdate = () => {
setTaskList(taskList)
fetch("/api/tasklistSave", {method: "POST", body: JSON.stringify(taskList)})
}
return ( return (
<> <>
@ -296,10 +304,10 @@ function Home({ initialSettings }) {
</div> </div>
)} )}
{tasklist?.length > 0 && ( {taskList?.length > 0 && (
<div className={`grow flex flex-wrap pt-0 p-4 sm:p-8 gap-2 grid-cols-1 lg:grid-cols-2 lg:grid-cols-${Math.min(6, tasklist.length)}`}> <div className={`grow flex flex-wrap pt-0 p-4 sm:p-8 gap-2 grid-cols-1 lg:grid-cols-2 lg:grid-cols-${Math.min(6, taskList.length)}`}>
{tasklist.map((group) => ( {taskList.map((group) => (
<TasklistGroup key={group.name} group={group} /> <TasklistGroup key={Object.keys(group)[0]} groupDetail={group} groupUpdate={taskListUpdate} />
))} ))}
</div> </div>
)} )}

View File

@ -54,19 +54,13 @@ export async function tasklistResponse() {
const fileContents = substituteEnvironmentVars(rawFileContents); const fileContents = substituteEnvironmentVars(rawFileContents);
const tasklist = yaml.load(fileContents); const tasklist = yaml.load(fileContents);
if (!tasklist) return []; return tasklist
}
// map easy to write YAML objects into easy to consume JS arrays export async function tasklistPersist(taskState) {
const tasklistArray = tasklist.map((group) => ({ const tasklistYaml = path.join(process.cwd(), "config", "tasklist.yaml");
name: Object.keys(group)[0], await fs.writeFile(tasklistYaml, yaml.dump(JSON.parse(taskState)));
tasklist: group[Object.keys(group)[0]].map((entries) => ({ return [taskState];
// id: Object.values(entries)[0].replaceAll(" ", "_"),
title: Object.values(entries)[0],
checked: Object.values(entries)[1],
})),
}));
return tasklistArray;
} }
export async function widgetsResponse() { export async function widgetsResponse() {