This commit is contained in:
ajnart
2022-12-20 11:45:33 +09:00
parent 79d7042cd9
commit 4d6e6123e1
32 changed files with 74 additions and 125 deletions

View File

@@ -50,8 +50,8 @@ export const AboutModal = ({ opened, closeModal }: AboutModalProps) => {
> >
<Text mb="lg"> <Text mb="lg">
Homarr is a simple and modern homepage for your server that helps you access all of your Homarr is a simple and modern homepage for your server that helps you access all of your
apps in one place. It integrates with the apps you use to display useful information apps in one place. It integrates with the apps you use to display useful information or
or control them. It&apos;s easy to install and supports many different devices. control them. It&apos;s easy to install and supports many different devices.
</Text> </Text>
<Title order={6} mb="xs" align="center"> <Title order={6} mb="xs" align="center">

View File

@@ -12,7 +12,6 @@ import {
import { arrayMove, SortableContext } from '@dnd-kit/sortable'; import { arrayMove, SortableContext } from '@dnd-kit/sortable';
import { useLocalStorage } from '@mantine/hooks'; import { useLocalStorage } from '@mantine/hooks';
import { useTranslation } from 'next-i18next';
import * as Modules from '../../modules'; import * as Modules from '../../modules';
import { useConfig } from '../../tools/state'; import { useConfig } from '../../tools/state';

View File

@@ -47,11 +47,9 @@ export default function ConfigChanger() {
); );
} }
const useConfigsQuery = () => { const useConfigsQuery = () => useQuery({
return useQuery({
queryKey: ['config/get-all'], queryKey: ['config/get-all'],
queryFn: fetchConfigs, queryFn: fetchConfigs,
}); });
};
const fetchConfigs = async () => (await (await fetch('/api/configs')).json()) as string[]; const fetchConfigs = async () => (await (await fetch('/api/configs')).json()) as string[];

View File

