diff --git a/data/configs/default.json b/data/configs/default.json index 591cd3e1f..7d7dc6277 100644 --- a/data/configs/default.json +++ b/data/configs/default.json @@ -128,9 +128,9 @@ { "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a990", "name": "Donate", - "url": "https://homarr.dev/docs/community/donate", + "url": "https://ko-fi.com/ajnart", "behaviour": { - "onClickUrl": "https://homarr.dev/docs/community/donate", + "onClickUrl": "https://ko-fi.com/ajnart", "isOpeningInNewTab": true }, "network": { @@ -140,7 +140,7 @@ ] }, "appearance": { - "iconUrl": "/imgs/logo/logo.png" + "iconUrl": "https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/61e1116779fc0a9bd5bdbcc7_Frame%206.png" }, "integration": { "type": null, diff --git a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx index 6093a1abe..608000e05 100644 --- a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx @@ -62,7 +62,7 @@ export const EditAppModal = ({ }, }, behaviour: { - onClickUrl: (url: string) => { + externalUrl: (url: string) => { if (url === undefined || url.length < 1) { return null; } @@ -158,7 +158,7 @@ export const EditAppModal = ({ {t('tabs.general')} } + rightSection={} icon={} value="behaviour" > diff --git a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx index 4edaf3b37..0cf437e02 100644 --- a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx @@ -35,7 +35,7 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { required {...form.getInputProps('url')} onChange={(e) => { - form.setFieldValue('behaviour.onClickUrl', e.target.value); + form.setFieldValue('behaviour.externalUrl', e.target.value); form.setFieldValue('url', e.target.value); }} /> @@ -46,7 +46,7 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { placeholder="https://homarr.mywebsite.com/" variant="default" mb="md" - {...form.getInputProps('behaviour.onClickUrl')} + {...form.getInputProps('behaviour.externalUrl')} /> ); diff --git a/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx b/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx index bdfb9b520..f74fbccb7 100644 --- a/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx +++ b/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx @@ -43,7 +43,7 @@ export const AvailableElementTypes = ({ }, behaviour: { isOpeningNewTab: true, - onClickUrl: '', + externalUrl: '', }, area: { type: 'sidebar', diff --git a/src/components/Dashboard/Wrappers/WrapperContent.tsx b/src/components/Dashboard/Wrappers/WrapperContent.tsx index bfc813f57..2a4dfa8dd 100644 --- a/src/components/Dashboard/Wrappers/WrapperContent.tsx +++ b/src/components/Dashboard/Wrappers/WrapperContent.tsx @@ -18,45 +18,47 @@ interface WrapperContentProps { }; } -export const WrapperContent = ({ apps, refs, widgets }: WrapperContentProps) => ( - <> - {apps?.map((app) => { - const { component: TileComponent, ...tile } = Tiles.app; - return ( - - - - ); - })} - {widgets.map((widget) => { - const definition = Widgets[widget.id as keyof typeof Widgets] as - | IWidgetDefinition - | undefined; - if (!definition) return null; +export function WrapperContent({ apps, refs, widgets }: WrapperContentProps) { + return ( + <> + {apps?.map((app) => { + const { component: TileComponent, ...tile } = Tiles.app; + return ( + + + + ); + })} + {widgets.map((widget) => { + const definition = Widgets[widget.id as keyof typeof Widgets] as + | IWidgetDefinition + | undefined; + if (!definition) return null; - return ( - - - - - - ); - })} - -); + return ( + + + + + + ); + })} + + ); +} diff --git a/src/components/layout/header/Search.tsx b/src/components/layout/header/Search.tsx index bbc46d865..e505cac06 100644 --- a/src/components/layout/header/Search.tsx +++ b/src/components/layout/header/Search.tsx @@ -119,7 +119,7 @@ export function Search() { label: app.name, value: app.name, icon: app.appearance.iconUrl, - url: app.behaviour.onClickUrl ?? app.url, + url: app.behaviour.externalUrl ?? app.url, })); const AutoCompleteItem = forwardRef( ({ label, value, icon, url, ...others }: any, ref) => ( diff --git a/src/modules/docker/ContainerActionBar.tsx b/src/modules/docker/ContainerActionBar.tsx index cbccb13bb..5e385c4c6 100644 --- a/src/modules/docker/ContainerActionBar.tsx +++ b/src/modules/docker/ContainerActionBar.tsx @@ -179,7 +179,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction }, behaviour: { isOpeningNewTab: true, - onClickUrl: '', + externalUrl: '', }, area: { type: 'wrapper', // TODO: Set the wrapper automatically diff --git a/src/tools/config/getConfig.ts b/src/tools/config/getConfig.ts index bdd584f42..a59cefb97 100644 --- a/src/tools/config/getConfig.ts +++ b/src/tools/config/getConfig.ts @@ -1,9 +1,18 @@ -import { BackendConfigType, ConfigType } from '../../types/config'; +import { BackendConfigType } from '../../types/config'; import { configExists } from './configExists'; import { getFallbackConfig } from './getFallbackConfig'; +import { migrateConfig } from './migrateConfig'; import { readConfig } from './readConfig'; export const getConfig = (name: string): BackendConfigType => { if (!configExists(name)) return getFallbackConfig(); - return readConfig(name); + // Else if config exists but contains no "schema_version" property + // then it is an old config file and we should try to migrate it + // to the new format. + let config = readConfig(name); + if (!config.schemaVersion) { + // TODO: Migrate config to new format + config = migrateConfig(config); + } + return config; }; diff --git a/src/tools/config/migrateConfig.ts b/src/tools/config/migrateConfig.ts new file mode 100644 index 000000000..6ecf89c2e --- /dev/null +++ b/src/tools/config/migrateConfig.ts @@ -0,0 +1,81 @@ +import { ConfigType } from '../../types/config'; +import { Config } from '../types'; + +export function migrateConfig(config: Config): ConfigType { + const newConfig: ConfigType = { + schemaVersion: '1.0.0', + configProperties: { + name: config.name ?? 'default', + }, + categories: [], + widgets: [], + apps: [], + settings: { + common: { + searchEngine: { + type: 'google', + properties: { + enabled: true, + openInNewTab: true, + }, + }, + defaultConfig: 'default', + }, + customization: { + colors: {}, + layout: { + enabledDocker: false, + enabledLeftSidebar: false, + enabledPing: false, + enabledRightSidebar: false, + enabledSearchbar: true, + }, + }, + }, + wrappers: [ + { + id: 'default', + position: 1, + }, + ], + }; + + newConfig.apps = config.services.map((s, idx) => ({ + name: s.name, + id: s.id, + url: s.url, + behaviour: { + isOpeningNewTab: s.newTab ?? true, + externalUrl: s.openedUrl ?? '', + }, + network: { + enabledStatusChecker: s.ping ?? true, + okStatus: s.status?.map((str) => parseInt(str, 10)) ?? [200], + }, + appearance: { + iconUrl: s.icon, + }, + integration: { + type: null, + properties: [], + }, + area: { + type: 'wrapper', + properties: { + id: 'default', + }, + }, + shape: { + location: { + x: (idx * 3) % 18, + y: Math.floor((idx / 6)) * 3, + }, + size: { + width: 3, + height: 3, + }, + }, + })); + + return newConfig; +} diff --git a/src/tools/types.ts b/src/tools/types.ts index 9408b6bda..83f5b24de 100644 --- a/src/tools/types.ts +++ b/src/tools/types.ts @@ -20,7 +20,7 @@ export interface Settings { export interface Config { name: string; - apps: serviceItem[]; + services: serviceItem[]; settings: Settings; modules: { [key: string]: ConfigModule; diff --git a/src/types/app.ts b/src/types/app.ts index ae2e780cc..4e3d193b1 100644 --- a/src/types/app.ts +++ b/src/types/app.ts @@ -16,7 +16,7 @@ export type ConfigAppType = Omit & { }; interface AppBehaviourType { - onClickUrl: string; + externalUrl: string; isOpeningNewTab: boolean; }