Merge branch 'dev' into ui/docker

This commit is contained in:
Thomas Camlong
2022-09-02 13:02:50 +02:00
committed by GitHub
345 changed files with 4226 additions and 1999 deletions

View File

@@ -10,6 +10,7 @@ import {
MultiSelect,
PasswordInput,
Select,
Space,
Stack,
Switch,
Tabs,
@@ -18,11 +19,11 @@ import {
Tooltip,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { useDebouncedValue } from '@mantine/hooks';
import { IconApps } from '@tabler/icons';
import { useTranslation } from 'next-i18next';
import { useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { useDebouncedValue } from '@mantine/hooks';
import { useTranslation } from 'next-i18next';
import { useConfig } from '../../tools/state';
import { tryMatchPort, ServiceTypeList, StatusCodes, Config } from '../../tools/types';
import Tip from '../layout/Tip';
@@ -61,7 +62,7 @@ export function AddItemShelfButton(props: any) {
function MatchIcon(name: string | undefined, form: any) {
if (name === undefined || name === '') return null;
fetch(
`https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/${name
`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${name
.replace(/\s+/g, '-')
.toLowerCase()
.replace(/^dash\.$/, 'dashdot')}.png`
@@ -118,6 +119,7 @@ export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) {
username: props.username ?? undefined,
password: props.password ?? undefined,
openedUrl: props.openedUrl ?? undefined,
ping: props.ping ?? true,
status: props.status ?? ['200'],
newTab: props.newTab ?? true,
},
@@ -186,7 +188,11 @@ export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) {
if (newForm.newTab === true) newForm.newTab = undefined;
if (newForm.openedUrl === '') newForm.openedUrl = undefined;
if (newForm.category === null) newForm.category = undefined;
if (newForm.status.length === 1 && newForm.status[0] === '200') {
if (newForm.ping === true) newForm.ping = undefined;
if (
(newForm.status.length === 1 && newForm.status[0] === '200') ||
newForm.ping === false
) {
delete newForm.status;
}
// If service already exists, update it.
@@ -220,6 +226,7 @@ export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) {
<Tabs.Tab value="Advanced Options">{t('modal.tabs.advancedOptions.title')}</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="Options">
<Space h="sm" />
<Stack>
<TextInput
required
@@ -279,7 +286,8 @@ export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) {
form.values.type === 'Lidarr' ||
form.values.type === 'Overseerr' ||
form.values.type === 'Jellyseerr' ||
form.values.type === 'Readarr') && (
form.values.type === 'Readarr' ||
form.values.type === 'Sabnzbd') && (
<>
<TextInput
required
@@ -405,20 +413,27 @@ export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) {
</Tabs.Panel>
<Tabs.Panel value="Advanced Options">
<Stack>
<MultiSelect
required
label={t('modal.tabs.advancedOptions.form.httpStatusCodes.label')}
data={StatusCodes}
placeholder={t('modal.tabs.advancedOptions.form.httpStatusCodes.placeholder')}
clearButtonLabel={t(
'modal.tabs.advancedOptions.form.httpStatusCodes.clearButtonLabel'
)}
nothingFound={t('modal.tabs.advancedOptions.form.httpStatusCodes.nothingFound')}
defaultValue={['200']}
clearable
searchable
{...form.getInputProps('status')}
<Switch
label={t('modal.tabs.advancedOptions.form.ping.label')}
defaultChecked={form.values.ping}
{...form.getInputProps('ping')}
/>
{form.values.ping && (
<MultiSelect
required
label={t('modal.tabs.advancedOptions.form.httpStatusCodes.label')}
data={StatusCodes}
placeholder={t('modal.tabs.advancedOptions.form.httpStatusCodes.placeholder')}
clearButtonLabel={t(
'modal.tabs.advancedOptions.form.httpStatusCodes.clearButtonLabel'
)}
nothingFound={t('modal.tabs.advancedOptions.form.httpStatusCodes.nothingFound')}
defaultValue={['200']}
clearable
searchable
{...form.getInputProps('status')}
/>
)}
<Switch
label={t('modal.tabs.advancedOptions.form.openServiceInNewTab.label')}
defaultChecked={form.values.newTab}

View File

@@ -1,5 +1,13 @@
import React, { useState } from 'react';
import { Accordion, Grid, Paper, Stack, useMantineColorScheme } from '@mantine/core';
import {
Accordion,
Divider,
Grid,
Paper,
Stack,
Title,
useMantineColorScheme,
} from '@mantine/core';
import {
closestCenter,
DndContext,
@@ -16,8 +24,9 @@ import { useConfig } from '../../tools/state';
import { SortableAppShelfItem, AppShelfItem } from './AppShelfItem';
import { ModuleMenu, ModuleWrapper } from '../../modules/moduleWrapper';
import { DownloadsModule } from '../../modules';
import DownloadComponent from '../../modules/downloads/DownloadsModule';
import { UsenetModule, TorrentsModule } from '../../modules';
import TorrentsComponent from '../../modules/torrents/TorrentsModule';
import { UsenetComponent } from '../../modules/usenet/UsenetModule';
const AppShelf = (props: any) => {
const { config, setConfig } = useConfig();
@@ -126,7 +135,11 @@ const AppShelf = (props: any) => {
const noCategory = config.services.filter(
(e) => e.category === undefined || e.category === null
);
const downloadEnabled = config.modules?.[DownloadsModule.id]?.enabled ?? false;
const torrentEnabled = config.modules?.[TorrentsModule.id]?.enabled ?? false;
const usenetEnabled = config.modules?.[UsenetModule.id]?.enabled ?? false;
const downloadEnabled = usenetEnabled || torrentEnabled;
// Create an item with 0: true, 1: true, 2: true... For each category
return (
// TODO: Style accordion so that the bar is transparent to the user settings
@@ -159,7 +172,6 @@ const AppShelf = (props: any) => {
<Accordion.Control>{t('accordions.downloads.text')}</Accordion.Control>
<Accordion.Panel>
<Paper
p="lg"
radius="lg"
style={{
background: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '255, 255, 255,'} \
@@ -170,8 +182,23 @@ const AppShelf = (props: any) => {
${(config.settings.appOpacity || 100) / 100}`,
}}
>
<ModuleMenu module={DownloadsModule} />
<DownloadComponent />
{torrentEnabled && (
<>
<Title size="h2">Torrents</Title>
<ModuleMenu module={TorrentsModule} />
<TorrentsComponent />
</>
)}
{usenetEnabled && (
<>
{torrentEnabled && <Divider my="sm" />}
<Title size="h2" mt={0}>
Usenet
</Title>
<ModuleMenu module={UsenetModule} />
<UsenetComponent />
</>
)}
</Paper>
</Accordion.Panel>
</Accordion.Item>
@@ -183,7 +210,8 @@ const AppShelf = (props: any) => {
return (
<Stack>
{getItems()}
<ModuleWrapper mt="xl" module={DownloadsModule} />
<ModuleWrapper mt="xl" module={TorrentsModule} />
<ModuleWrapper mt="xl" module={UsenetModule} />
</Stack>
);
};

View File

@@ -1,21 +1,21 @@
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import {
Text,
Card,
Anchor,
AspectRatio,
Card,
Center,
createStyles,
useMantineColorScheme,
Image,
Text,
useMantineColorScheme,
} from '@mantine/core';
import { motion } from 'framer-motion';
import { useState } from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { serviceItem } from '../../tools/types';
import PingComponent from '../../modules/ping/PingModule';
import AppShelfMenu from './AppShelfMenu';
import { useConfig } from '../../tools/state';
import { serviceItem } from '../../tools/types';
import AppShelfMenu from './AppShelfMenu';
const useStyles = createStyles((theme) => ({
item: {
@@ -134,7 +134,7 @@ export function AppShelfItem(props: any) {
</Anchor>
</motion.i>
</AspectRatio>
<PingComponent url={service.url} status={service.status} />
{service.ping !== false && <PingComponent url={service.url} status={service.status} />}
</Card.Section>
</Center>
</Card>

View File

@@ -1,4 +1,4 @@
import { Anchor, Avatar, Group, Text } from '@mantine/core';
import { Avatar, Group, Text } from '@mantine/core';
interface smallServiceItem {
label: string;

View File

@@ -1,4 +1,4 @@
import { TextInput, Button, Stack } from '@mantine/core';
import { TextInput, Button, Stack, Textarea } from '@mantine/core';
import { useForm } from '@mantine/form';
import { useTranslation } from 'next-i18next';
import { useConfig } from '../../tools/state';
@@ -17,6 +17,7 @@ export default function TitleChanger() {
logo: config.settings.logo,
favicon: config.settings.favicon,
background: config.settings.background,
customCSS: config.settings.customCSS,
},
});
@@ -25,6 +26,7 @@ export default function TitleChanger() {
logo?: string;
favicon?: string;
background?: string;
customCSS?: string;
}) => {
setConfig({
...config,
@@ -34,6 +36,7 @@ export default function TitleChanger() {
logo: values.logo,
favicon: values.favicon,
background: values.background,
customCSS: values.customCSS,
},
});
};
@@ -62,6 +65,12 @@ export default function TitleChanger() {
placeholder={t('background.placeholder')}
{...form.getInputProps('background')}
/>
<Textarea
minRows={5}
label={t('customCSS.label')}
placeholder={t('customCSS.placeholder')}
{...form.getInputProps('customCSS')}
/>
<Button type="submit">{t('buttons.submit')}</Button>
</Stack>
</form>

View File

@@ -12,7 +12,7 @@ export default function LanguageSwitch() {
const { t, i18n } = useTranslation('settings/general/internationalization');
const { changeLanguage } = i18n;
const configLocale = getCookie('config-locale');
const { locale, locales } = useRouter();
const { locale, locales, push } = useRouter();
const [selectedLanguage, setSelectedLanguage] = useState<string>(
(configLocale as string) ?? locale ?? 'en'
);
@@ -37,6 +37,8 @@ export default function LanguageSwitch() {
sameSite: 'strict',
});
push('/', '/', { locale: value });
showNotification({
title: 'Language changed',
message: `You changed the language to '${newLanguage.originalName}'`,
@@ -65,6 +67,14 @@ export default function LanguageSwitch() {
onChange={onChangeSelect}
value={selectedLanguage}
defaultValue={locale}
searchable
filter={(value, item) => {
const selectItems = item as unknown as { value: string, language: Language };
return (
selectItems.language.originalName.trim().includes(value.trim()) ||
selectItems.language.translatedName.trim().includes(value.trim())
);
}}
styles={{
icon: {
width: 42,

View File

@@ -34,6 +34,9 @@ export default function Layout({ children, style }: any) {
>
{children}
</main>
<style>
{cx(config.settings.customCSS)}
</style>
</AppShell>
);
}