mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 23:45:48 +01:00
Merge branch 'dev' into dnd
This commit is contained in:
180
package.json
180
package.json
@@ -1,93 +1,95 @@
|
|||||||
{
|
{
|
||||||
"name": "homarr",
|
"name": "homarr",
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"private": "false",
|
"private": "false",
|
||||||
"description": "Homarr - A homepage for your server.",
|
"description": "Homarr - A homepage for your server.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ajnart/homarr"
|
"url": "https://github.com/ajnart/homarr"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"analyze": "ANALYZE=true next build",
|
"analyze": "ANALYZE=true next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"export": "next build && next export",
|
"export": "next build && next export",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"jest": "jest",
|
"jest": "jest",
|
||||||
"jest:watch": "jest --watch",
|
"jest:watch": "jest --watch",
|
||||||
"prettier:check": "prettier --check \"**/*.{ts,tsx}\"",
|
"prettier:check": "prettier --check \"**/*.{ts,tsx}\"",
|
||||||
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
|
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
|
||||||
"test": "npm run prettier:check && npm run lint && npm run typecheck && npm run jest",
|
"test": "npm run prettier:check && npm run lint && npm run typecheck && npm run jest",
|
||||||
"storybook": "start-storybook -p 7001",
|
"storybook": "start-storybook -p 7001",
|
||||||
"storybook:build": "build-storybook",
|
"storybook:build": "build-storybook",
|
||||||
"ci": "yarn test && yarn lint --fix && yarn typecheck && yarn prettier:write"
|
"ci": "yarn test && yarn lint --fix && yarn typecheck && yarn prettier:write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/core": "^6.0.1",
|
"@dnd-kit/core": "^6.0.1",
|
||||||
"@dnd-kit/sortable": "^7.0.0",
|
"@dnd-kit/sortable": "^7.0.0",
|
||||||
"@mantine/core": "^4.2.4",
|
"@mantine/core": "^4.2.4",
|
||||||
"@mantine/dates": "^4.2.4",
|
"@mantine/dates": "^4.2.4",
|
||||||
"@mantine/dropzone": "^4.2.4",
|
"@mantine/dropzone": "^4.2.4",
|
||||||
"@mantine/form": "^4.2.4",
|
"@mantine/form": "^4.2.4",
|
||||||
"@mantine/hooks": "^4.2.4",
|
"@mantine/hooks": "^4.2.4",
|
||||||
"@mantine/modals": "^4.2.4",
|
"@mantine/modals": "^4.2.4",
|
||||||
"@mantine/next": "^4.2.4",
|
"@mantine/next": "^4.2.4",
|
||||||
"@mantine/notifications": "^4.2.4",
|
"@mantine/notifications": "^4.2.4",
|
||||||
"@mantine/prism": "^4.2.4",
|
"@mantine/prism": "^4.2.4",
|
||||||
"@mantine/rte": "^4.2.4",
|
"@mantine/rte": "^4.2.4",
|
||||||
"@mantine/spotlight": "^4.2.4",
|
"@mantine/spotlight": "^4.2.4",
|
||||||
"@modulz/radix-icons": "^4.0.0",
|
"@modulz/radix-icons": "^4.0.0",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"cookies-next": "^2.0.4",
|
"cookies-next": "^2.0.4",
|
||||||
"dayjs": "^1.11.2",
|
"dayjs": "^1.11.2",
|
||||||
"framer-motion": "^6.3.1",
|
"framer-motion": "^6.3.1",
|
||||||
"js-file-download": "^0.4.12",
|
"js-file-download": "^0.4.12",
|
||||||
"next": "12.1.5-canary.4",
|
"next": "12.1.5-canary.4",
|
||||||
"prism-react-renderer": "^1.3.1",
|
"prism-react-renderer": "^1.3.1",
|
||||||
"react": "18.0.0",
|
"react": "18.0.0",
|
||||||
"react-dom": "18.0.0",
|
"react-dom": "18.0.0",
|
||||||
"tabler-icons-react": "^1.46.0"
|
"tabler-icons-react": "^1.46.0",
|
||||||
},
|
"uuid": "^8.3.2"
|
||||||
"devDependencies": {
|
},
|
||||||
"@babel/core": "^7.17.8",
|
"devDependencies": {
|
||||||
"@next/bundle-analyzer": "^12.1.4",
|
"@babel/core": "^7.17.8",
|
||||||
"@next/eslint-plugin-next": "^12.1.4",
|
"@next/bundle-analyzer": "^12.1.4",
|
||||||
"@storybook/addon-essentials": "^6.4.22",
|
"@next/eslint-plugin-next": "^12.1.4",
|
||||||
"@storybook/addon-links": "^6.4.22",
|
"@storybook/addon-essentials": "^6.4.22",
|
||||||
"@storybook/react": "^6.4.22",
|
"@storybook/addon-links": "^6.4.22",
|
||||||
"@testing-library/dom": "^8.12.0",
|
"@storybook/react": "^6.4.22",
|
||||||
"@testing-library/jest-dom": "^5.16.3",
|
"@testing-library/dom": "^8.12.0",
|
||||||
"@testing-library/react": "^13.0.0",
|
"@testing-library/jest-dom": "^5.16.3",
|
||||||
"@testing-library/user-event": "^14.0.4",
|
"@testing-library/react": "^13.0.0",
|
||||||
"@types/jest": "^27.4.1",
|
"@testing-library/user-event": "^14.0.4",
|
||||||
"@types/node": "^17.0.23",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/react": "17.0.43",
|
"@types/node": "^17.0.23",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
"@types/react": "17.0.43",
|
||||||
"@typescript-eslint/parser": "^5.16.0",
|
"@types/uuid": "^8.3.4",
|
||||||
"babel-loader": "^8.2.4",
|
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||||
"eslint": "^8.11.0",
|
"@typescript-eslint/parser": "^5.16.0",
|
||||||
"eslint-config-airbnb": "19.0.4",
|
"babel-loader": "^8.2.4",
|
||||||
"eslint-config-airbnb-typescript": "^16.1.4",
|
"eslint": "^8.11.0",
|
||||||
"eslint-config-mantine": "1.1.0",
|
"eslint-config-airbnb": "19.0.4",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-config-airbnb-typescript": "^16.1.4",
|
||||||
"eslint-plugin-jest": "^26.1.3",
|
"eslint-config-mantine": "1.1.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-jest": "^26.1.3",
|
||||||
"eslint-plugin-react-hooks": "^4.3.0",
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
"eslint-plugin-storybook": "^0.5.11",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-testing-library": "^5.2.0",
|
"eslint-plugin-react-hooks": "^4.3.0",
|
||||||
"eslint-plugin-unused-imports": "^2.0.0",
|
"eslint-plugin-storybook": "^0.5.11",
|
||||||
"jest": "^27.5.1",
|
"eslint-plugin-testing-library": "^5.2.0",
|
||||||
"prettier": "^2.6.2",
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
"storybook-addon-mock": "^2.3.2",
|
"jest": "^27.5.1",
|
||||||
"storybook-addon-turbo-build": "^1.1.0",
|
"prettier": "^2.6.2",
|
||||||
"storybook-dark-mode": "^1.0.9",
|
"storybook-addon-mock": "^2.3.2",
|
||||||
"ts-jest": "^27.1.4",
|
"storybook-addon-turbo-build": "^1.1.0",
|
||||||
"typescript": "4.6.3"
|
"storybook-dark-mode": "^1.0.9",
|
||||||
},
|
"ts-jest": "^27.1.4",
|
||||||
"resolutions": {
|
"typescript": "4.6.3"
|
||||||
"@types/react": "17.0.30"
|
},
|
||||||
}
|
"resolutions": {
|
||||||
|
"@types/react": "17.0.30"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Apps } from 'tabler-icons-react';
|
import { Apps } from 'tabler-icons-react';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { useConfig } from '../../tools/state';
|
import { useConfig } from '../../tools/state';
|
||||||
import { ServiceTypeList } from '../../tools/types';
|
import { ServiceTypeList } from '../../tools/types';
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
|
|||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
id: props.id ?? crypto.randomUUID(),
|
id: props.id ?? uuidv4(),
|
||||||
type: props.type ?? 'Other',
|
type: props.type ?? 'Other',
|
||||||
name: props.name ?? '',
|
name: props.name ?? '',
|
||||||
icon: props.icon ?? '/favicon.svg',
|
icon: props.icon ?? '/favicon.svg',
|
||||||
|
|||||||
@@ -5,34 +5,25 @@ import { useConfig } from '../../tools/state';
|
|||||||
export default function ModuleEnabler(props: any) {
|
export default function ModuleEnabler(props: any) {
|
||||||
const { config, setConfig } = useConfig();
|
const { config, setConfig } = useConfig();
|
||||||
const modules = Object.values(Modules).map((module) => module);
|
const modules = Object.values(Modules).map((module) => module);
|
||||||
const enabledModules = config.settings.enabledModules ?? [];
|
|
||||||
modules.filter((module) => enabledModules.includes(module.title));
|
|
||||||
return (
|
return (
|
||||||
<Group direction="column">
|
<Group direction="column">
|
||||||
{modules.map((module) => (
|
{modules.map((module) => (
|
||||||
<Switch
|
<Switch
|
||||||
key={module.title}
|
key={module.title}
|
||||||
size="md"
|
size="md"
|
||||||
checked={enabledModules.includes(module.title)}
|
checked={config.modules?.[module.title]?.enabled ?? false}
|
||||||
label={`Enable ${module.title} module`}
|
label={`Enable ${module.title} module`}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.currentTarget.checked) {
|
setConfig({
|
||||||
setConfig({
|
...config,
|
||||||
...config,
|
modules: {
|
||||||
settings: {
|
...config.modules,
|
||||||
...config.settings,
|
[module.title]: {
|
||||||
enabledModules: [...enabledModules, module.title],
|
...config.modules?.[module.title],
|
||||||
|
enabled: e.currentTarget.checked,
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
} else {
|
});
|
||||||
setConfig({
|
|
||||||
...config,
|
|
||||||
settings: {
|
|
||||||
...config.settings,
|
|
||||||
enabledModules: enabledModules.filter((m) => m !== module.title),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -33,22 +33,22 @@ export default function CalendarComponent(props: any) {
|
|||||||
const nextMonth = new Date(new Date().setMonth(new Date().getMonth() + 2)).toISOString();
|
const nextMonth = new Date(new Date().setMonth(new Date().getMonth() + 2)).toISOString();
|
||||||
if (sonarrService && sonarrService.apiKey) {
|
if (sonarrService && sonarrService.apiKey) {
|
||||||
const baseUrl = new URL(sonarrService.url).origin;
|
const baseUrl = new URL(sonarrService.url).origin;
|
||||||
fetch(
|
fetch(`${baseUrl}/api/calendar?apikey=${sonarrService?.apiKey}&end=${nextMonth}`).then(
|
||||||
`${baseUrl}/api/calendar?apikey=${sonarrService?.apiKey}&end=${nextMonth}`
|
(response) => {
|
||||||
).then((response) => {
|
response.ok &&
|
||||||
response.ok &&
|
response.json().then((data) => {
|
||||||
response.json().then((data) => {
|
setSonarrMedias(data);
|
||||||
setSonarrMedias(data);
|
showNotification({
|
||||||
showNotification({
|
title: 'Sonarr',
|
||||||
title: 'Sonarr',
|
icon: <Check />,
|
||||||
icon: <Check />,
|
color: 'green',
|
||||||
color: 'green',
|
autoClose: 1500,
|
||||||
autoClose: 1500,
|
radius: 'md',
|
||||||
radius: 'md',
|
message: `Loaded ${data.length} releases`,
|
||||||
message: `Loaded ${data.length} releases`,
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
if (radarrService && radarrService.apiKey) {
|
if (radarrService && radarrService.apiKey) {
|
||||||
const baseUrl = new URL(radarrService.url).origin;
|
const baseUrl = new URL(radarrService.url).origin;
|
||||||
|
|||||||
@@ -21,13 +21,8 @@ export const DateModule: IModule = {
|
|||||||
export default function DateComponent(props: any) {
|
export default function DateComponent(props: any) {
|
||||||
const [date, setDate] = useState(new Date());
|
const [date, setDate] = useState(new Date());
|
||||||
const { config } = useConfig();
|
const { config } = useConfig();
|
||||||
const hours = date.getHours();
|
const isFullTime = config?.modules?.[DateModule.title]?.options?.full?.value ?? false;
|
||||||
const minutes = date.getMinutes();
|
const formatString = isFullTime ? 'HH:mm' : 'h:mm A';
|
||||||
const isFullTime =
|
|
||||||
config.settings[`${DateModule.title}.full`] === undefined
|
|
||||||
? true
|
|
||||||
: config.settings[`${DateModule.title}.full`];
|
|
||||||
const formatString = isFullTime ? 'HH:mm' : 'h:mm a';
|
|
||||||
// Change date on minute change
|
// Change date on minute change
|
||||||
// Note: Using 10 000ms instead of 1000ms to chill a little :)
|
// Note: Using 10 000ms instead of 1000ms to chill a little :)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { IModule } from './modules';
|
|||||||
export function ModuleWrapper(props: any) {
|
export function ModuleWrapper(props: any) {
|
||||||
const { module }: { module: IModule } = props;
|
const { module }: { module: IModule } = props;
|
||||||
const { config, setConfig } = useConfig();
|
const { config, setConfig } = useConfig();
|
||||||
const enabledModules = config.settings.enabledModules ?? [];
|
const enabledModules = config.modules ?? {};
|
||||||
// Remove 'Module' from enabled modules titles
|
// Remove 'Module' from enabled modules titles
|
||||||
const isShown = enabledModules.includes(module.title);
|
const isShown = enabledModules[module.title]?.enabled ?? false;
|
||||||
const theme = useMantineTheme();
|
const theme = useMantineTheme();
|
||||||
const items: JSX.Element[] = [];
|
const items: JSX.Element[] = [];
|
||||||
if (module.options) {
|
if (module.options) {
|
||||||
@@ -18,25 +18,31 @@ export function ModuleWrapper(props: any) {
|
|||||||
// Loop over all the types with a for each loop
|
// Loop over all the types with a for each loop
|
||||||
types.forEach((type, index) => {
|
types.forEach((type, index) => {
|
||||||
const optionName = `${module.title}.${keys[index]}`;
|
const optionName = `${module.title}.${keys[index]}`;
|
||||||
|
const moduleInConfig = config.modules?.[module.title];
|
||||||
// TODO: Add support for other types
|
// TODO: Add support for other types
|
||||||
if (type === 'boolean') {
|
if (type === 'boolean') {
|
||||||
items.push(
|
items.push(
|
||||||
<Switch
|
<Switch
|
||||||
defaultChecked={
|
defaultChecked={
|
||||||
// Set default checked to the value of the option if it exists
|
// Set default checked to the value of the option if it exists
|
||||||
config.settings[optionName] ??
|
moduleInConfig?.options?.[keys[index]]?.value ?? false
|
||||||
(module.options && module.options[keys[index]].value) ??
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
defaultValue={config.settings[optionName] ?? false}
|
|
||||||
key={keys[index]}
|
key={keys[index]}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
setConfig({
|
setConfig({
|
||||||
...config,
|
...config,
|
||||||
settings: {
|
modules: {
|
||||||
...config.settings,
|
...config.modules,
|
||||||
enabledModules: [...config.settings.enabledModules],
|
[module.title]: {
|
||||||
[optionName]: e.currentTarget.checked,
|
...config.modules[module.title],
|
||||||
|
options: {
|
||||||
|
...config.modules[module.title].options,
|
||||||
|
[keys[index]]: {
|
||||||
|
...config.modules[module.title].options?.[keys[index]],
|
||||||
|
value: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@@ -46,7 +52,6 @@ export function ModuleWrapper(props: any) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Sussy baka
|
|
||||||
if (!isShown) {
|
if (!isShown) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface Option {
|
|||||||
[x: string]: OptionValues;
|
[x: string]: OptionValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OptionValues {
|
export interface OptionValues {
|
||||||
name: string;
|
name: string;
|
||||||
value: boolean;
|
value: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ export default function PingComponent(props: any) {
|
|||||||
|
|
||||||
const { url }: { url: string } = props;
|
const { url }: { url: string } = props;
|
||||||
const [isOnline, setOnline] = useState<State>('loading');
|
const [isOnline, setOnline] = useState<State>('loading');
|
||||||
|
const exists = config.modules?.[PingModule.title]?.enabled ?? false;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config.settings.enabledModules.includes('Ping Services')) {
|
if (!exists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
axios
|
axios
|
||||||
@@ -32,7 +33,7 @@ export default function PingComponent(props: any) {
|
|||||||
setOnline('down');
|
setOnline('down');
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
if (!config.settings.enabledModules.includes('Ping Services')) {
|
if (!exists) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ export default function SearchBar(props: any) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If enabled modules doesn't contain the module, return null
|
// If enabled modules doesn't contain the module, return null
|
||||||
if (!config.settings.enabledModules.includes(SearchModule.title)) {
|
// If module in enabled
|
||||||
|
|
||||||
|
const exists = config.modules?.[SearchModule.title]?.enabled ?? false;
|
||||||
|
if (!exists) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,9 +132,7 @@ export default function WeatherComponent(props: any) {
|
|||||||
const { config } = useConfig();
|
const { config } = useConfig();
|
||||||
const [weather, setWeather] = useState({} as WeatherResponse);
|
const [weather, setWeather] = useState({} as WeatherResponse);
|
||||||
const isFahrenheit: boolean =
|
const isFahrenheit: boolean =
|
||||||
config.settings[`${WeatherModule.title}.freedomunit`] === undefined
|
config?.modules?.[WeatherModule.title]?.options?.freedomunit?.value ?? false;
|
||||||
? false
|
|
||||||
: config.settings[`${WeatherModule.title}.freedomunit`];
|
|
||||||
|
|
||||||
if ('geolocation' in navigator && location.lat === 0 && location.lng === 0) {
|
if ('geolocation' in navigator && location.lat === 0 && location.lng === 0) {
|
||||||
navigator.geolocation.getCurrentPosition((position) => {
|
navigator.geolocation.getCurrentPosition((position) => {
|
||||||
@@ -163,10 +161,10 @@ export default function WeatherComponent(props: any) {
|
|||||||
<Group spacing={0}>
|
<Group spacing={0}>
|
||||||
<WeatherIcon code={weather.current_weather.weathercode} />
|
<WeatherIcon code={weather.current_weather.weathercode} />
|
||||||
<Space mx="sm" />
|
<Space mx="sm" />
|
||||||
<span>{weather.daily.temperature_2m_max[0]}°C</span>
|
<span>{usePerferedUnit(weather.daily.temperature_2m_max[0])}</span>
|
||||||
<ArrowUpRight size={16} style={{ right: 15 }} />
|
<ArrowUpRight size={16} style={{ right: 15 }} />
|
||||||
<Space mx="sm" />
|
<Space mx="sm" />
|
||||||
<span>{weather.daily.temperature_2m_min[0]}°C</span>
|
<span>{usePerferedUnit(weather.daily.temperature_2m_min[0])}</span>
|
||||||
<ArrowDownRight size={16} />
|
<ArrowDownRight size={16} />
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
config: {
|
config: {
|
||||||
name: '',
|
name: 'Default config',
|
||||||
services: [],
|
services: [],
|
||||||
settings: {
|
settings: {
|
||||||
enabledModules: [],
|
|
||||||
searchUrl: 'https://www.google.com/search?q=',
|
searchUrl: 'https://www.google.com/search?q=',
|
||||||
},
|
},
|
||||||
|
modules: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,10 +27,9 @@ export async function getServerSideProps({
|
|||||||
name: cookie.toString(),
|
name: cookie.toString(),
|
||||||
services: [],
|
services: [],
|
||||||
settings: {
|
settings: {
|
||||||
enabledModules: [],
|
|
||||||
searchBar: true,
|
|
||||||
searchUrl: 'https://www.google.com/search?q=',
|
searchUrl: 'https://www.google.com/search?q=',
|
||||||
},
|
},
|
||||||
|
modules: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
33
src/pages/tryconfig.tsx
Normal file
33
src/pages/tryconfig.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Button } from '@mantine/core';
|
||||||
|
import { Prism } from '@mantine/prism';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { DateModule } from '../components/modules';
|
||||||
|
import { useConfig } from '../tools/state';
|
||||||
|
|
||||||
|
export default function TryConfig(props: any) {
|
||||||
|
const { config } = useConfig();
|
||||||
|
const [tempConfig, setTempConfig] = useState(config);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Prism language="json">{JSON.stringify(tempConfig, null, 2)}</Prism>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setTempConfig({
|
||||||
|
...tempConfig,
|
||||||
|
modules: {
|
||||||
|
[DateModule.title]: {
|
||||||
|
enabled: true,
|
||||||
|
title: DateModule.title,
|
||||||
|
options: {
|
||||||
|
...DateModule.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add a module to the modules thingy
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,10 +17,9 @@ const configContext = createContext<configContextType>({
|
|||||||
name: 'default',
|
name: 'default',
|
||||||
services: [],
|
services: [],
|
||||||
settings: {
|
settings: {
|
||||||
searchBar: true,
|
searchUrl: 'https://google.com/search?q=',
|
||||||
searchUrl: 'https://www.google.com/search?q=',
|
|
||||||
enabledModules: [],
|
|
||||||
},
|
},
|
||||||
|
modules: {},
|
||||||
},
|
},
|
||||||
setConfig: () => {},
|
setConfig: () => {},
|
||||||
loadConfig: async (name: string) => {},
|
loadConfig: async (name: string) => {},
|
||||||
@@ -44,10 +43,9 @@ export function ConfigProvider({ children }: Props) {
|
|||||||
name: 'default',
|
name: 'default',
|
||||||
services: [],
|
services: [],
|
||||||
settings: {
|
settings: {
|
||||||
searchBar: true,
|
|
||||||
searchUrl: 'https://www.google.com/search?q=',
|
searchUrl: 'https://www.google.com/search?q=',
|
||||||
enabledModules: [],
|
|
||||||
},
|
},
|
||||||
|
modules: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
async function loadConfig(configName: string) {
|
async function loadConfig(configName: string) {
|
||||||
|
|||||||
@@ -1,32 +1,43 @@
|
|||||||
|
import { OptionValues } from '../components/modules/modules';
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
searchUrl: string;
|
searchUrl: string;
|
||||||
enabledModules: string[];
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
name: string;
|
name: string;
|
||||||
services: serviceItem[];
|
services: serviceItem[];
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
modules: {
|
||||||
|
[key: string]: ConfigModule;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConfigModule {
|
||||||
|
title: string;
|
||||||
|
enabled: boolean;
|
||||||
|
options: {
|
||||||
|
[key: string]: OptionValues;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ServiceTypeList = [
|
export const ServiceTypeList = [
|
||||||
'Other',
|
'Other',
|
||||||
'Sonarr',
|
|
||||||
'Radarr',
|
|
||||||
'Lidarr',
|
|
||||||
'qBittorrent',
|
|
||||||
'Plex',
|
|
||||||
'Emby',
|
'Emby',
|
||||||
|
'Lidarr',
|
||||||
|
'Plex',
|
||||||
|
'Radarr',
|
||||||
|
'Sonarr',
|
||||||
|
'qBittorrent',
|
||||||
];
|
];
|
||||||
export type ServiceType =
|
export type ServiceType =
|
||||||
| 'Other'
|
| 'Other'
|
||||||
| 'Sonarr'
|
| 'Emby'
|
||||||
| 'Radarr'
|
|
||||||
| 'Lidarr'
|
| 'Lidarr'
|
||||||
| 'qBittorrent'
|
|
||||||
| 'Plex'
|
| 'Plex'
|
||||||
| 'Emby';
|
| 'Radarr'
|
||||||
|
| 'Sonarr'
|
||||||
|
| 'qBittorrent';
|
||||||
|
|
||||||
export interface serviceItem {
|
export interface serviceItem {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -16,5 +16,5 @@
|
|||||||
"incremental": true
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js"],
|
||||||
"exclude": ["node_modules", "**/*.story.*"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user