diff --git a/src/components/AppShelf/AddAppShelfItem.tsx b/src/components/AppShelf/AddAppShelfItem.tsx index 1106bb0db..f9229d220 100644 --- a/src/components/AppShelf/AddAppShelfItem.tsx +++ b/src/components/AppShelf/AddAppShelfItem.tsx @@ -12,6 +12,10 @@ import { Title, Anchor, Text, + Tabs, + MultiSelect, + ScrollArea, + Switch, } from '@mantine/core'; import { useForm } from '@mantine/form'; import { useEffect, useState } from 'react'; @@ -19,7 +23,7 @@ import { IconApps as Apps } from '@tabler/icons'; import { v4 as uuidv4 } from 'uuid'; import { useDebouncedValue } from '@mantine/hooks'; import { useConfig } from '../../tools/state'; -import { ServiceTypeList } from '../../tools/types'; +import { ServiceTypeList, StatusCodes } from '../../tools/types'; export function AddItemShelfButton(props: any) { const [opened, setOpened] = useState(false); @@ -113,6 +117,8 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & username: props.username ?? (undefined as unknown as string), password: props.password ?? (undefined as unknown as string), openedUrl: props.openedUrl ?? (undefined as unknown as string), + status: props.status ?? ['200'], + newTab: props.newTab ?? true, }, validate: { apiKey: () => null, @@ -133,6 +139,12 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & } return null; }, + status: (value: string[]) => { + if (!value.length) { + return 'Please select a status code'; + } + return null; + }, }, }); @@ -167,6 +179,12 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
{ + if (JSON.stringify(form.values.status) === JSON.stringify(['200'])) { + form.values.status = undefined; + } + if (form.values.newTab === true) { + form.values.newTab = undefined; + } // If service already exists, update it. if (config.services && config.services.find((s) => s.id === form.values.id)) { setConfig({ @@ -191,117 +209,167 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & form.reset(); })} > - - + + + + + - - - - { - e.preventDefault(); - }} - getCreateLabel={(query) => `+ Create "${query}"`} - onCreate={(query) => {}} - {...form.getInputProps('category')} - /> - - {(form.values.type === 'Sonarr' || - form.values.type === 'Radarr' || - form.values.type === 'Lidarr' || - form.values.type === 'Readarr') && ( - <> - + + + { + e.preventDefault(); + }} + getCreateLabel={(query) => `+ Create "${query}"`} + onCreate={(query) => {}} + {...form.getInputProps('category')} + /> + + {(form.values.type === 'Sonarr' || + form.values.type === 'Radarr' || + form.values.type === 'Lidarr' || + form.values.type === 'Readarr') && ( + <> + { + form.setFieldValue('apiKey', event.currentTarget.value); + }} + error={form.errors.apiKey && 'Invalid API key'} + /> + + Tip: Get your API key{' '} + + here. + + + + )} + {form.values.type === 'qBittorrent' && ( + <> + { + form.setFieldValue('username', event.currentTarget.value); + }} + error={form.errors.username && 'Invalid username'} + /> + { + form.setFieldValue('password', event.currentTarget.value); + }} + error={form.errors.password && 'Invalid password'} + /> + + )} + {(form.values.type === 'Deluge' || + form.values.type === 'Transmission' || + form.values.type === 'qBittorrent') && ( + <> + { + form.setFieldValue('username', event.currentTarget.value); + }} + error={form.errors.username && 'Invalid username'} + /> + { + form.setFieldValue('password', event.currentTarget.value); + }} + error={form.errors.password && 'Invalid password'} + /> + + )} + + + + + + { - form.setFieldValue('apiKey', event.currentTarget.value); - }} - error={form.errors.apiKey && 'Invalid API key'} + label="HTTP Status Codes" + data={StatusCodes} + placeholder="Select valid status codes" + clearButtonLabel="Clear selection" + nothingFound="Nothing found" + defaultValue={['200']} + clearable + searchable + {...form.getInputProps('status')} /> - - Tip: Get your API key{' '} - - here. - - - - )} - {(form.values.type === 'Deluge' || - form.values.type === 'Transmission' || - form.values.type === 'qBittorrent') && ( - <> - { - form.setFieldValue('username', event.currentTarget.value); - }} - error={form.errors.username && 'Invalid username'} + - { - form.setFieldValue('password', event.currentTarget.value); - }} - error={form.errors.password && 'Invalid password'} - /> - - )} - - + + + diff --git a/src/components/AppShelf/AppShelfItem.tsx b/src/components/AppShelf/AppShelfItem.tsx index ea8fb4fce..109b873c2 100644 --- a/src/components/AppShelf/AppShelfItem.tsx +++ b/src/components/AppShelf/AppShelfItem.tsx @@ -83,7 +83,7 @@ export function AppShelfItem(props: any) { > @@ -127,13 +127,14 @@ export function AppShelfItem(props: any) { src={service.icon} fit="contain" onClick={() => { - if (service.openedUrl) window.open(service.openedUrl, '_blank'); - else window.open(service.url); + if (service.openedUrl) { + window.open(service.openedUrl, service.newTab === false ? '_top' : '_blank'); + } else window.open(service.url, service.newTab === false ? '_top' : '_blank'); }} /> - + diff --git a/src/components/AppShelf/AppShelfMenu.tsx b/src/components/AppShelf/AppShelfMenu.tsx index 824b9ae7a..5aada187a 100644 --- a/src/components/AppShelf/AppShelfMenu.tsx +++ b/src/components/AppShelf/AppShelfMenu.tsx @@ -22,16 +22,7 @@ export default function AppShelfMenu(props: any) { > diff --git a/src/components/modules/ping/PingModule.story.tsx b/src/components/modules/ping/PingModule.story.tsx index 52a832da5..1a9fefbf3 100644 --- a/src/components/modules/ping/PingModule.story.tsx +++ b/src/components/modules/ping/PingModule.story.tsx @@ -11,6 +11,8 @@ const service: serviceItem = { name: 'YouTube', icon: 'https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/youtube.png', url: 'https://youtube.com/', + status: ['200'], + target: "_blank", }; export const Default = (args: any) => ; diff --git a/src/components/modules/ping/PingModule.tsx b/src/components/modules/ping/PingModule.tsx index c7586f538..b77d8c2fd 100644 --- a/src/components/modules/ping/PingModule.tsx +++ b/src/components/modules/ping/PingModule.tsx @@ -1,5 +1,5 @@ import { Indicator, Tooltip } from '@mantine/core'; -import axios from 'axios'; +import axios, { AxiosResponse } from 'axios'; import { motion } from 'framer-motion'; import { useEffect, useState } from 'react'; import { IconPlug as Plug } from '@tabler/icons'; @@ -19,18 +19,37 @@ export default function PingComponent(props: any) { const { url }: { url: string } = props; const [isOnline, setOnline] = useState('loading'); + const [response, setResponse] = useState(500); const exists = config.modules?.[PingModule.title]?.enabled ?? false; + + function statusCheck(response: AxiosResponse) { + const { status }: {status: string[]} = props; + //Default Status + let acceptableStatus = ['200']; + if (status !== undefined && status.length) { + acceptableStatus = status; + } + // Checks if reported status is in acceptable status array + if (acceptableStatus.indexOf((response.status).toString()) >= 0) { + setOnline('online'); + setResponse(response.status); + } else { + setOnline('down'); + setResponse(response.status) + } + } + useEffect(() => { if (!exists) { return; } axios .get('/api/modules/ping', { params: { url } }) - .then(() => { - setOnline('online'); + .then((response) => { + statusCheck(response); }) - .catch(() => { - setOnline('down'); + .catch((error) => { + statusCheck(error.response); }); }, [config.modules?.[PingModule.title]?.enabled]); if (!exists) { @@ -40,7 +59,7 @@ export default function PingComponent(props: any) { { - res.status(200).json(response.data); + res.status(response.status).json(response.statusText); }) .catch((error) => { - res.status(500).json(error); + if (error.response) { + res.status(error.response.status).json(error.response.statusText); + } else { + res.status(500).json('Server Error'); + } }); // // Make a request to the URL // const response = await axios.get(url); diff --git a/src/tools/types.ts b/src/tools/types.ts index 92d5345ac..1b3953a1f 100644 --- a/src/tools/types.ts +++ b/src/tools/types.ts @@ -31,6 +31,32 @@ interface ConfigModule { }; } +export const StatusCodes = [ + {value: '200', label: '200 - OK', group:'Sucessful responses'}, + {value: '204', label: '204 - No Content', group:'Sucessful responses'}, + {value: '301', label: '301 - Moved Permanently', group:'Redirection responses'}, + {value: '302', label: '302 - Found / Moved Temporarily', group:'Redirection responses'}, + {value: '304', label: '304 - Not Modified', group:'Redirection responses'}, + {value: '307', label: '307 - Temporary Redirect', group:'Redirection responses'}, + {value: '308', label: '308 - Permanent Redirect', group:'Redirection responses'}, + {value: '400', label: '400 - Bad Request', group:'Client error responses'}, + {value: '401', label: '401 - Unauthorized', group:'Client error responses'}, + {value: '403', label: '403 - Forbidden', group:'Client error responses'}, + {value: '404', label: '404 - Not Found', group:'Client error responses'}, + {value: '408', label: '408 - Request Timeout', group:'Client error responses'}, + {value: '410', label: '410 - Gone', group:'Client error responses'}, + {value: '429', label: '429 - Too Many Requests', group:'Client error responses'}, + {value: '500', label: '500 - Internal Server Error', group:'Server error responses'}, + {value: '502', label: '502 - Bad Gateway', group:'Server error responses'}, + {value: '503', label: '503 - Service Unavailable', group:'Server error responses'}, + {value: '054', label: '504 - Gateway Timeout Error', group:'Server error responses'}, + ]; + +export const Targets = [ + {value: '_blank', label: 'New Tab'}, + {value: '_top', label: 'Same Window'} +] + export const ServiceTypeList = [ 'Other', 'Emby', @@ -66,4 +92,6 @@ export interface serviceItem { password?: string; username?: string; openedUrl?: string; + newTab?: boolean; + status?: string[]; }