feat: add board (#15)

* wip: Add gridstack board
* wip: Centralize board pages, Add board settings page
* fix: remove cyclic dependency and rename widget-sort to kind
* improve: Add header actions as parallel route
* feat: add item select modal, add category edit modal,
* feat: add edit item modal
* feat: add remove item modal
* wip: add category actions
* feat: add saving of board, wip: add app widget
* Merge branch 'main' into add-board
* chore: update turbo dependencies
* chore: update mantine dependencies
* chore: fix typescript errors, lint and format
* feat: add confirm modal to category removal, move items of removed category to above wrapper
* feat: remove app widget to continue in another branch
* feat: add loading spinner until board is initialized
* fix: issue with cellheight of gridstack items
* feat: add translations for board
* fix: issue with translation for settings page
* chore: address pull request feedback
This commit is contained in:
Meier Lukas
2024-02-03 22:26:12 +01:00
committed by GitHub
parent cfd1c14034
commit 9d520874f4
88 changed files with 3431 additions and 262 deletions

View File

@@ -1,46 +1,46 @@
"use client";
import type { Dispatch, SetStateAction } from "react";
import type { ManagedModal } from "mantine-modal-manager";
import { useScopedI18n } from "@homarr/translation/client";
import type { WidgetKind } from "@homarr/definitions";
import { useI18n } from "@homarr/translation/client";
import { Button, Group, Stack } from "@homarr/ui";
import type { WidgetSort } from "..";
import { widgetImports } from "..";
import { getInputForType } from "../_inputs";
import { FormProvider, useForm } from "../_inputs/form";
import type { WidgetOptionsRecordOf } from "../definition";
import type { WidgetOptionDefinition } from "../options";
import { WidgetIntegrationSelect } from "../widget-integration-select";
import type { IntegrationSelectOption } from "../widget-integration-select";
import { WidgetIntegrationSelect } from "../widget-integration-select";
export interface WidgetEditModalState {
options: Record<string, unknown>;
integrations: string[];
}
interface ModalProps<TSort extends WidgetSort> {
sort: TSort;
state: [WidgetEditModalState, Dispatch<SetStateAction<WidgetEditModalState>>];
definition: WidgetOptionsRecordOf<TSort>;
interface ModalProps<TSort extends WidgetKind> {
kind: TSort;
value: WidgetEditModalState;
onSuccessfulEdit: (value: WidgetEditModalState) => void;
integrationData: IntegrationSelectOption[];
integrationSupport: boolean;
}
export const WidgetEditModal: ManagedModal<ModalProps<WidgetSort>> = ({
export const WidgetEditModal: ManagedModal<ModalProps<WidgetKind>> = ({
actions,
innerProps,
}) => {
const t = useScopedI18n("widget.editModal");
const [value, setValue] = innerProps.state;
const t = useI18n();
const form = useForm({
initialValues: value,
initialValues: innerProps.value,
});
const { definition } = widgetImports[innerProps.kind];
return (
<form
onSubmit={form.onSubmit((v) => {
setValue(v);
innerProps.onSuccessfulEdit(v);
actions.closeModal();
})}
>
@@ -48,12 +48,12 @@ export const WidgetEditModal: ManagedModal<ModalProps<WidgetSort>> = ({
<Stack>
{innerProps.integrationSupport && (
<WidgetIntegrationSelect
label={t("integrations.label")}
label={t("item.edit.field.integrations.label")}
data={innerProps.integrationData}
{...form.getInputProps("integrations")}
/>
)}
{Object.entries(innerProps.definition).map(
{Object.entries(definition.options).map(
([key, value]: [string, WidgetOptionDefinition]) => {
const Input = getInputForType(value.type);
@@ -64,7 +64,7 @@ export const WidgetEditModal: ManagedModal<ModalProps<WidgetSort>> = ({
return (
<Input
key={key}
sort={innerProps.sort}
kind={innerProps.kind}
property={key}
options={value as never}
/>
@@ -73,10 +73,10 @@ export const WidgetEditModal: ManagedModal<ModalProps<WidgetSort>> = ({
)}
<Group justify="right">
<Button onClick={actions.closeModal} variant="subtle" color="gray">
Close
{t("common.action.cancel")}
</Button>
<Button type="submit" color="teal">
Save
{t("common.action.saveChanges")}
</Button>
</Group>
</Stack>