Update default config

This commit is contained in:
ajnart
2022-12-24 17:18:16 +09:00
parent 3fb82a7336
commit e3d7b04059
20 changed files with 815 additions and 169 deletions

View File

@@ -20,7 +20,6 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
description={t('general.appname.description')}
placeholder="My example app"
variant="default"
mb="md"
withAsterisk
required
{...form.getInputProps('name')}
@@ -45,7 +44,7 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
description={t('general.externalAddress.description')}
placeholder="https://homarr.mywebsite.com/"
variant="default"
mb="md"
required
{...form.getInputProps('behaviour.externalUrl')}
/>
</Tabs.Panel>

View File

@@ -3,6 +3,7 @@ import { ContextModalProps } from '@mantine/modals';
import { useTranslation } from 'next-i18next';
import { useState } from 'react';
import Widgets from '../../../../widgets';
import type { IWidgetOptionValue } from '../../../../widgets/widgets';
import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store';
import { IWidget } from '../../../../widgets/widgets';
@@ -23,6 +24,8 @@ export const WidgetsEditModal = ({
const [moduleProperties, setModuleProperties] = useState(innerProps.options);
const items = Object.entries(moduleProperties ?? {}) as [string, IntegrationOptionsValueType][];
// Find the Key in the "Widgets" Object that matches the widgetId
const currentWidgetDefinition = Widgets[innerProps.widgetId as keyof typeof Widgets];
const { name: configName } = useConfigContext();
const updateConfig = useConfigStore((x) => x.updateConfig);
@@ -63,33 +66,38 @@ export const WidgetsEditModal = ({
return (
<Stack>
{items.map(([key, value]) => (
<>
{typeof value === 'boolean' ? (
<Switch
label={t(`descriptor.settings.${key}.label`)}
checked={value}
onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
/>
) : null}
{typeof value === 'string' ? (
<TextInput
label={t(`descriptor.settings.${key}.label`)}
value={value}
onChange={(ev) => handleChange(key, ev.currentTarget.value)}
/>
) : null}
{typeof value === 'object' && Array.isArray(value) ? (
<MultiSelect
data={getMutliselectData(key)}
label={t(`descriptor.settings.${key}.label`)}
value={value}
onChange={(v) => handleChange(key, v)}
/>
) : null}
</>
))}
{items.map(([key, value]) => {
const option = (currentWidgetDefinition as any).options[key] as IWidgetOptionValue;
switch (option.type) {
case 'switch':
return (
<Switch
label={t(`descriptor.settings.${key}.label`)}
checked={value as boolean}
onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
/>
);
case 'text':
return (
<TextInput
label={t(`descriptor.settings.${key}.label`)}
value={value as string}
onChange={(ev) => handleChange(key, ev.currentTarget.value)}
/>
);
case 'multi-select':
return (
<MultiSelect
data={getMutliselectData(key)}
label={t(`descriptor.settings.${key}.label`)}
value={value as string[]}
onChange={(v) => handleChange(key, v)}
/>
);
default:
return null;
}
})}
<Group position="right">
<Button onClick={() => context.closeModal(id)} variant="light">
{t('common:cancel')}
@@ -99,3 +107,41 @@ export const WidgetsEditModal = ({
</Stack>
);
};
// <Stack>
// {items.map(([key, value]) => (
// <>
// {typeof value === 'boolean' ? (
// <Switch
// label={t(`descriptor.settings.${key}.label`)}
// checked={value}
// onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
// />
// ) : null}
// {typeof value === 'string' ? (
// <TextInput
// label={t(`descriptor.settings.${key}.label`)}
// value={value}
// onChange={(ev) => handleChange(key, ev.currentTarget.value)}
// />
// ) : null}
// {typeof value === 'object' && Array.isArray(value) ? (
// <MultiSelect
// data={getMutliselectData(key)}
// label={t(`descriptor.settings.${key}.label`)}
// value={value}
// onChange={(v) => handleChange(key, v)}
// />
// ) : null}
// </>
// ))}
// <Group position="right">
// <Button onClick={() => context.closeModal(id)} variant="light">
// {t('common:cancel')}
// </Button>
// <Button onClick={handleSave}>{t('common:save')}</Button>
// </Group>
// </Stack>
// );
// };

View File

@@ -6,6 +6,7 @@ import {
IconRowInsertTop,
IconRowInsertBottom,
IconEdit,
IconTrash,
} from '@tabler/icons';
import { useConfigContext } from '../../../../config/provider';
import { CategoryType } from '../../../../types/category';
@@ -17,11 +18,11 @@ interface CategoryEditMenuProps {
export const CategoryEditMenu = ({ category }: CategoryEditMenuProps) => {
const { name: configName } = useConfigContext();
const { addCategoryAbove, addCategoryBelow, moveCategoryUp, moveCategoryDown, edit } =
const { addCategoryAbove, addCategoryBelow, moveCategoryUp, moveCategoryDown, edit, remove } =
useCategoryActions(configName, category);
return (
<Menu withinPortal>
<Menu withinPortal position="left-start" withArrow>
<Menu.Target>
<ActionIcon>
<IconDots />
@@ -31,6 +32,9 @@ export const CategoryEditMenu = ({ category }: CategoryEditMenuProps) => {
<Menu.Item icon={<IconEdit size={20} />} onClick={edit}>
Edit
</Menu.Item>
<Menu.Item icon={<IconTrash size={20} />} onClick={remove}>
Remove
</Menu.Item>
<Menu.Label>Change positon</Menu.Label>
<Menu.Item icon={<IconTransitionTop size={20} />} onClick={moveCategoryUp}>
Move up

View File

@@ -39,7 +39,7 @@ export const CategoryEditModal = ({
<TextInput data-autoFocus {...form.getInputProps('name')} label="Name of category" />
<Group mt="md" grow>
<Button onClick={() => context.closeModal(id)} variant="light" color="gray">
<Button onClick={() => context.closeModal(id)} variant="filled" color="gray">
{t('cancel')}
</Button>
<Button type="submit">{t('save')}</Button>

View File

@@ -176,6 +176,37 @@ export const useCategoryActions = (configName: string | undefined, category: Cat
);
};
// Removes the current category
const remove = () => {
if (!configName) return;
updateConfig(
configName,
(previous) => {
const currentItem = previous.categories.find((x) => x.id === category.id);
if (!currentItem) return previous;
// Find the main wrapper
const mainWrapper = previous.wrappers.find((x) => x.position === 1);
// Check that the app has an area.type or "category" and that the area.id is the current category
const appsToMove = previous.apps.filter(
(x) => x.area && x.area.type === 'category' && x.area.properties.id === currentItem.id
);
appsToMove.forEach((x) => {
// eslint-disable-next-line no-param-reassign
x.area = { type: 'wrapper', properties: { id: mainWrapper?.id ?? 'default' } };
});
return {
...previous,
apps: previous.apps,
categories: previous.categories.filter((x) => x.id !== category.id),
wrappers: previous.wrappers.filter((x) => x.position !== currentItem.position),
};
},
true
);
};
const edit = async () => {
openContextModalGeneric<CategoryEditModalInnerProps>({
modal: 'categoryEditModal',
@@ -201,6 +232,7 @@ export const useCategoryActions = (configName: string | undefined, category: Cat
addCategoryBelow,
moveCategoryUp,
moveCategoryDown,
remove,
edit,
};
};

View File

@@ -15,10 +15,8 @@ export function Logo({ size = 'md', withoutText = false }: LogoProps) {
<Group spacing={size === 'md' ? 'xs' : 4} noWrap>
<Image
width={size === 'md' ? 50 : 12}
src={config?.settings.customization.logoImageUrl || '/imgs/logo/logo.png'}
style={{
position: 'relative',
}}
src={config?.settings.customization.logoImageUrl || '/imgs/logo/logo-color.svg'}
alt="Homarr Logo"
/>
{withoutText ? null : (
<Text

View File

@@ -1,7 +1,11 @@
import { ActionIcon, Button, Popover, Text, Tooltip } from '@mantine/core';
import { IconEditCircle, IconEditCircleOff, IconX } from '@tabler/icons';
import axios from 'axios';
import Consola from 'consola';
import { getCookie } from 'cookies-next';
import { Trans, useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useConfigContext } from '../../../../../config/provider';
import { useScreenSmallerThan } from '../../../../../hooks/useScreenSmallerThan';
import { useEditModeStore } from '../../../../Dashboard/Views/useEditModeStore';
@@ -13,9 +17,18 @@ export const ToggleEditModeAction = () => {
const { t } = useTranslation('layout/header/actions/toggle-edit-mode');
const smallerThanSm = useScreenSmallerThan('sm');
const { config } = useConfigContext();
useEffect(() => {
if (enabled || config === undefined || config?.schemaVersion === undefined) return;
const configName = getCookie('config-name')?.toString() ?? 'default';
axios.put(`/api/configs/${configName}`, { ...config });
Consola.log('Saved config to server', configName);
}, [enabled]);
const toggleButtonClicked = () => {
toggleEditMode();
setPopoverManuallyHidden(false);
};