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;
}