@@ -3,8 +3,6 @@ import { DashboardDetailView } from './Views/DetailView';
import { DashboardEditView } from './Views/EditView'; import { DashboardEditView } from './Views/EditView';
import { useEditModeStore } from './Views/useEditModeStore'; import { useEditModeStore } from './Views/useEditModeStore';
interface DashboardProps {}
export const Dashboard = () => { export const Dashboard = () => {
const isEditMode = useEditModeStore((x) => x.enabled); const isEditMode = useEditModeStore((x) => x.enabled);

View File

@@ -10,8 +10,7 @@ interface MobileRibbonSidebarDrawerProps {
export const MobileRibbonSidebarDrawer = ({ export const MobileRibbonSidebarDrawer = ({
location, location,
...props ...props
}: MobileRibbonSidebarDrawerProps) => { }: MobileRibbonSidebarDrawerProps) => (
return (
<Drawer <Drawer
position={location} position={location}
title={<Title order={4}>{location} sidebar</Title>} title={<Title order={4}>{location} sidebar</Title>}
@@ -24,4 +23,3 @@ export const MobileRibbonSidebarDrawer = ({
<DashboardSidebar location={location} /> <DashboardSidebar location={location} />
</Drawer> </Drawer>
); );
};

View File

@@ -22,7 +22,7 @@ export const ChangeWidgetPositionModal = ({
updateConfig( updateConfig(
configName, configName,
(prev) => { (prev) => {
let currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId); const currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId);
currentWidget!.shape = { currentWidget!.shape = {
location: { location: {
x, x,

View File

@@ -29,11 +29,7 @@ interface IconSelectorProps {
allowAppNamePropagation: boolean; allowAppNamePropagation: boolean;
} }
export const IconSelector = ({ export const IconSelector = ({ onChange, allowAppNamePropagation, form }: IconSelectorProps) => {
onChange,
allowAppNamePropagation,
form,
}: IconSelectorProps) => {
const { data, isLoading } = useRepositoryIconsQuery<WalkxcodeRepositoryIcon>({ const { data, isLoading } = useRepositoryIconsQuery<WalkxcodeRepositoryIcon>({
url: 'https://api.github.com/repos/walkxcode/Dashboard-Icons/contents/png', url: 'https://api.github.com/repos/walkxcode/Dashboard-Icons/contents/png',
converter: (item) => ({ converter: (item) => ({

View File

@@ -1,6 +1,5 @@
import { Tabs, TextInput, Switch, Text } from '@mantine/core'; import { Tabs, Switch } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form'; import { UseFormReturnType } from '@mantine/form';
import { IconClick } from '@tabler/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { AppType } from '../../../../../../types/app'; import { AppType } from '../../../../../../types/app';

View File

@@ -31,9 +31,9 @@ export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererP
let indexInFormValue = let indexInFormValue =
form.values.integration?.properties.findIndex((p) => p.field === property) ?? -1; form.values.integration?.properties.findIndex((p) => p.field === property) ?? -1;
if (indexInFormValue === -1) { if (indexInFormValue === -1) {
const type = Object.entries(integrationFieldDefinitions).find( const { type } = Object.entries(integrationFieldDefinitions).find(
([k, v]) => k === property ([k, v]) => k === property
)![1].type; )![1];
const newProperty: AppIntegrationPropertyType = { const newProperty: AppIntegrationPropertyType = {
type, type,
field: property as IntegrationField, field: property as IntegrationField,

View File

@@ -20,12 +20,7 @@ export const IntegrationTab = ({ form }: IntegrationTabProps) => {
{hasIntegrationSelected && ( {hasIntegrationSelected && (
<> <>
<Divider <Divider label={t('integration.type.label')} labelPosition="center" mt="xl" mb="md" />
label={t('integration.type.label')}
labelPosition="center"
mt="xl"
mb="md"
/>
<Text size="sm" color="dimmed" mb="lg"> <Text size="sm" color="dimmed" mb="lg">
{t('integration.secrets.description')} {t('integration.secrets.description')}
</Text> </Text>

View File

@@ -1,6 +1 @@
export type EditAppModalTab = export type EditAppModalTab = 'general' | 'behaviour' | 'network' | 'appereance' | 'integration';
| 'general'
| 'behaviour'
| 'network'
| 'appereance'
| 'integration';

View File

@@ -21,9 +21,7 @@ export const WidgetElementType = ({ id, image, disabled, widget }: WidgetElement
if (!configName) return null; if (!configName) return null;
const getLowestWrapper = () => { const getLowestWrapper = () => config?.wrappers.sort((a, b) => a.position - b.position)[0];
return config?.wrappers.sort((a, b) => a.position - b.position)[0];
};
const handleAddition = async () => { const handleAddition = async () => {
updateConfig( updateConfig(

View File

@@ -1,4 +1,4 @@
import { Card, Center, Text, UnstyledButton } from '@mantine/core'; import { Center, Text, UnstyledButton } from '@mantine/core';
import { NextLink } from '@mantine/next'; import { NextLink } from '@mantine/next';
import { createStyles } from '@mantine/styles'; import { createStyles } from '@mantine/styles';
import { AppType } from '../../../../types/app'; import { AppType } from '../../../../types/app';

View File

@@ -1,6 +1,6 @@
import { HomarrCardWrapper } from './HomarrCardWrapper'; import { HomarrCardWrapper } from './HomarrCardWrapper';
import { BaseTileProps } from './type'; import { BaseTileProps } from './type';
export const EmptyTile = ({ className }: BaseTileProps) => { export const EmptyTile = ({ className }: BaseTileProps) => (
return <HomarrCardWrapper className={className}>Empty</HomarrCardWrapper>; <HomarrCardWrapper className={className}>Empty</HomarrCardWrapper>
}; );

View File

@@ -1,8 +1,8 @@
import Widgets from '../../../../widgets';
import { Button, Group, MultiSelect, Stack, Switch, TextInput } from '@mantine/core'; import { Button, Group, MultiSelect, Stack, Switch, TextInput } from '@mantine/core';
import { ContextModalProps } from '@mantine/modals'; import { ContextModalProps } from '@mantine/modals';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useState } from 'react'; import { useState } from 'react';
import Widgets from '../../../../widgets';
import { useConfigContext } from '../../../../config/provider'; import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store'; import { useConfigStore } from '../../../../config/store';
import { IWidget } from '../../../../widgets/widgets'; import { IWidget } from '../../../../widgets/widgets';
@@ -48,7 +48,7 @@ export const WidgetsEditModal = ({
updateConfig( updateConfig(
configName, configName,
(prev) => { (prev) => {
let currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId); const currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId);
currentWidget!.properties = moduleProperties; currentWidget!.properties = moduleProperties;
return { return {

View File

@@ -38,7 +38,7 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => {
title: null, title: null,
innerProps: { innerProps: {
widgetId: integration, widgetId: integration,
widget: widget, widget,
}, },
}); });
}; };

View File

@@ -1,5 +1,3 @@
import { DashboardView } from './DashboardView'; import { DashboardView } from './DashboardView';
export const DashboardDetailView = () => { export const DashboardDetailView = () => <DashboardView />;
return <DashboardView />;
};

View File

@@ -1,10 +1,6 @@
import { Card, Group, Title } from '@mantine/core'; import { Group, Title } from '@mantine/core';
import { CategoryType } from '../../../../types/category'; import { CategoryType } from '../../../../types/category';
import { IWidgetDefinition } from '../../../../widgets/widgets';
import { HomarrCardWrapper } from '../../Tiles/HomarrCardWrapper'; import { HomarrCardWrapper } from '../../Tiles/HomarrCardWrapper';
import { Tiles } from '../../Tiles/tilesDefinitions';
import Widgets from '../../../../widgets';
import { GridstackTileWrapper } from '../../Tiles/TileWrapper';
import { useEditModeStore } from '../../Views/useEditModeStore'; import { useEditModeStore } from '../../Views/useEditModeStore';
import { useGridstack } from '../gridstack/use-gridstack'; import { useGridstack } from '../gridstack/use-gridstack';
import { CategoryEditMenu } from './CategoryEditMenu'; import { CategoryEditMenu } from './CategoryEditMenu';

View File

@@ -1,9 +1,5 @@
import { Card } from '@mantine/core'; import { Card } from '@mantine/core';
import { RefObject } from 'react'; import { RefObject } from 'react';
import { IWidgetDefinition } from '../../../../widgets/widgets';
import { Tiles } from '../../Tiles/tilesDefinitions';
import Widgets from '../../../../widgets';
import { GridstackTileWrapper } from '../../Tiles/TileWrapper';
import { useGridstack } from '../gridstack/use-gridstack'; import { useGridstack } from '../gridstack/use-gridstack';
import { WrapperContent } from '../WrapperContent'; import { WrapperContent } from '../WrapperContent';
@@ -38,6 +34,5 @@ export const DashboardSidebar = ({ location }: DashboardSidebarProps) => {
); );
}; };
const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) => { const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) =>
return wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 64) : 2; wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 64) : 2;
};

View File

@@ -4,7 +4,6 @@ import ConfigChanger from '../../Config/ConfigChanger';
import ConfigActions from './Config/ConfigActions'; import ConfigActions from './Config/ConfigActions';
import LanguageSelect from './Language/LanguageSelect'; import LanguageSelect from './Language/LanguageSelect';
import { SearchEngineSelector } from './SearchEngine/SearchEngineSelector'; import { SearchEngineSelector } from './SearchEngine/SearchEngineSelector';
import { SearchNewTabSwitch } from './SearchNewTabSwitch';
export default function CommonSettings() { export default function CommonSettings() {
const { config } = useConfigContext(); const { config } = useConfigContext();

View File

@@ -1,6 +1,5 @@
import { import {
ActionIcon, ActionIcon,
Center,
Checkbox, Checkbox,
createStyles, createStyles,
Flex, Flex,

View File

@@ -1,7 +1,4 @@
import { ActionIcon, Title, Tooltip, Drawer, Tabs, ScrollArea } from '@mantine/core'; import { Title, Drawer, Tabs, ScrollArea } from '@mantine/core';
import { useHotkeys } from '@mantine/hooks';
import { useState } from 'react';
import { IconSettings } from '@tabler/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import CustomizationSettings from './Customization/CustomizationSettings'; import CustomizationSettings from './Customization/CustomizationSettings';

View File

@@ -60,8 +60,7 @@ export function Search() {
// Overseerr is not use anywhere else, so it makes no sense to add a standalone toggle for displaying results // Overseerr is not use anywhere else, so it makes no sense to add a standalone toggle for displaying results
const isOverseerrEnabled = false; //config?.settings.common.enabledModules.overseerr; const isOverseerrEnabled = false; //config?.settings.common.enabledModules.overseerr;
const overseerrApp = config?.apps.find( const overseerrApp = config?.apps.find(
(app) => (app) => app.integration?.type === 'overseerr' || app.integration?.type === 'jellyseerr'
app.integration?.type === 'overseerr' || app.integration?.type === 'jellyseerr'
); );
const searchEngineSettings = config?.settings.common.searchEngine; const searchEngineSettings = config?.settings.common.searchEngine;
const searchEngineUrl = !searchEngineSettings const searchEngineUrl = !searchEngineSettings

View File

@@ -1,4 +1,4 @@
import { Menu, useMantineColorScheme, useMantineTheme } from '@mantine/core'; import { Menu, useMantineColorScheme } from '@mantine/core';
import { IconMoonStars, IconSun } from '@tabler/icons'; import { IconMoonStars, IconSun } from '@tabler/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';

View File

@@ -41,8 +41,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
'lidarr', 'lidarr',
]; ];
const mediaApps = config.apps.filter( const mediaApps = config.apps.filter(
(app) => (app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
app.integration && mediaAppIntegrationTypes.includes(app.integration.type)
); );
const medias = await Promise.all( const medias = await Promise.all(

View File

@@ -3,7 +3,6 @@ import { getCookie } from 'cookies-next';
import axios from 'axios'; import axios from 'axios';
import Consola from 'consola'; import Consola from 'consola';
import { getConfig } from '../../../../tools/config/getConfig'; import { getConfig } from '../../../../tools/config/getConfig';
import { Config } from '../../../../tools/types';
import { MediaType } from '../../../../modules/overseerr/SearchResult'; import { MediaType } from '../../../../modules/overseerr/SearchResult';
async function Get(req: NextApiRequest, res: NextApiResponse) { async function Get(req: NextApiRequest, res: NextApiResponse) {

View File

@@ -2,7 +2,6 @@ import axios from 'axios';
import { getCookie } from 'cookies-next'; import { getCookie } from 'cookies-next';
import { NextApiRequest, NextApiResponse } from 'next'; import { NextApiRequest, NextApiResponse } from 'next';
import { getConfig } from '../../../../tools/config/getConfig'; import { getConfig } from '../../../../tools/config/getConfig';
import { Config } from '../../../../tools/types';
async function Get(req: NextApiRequest, res: NextApiResponse) { async function Get(req: NextApiRequest, res: NextApiResponse) {
const configName = getCookie('config-name', { req }); const configName = getCookie('config-name', { req });

View File

@@ -39,10 +39,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) {
const options = { const options = {
host: url.hostname, host: url.hostname,
port: url.port, port: url.port,
login: login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
hash:
app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
}; };
const nzbGet = NzbgetClient(options); const nzbGet = NzbgetClient(options);

View File

@@ -31,10 +31,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
const options = { const options = {
host: url.hostname, host: url.hostname,
port: url.port, port: url.port,
login: login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
hash:
app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
}; };
const nzbGet = NzbgetClient(options); const nzbGet = NzbgetClient(options);

View File

@@ -32,10 +32,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) {
const options = { const options = {
host: url.hostname, host: url.hostname,
port: url.port, port: url.port,
login: login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined,
app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
hash:
app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined,
}; };
const nzbGet = NzbgetClient(options); const nzbGet = NzbgetClient(options);

View File

@@ -10,5 +10,4 @@ export const useGetServiceByType = (...serviceTypes: ServiceType[]) => {
export const getServiceByType = (config: Config, ...serviceTypes: ServiceType[]) => export const getServiceByType = (config: Config, ...serviceTypes: ServiceType[]) =>
config.apps.filter((s) => serviceTypes.includes(s.type)); config.apps.filter((s) => serviceTypes.includes(s.type));
export const getServiceById = (config: Config, id: string) => export const getServiceById = (config: Config, id: string) => config.apps.find((s) => s.id === id);
config.apps.find((s) => s.id === id);