mirror of
https://github.com/ajnart/homarr.git
synced 2026-01-27 01:39:16 +01:00
✨ Add match by list of integrations
This commit is contained in:
@@ -22,6 +22,67 @@
|
||||
}
|
||||
],
|
||||
"apps": [
|
||||
{
|
||||
"id": "5df743d9-5cb1-457c-85d2-64ff86855652",
|
||||
"name": "Documentation",
|
||||
"url": "https://homarr.dev",
|
||||
"behaviour": {
|
||||
"onClickUrl": "https://homarr.dev",
|
||||
"externalUrl": "https://homarr.dev",
|
||||
"isOpeningNewTab": true
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"statusCodes": [
|
||||
"200"
|
||||
]
|
||||
},
|
||||
"appearance": {
|
||||
"iconUrl": "/imgs/logo/logo.png"
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"md": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"sm": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 1,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"lg": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a337",
|
||||
"name": "Discord",
|
||||
@@ -83,6 +144,76 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330",
|
||||
"name": "Contribute",
|
||||
"url": "https://github.com/ajnart/homarr",
|
||||
"behaviour": {
|
||||
"onClickUrl": "https://github.com/ajnart/homarr",
|
||||
"externalUrl": "https://github.com/ajnart/homarr",
|
||||
"isOpeningNewTab": true
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"statusCodes": []
|
||||
},
|
||||
"appearance": {
|
||||
"iconUrl": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/github.png"
|
||||
},
|
||||
"integration": {
|
||||
"type": "transmission",
|
||||
"properties": [
|
||||
{
|
||||
"field": "username",
|
||||
"type": "public",
|
||||
"value": "qwdqwd"
|
||||
},
|
||||
{
|
||||
"field": "password",
|
||||
"type": "private",
|
||||
"value": "qdwqdqw"
|
||||
}
|
||||
]
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"md": {
|
||||
"location": {
|
||||
"x": 2,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"sm": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 2
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"lg": {
|
||||
"location": {
|
||||
"x": 4,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a990",
|
||||
"name": "Donate",
|
||||
@@ -143,126 +274,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330",
|
||||
"name": "Contribute",
|
||||
"url": "https://github.com/ajnart/homarr",
|
||||
"behaviour": {
|
||||
"onClickUrl": "https://github.com/ajnart/homarr",
|
||||
"externalUrl": "https://github.com/ajnart/homarr",
|
||||
"isOpeningNewTab": true
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"statusCodes": []
|
||||
},
|
||||
"appearance": {
|
||||
"iconUrl": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/github.png"
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"md": {
|
||||
"location": {
|
||||
"x": 2,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"sm": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 2
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"lg": {
|
||||
"location": {
|
||||
"x": 4,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5df743d9-5cb1-457c-85d2-64ff86855652",
|
||||
"name": "Documentation",
|
||||
"url": "https://homarr.dev",
|
||||
"behaviour": {
|
||||
"onClickUrl": "https://homarr.dev",
|
||||
"externalUrl": "https://homarr.dev",
|
||||
"isOpeningNewTab": true
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"statusCodes": [
|
||||
"200"
|
||||
]
|
||||
},
|
||||
"appearance": {
|
||||
"iconUrl": "/imgs/logo/logo.png"
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"md": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"sm": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 1,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"lg": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"widgets": [
|
||||
@@ -362,6 +373,74 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"integrations": {
|
||||
"sonarr": [
|
||||
{
|
||||
"id": "971aa859-8570-49a1-8d34-dd5c7b3638d1",
|
||||
"url": "https://discord.com/invite/aCsmEV5RgA",
|
||||
"name": "Sonarr 4k",
|
||||
"type": "sonarr",
|
||||
"properties": [
|
||||
{
|
||||
"field": "apiKey",
|
||||
"type": "public",
|
||||
"value": "blabla"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a326",
|
||||
"url": "https://discord.com/invite/aCsmEV5RgA",
|
||||
"name": "Sonarr HD",
|
||||
"type": "sonarr",
|
||||
"properties": [
|
||||
{
|
||||
"field": "apiKey",
|
||||
"type": "private",
|
||||
"value": "blabla"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330",
|
||||
"url": "https://discord.com/invite/aCsmEV5RgA",
|
||||
"name": "Sonarr 16k",
|
||||
"type": "sonarr",
|
||||
"properties": [
|
||||
{
|
||||
"field": "apiKey",
|
||||
"type": "private",
|
||||
"value": "blabla"
|
||||
},
|
||||
{
|
||||
"field": "apiKey 2",
|
||||
"type": "private",
|
||||
"value": "blabla 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"transmission": [
|
||||
{
|
||||
"id": "test",
|
||||
"url": "https://discord.com/invite/aCsmEV5RgA",
|
||||
"name": "Transmission Porn 4k asian babes",
|
||||
"type": "transmission",
|
||||
"properties": [
|
||||
{
|
||||
"field": "username",
|
||||
"type": "public",
|
||||
"value": "qwdqwd"
|
||||
},
|
||||
{
|
||||
"field": "password",
|
||||
"type": "private",
|
||||
"value": "qdwqdqw"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"common": {
|
||||
"searchEngine": {
|
||||
@@ -378,7 +457,7 @@
|
||||
"enabledSearchbar": true
|
||||
},
|
||||
"pageTitle": "Homarr v0.12 ⭐️",
|
||||
"logoImageUrl": "/imgs/logo/logo.png",
|
||||
"logoImageUrl": "",
|
||||
"faviconUrl": "/imgs/favicon/favicon-squared.png",
|
||||
"backgroundImageUrl": "",
|
||||
"customCss": "",
|
||||
@@ -390,4 +469,4 @@
|
||||
"appOpacity": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,26 @@
|
||||
import {
|
||||
Accordion,
|
||||
Image,
|
||||
Loader,
|
||||
Menu,
|
||||
Modal,
|
||||
PasswordInput,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
rem,
|
||||
} from '@mantine/core';
|
||||
import { Form, useForm } from '@mantine/form';
|
||||
import { modals, openModal } from '@mantine/modals';
|
||||
import { UseFormReturnType, useForm } from '@mantine/form';
|
||||
import { notifications } from '@mantine/notifications';
|
||||
import { IconPlugConnected } from '@tabler/icons-react';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { getQueryKey } from '@trpc/react-query';
|
||||
import { getCookie, getCookies, setCookie } from 'cookies-next';
|
||||
import Image from 'next/image';
|
||||
import { useState } from 'react';
|
||||
import { getCookie, setCookie } from 'cookies-next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { integrationsList } from '~/components/Dashboard/Modals/EditAppModal/Tabs/IntegrationTab/Components/InputElements/IntegrationSelector';
|
||||
import {
|
||||
IntegrationOptionsRenderer,
|
||||
IntegrationOptionsRendererNoForm,
|
||||
} from '~/components/Dashboard/Modals/EditAppModal/Tabs/IntegrationTab/Components/IntegrationOptionsRenderer/IntegrationOptionsRenderer';
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { AppIntegrationType, AppType, IntegrationType } from '~/types/app';
|
||||
import { AppIntegrationType, IntegrationType } from '~/types/app';
|
||||
import { IntegrationTypeMap } from '~/types/config';
|
||||
import { api } from '~/utils/api';
|
||||
|
||||
const ModalTitle = ({ title, description }: { title: string; description: string }) => (
|
||||
@@ -84,16 +79,41 @@ export function IntegrationMenu({ integrationsModal }: { integrationsModal: any
|
||||
);
|
||||
}
|
||||
|
||||
function IntegrationDisplay({ integration }: { integration: AppIntegrationType }) {
|
||||
function IntegrationDisplay({
|
||||
integration,
|
||||
integrationIdx,
|
||||
form,
|
||||
}: {
|
||||
integration: AppIntegrationType;
|
||||
integrationIdx: number;
|
||||
form: UseFormReturnType<any>;
|
||||
}) {
|
||||
if (!integration.type) return null;
|
||||
|
||||
return (
|
||||
<Accordion.Item value={integration.id}>
|
||||
<Accordion.Control>{integration.name}</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
<IntegrationOptionsRendererNoForm
|
||||
type={integration.type}
|
||||
properties={integration.properties}
|
||||
/>
|
||||
<Stack>
|
||||
<TextInput label="url" {...form.getInputProps(`${integration.type}.${integrationIdx}.url`)} />
|
||||
{integration.properties.map((property, idx) => {
|
||||
const test = form.getInputProps(`${integration.type}.${integrationIdx}.properties.${idx}.value`);
|
||||
if (property.type === 'private')
|
||||
return (
|
||||
<PasswordInput
|
||||
label={property.field}
|
||||
{...form.getInputProps(`${integration.type}.${integrationIdx}.properties.${idx}.value`)}
|
||||
/>
|
||||
);
|
||||
else if (property.type === 'public')
|
||||
return (
|
||||
<TextInput
|
||||
label={property.field}
|
||||
{...form.getInputProps(`${integration.type}.${integrationIdx}.properties.${idx}.value`)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
);
|
||||
@@ -120,63 +140,61 @@ interface IntegrationGroupedType {
|
||||
// | 'nzbGet'
|
||||
// | 'pihole'
|
||||
// | 'adGuardHome';
|
||||
|
||||
export interface IntegrationObject {
|
||||
[key: string]: AppIntegrationType;
|
||||
}
|
||||
|
||||
export function IntegrationsAccordion() {
|
||||
const cookie = getCookie('INTEGRATIONS_PASSWORD');
|
||||
const queryClient = useQueryClient();
|
||||
const queryKey = getQueryKey(api.system.checkLogin, { password: cookie?.toString() }, 'query');
|
||||
let integrations: AppIntegrationType[] | undefined = queryClient.getQueryData(queryKey);
|
||||
let integrations: IntegrationTypeMap | undefined = queryClient.getQueryData(queryKey);
|
||||
if (!integrations) {
|
||||
integrations = [];
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fill configIntegrationList with config.integrations in the
|
||||
const configIntegrationList: IntegrationGroupedType[] = [];
|
||||
integrations.forEach((configIntegration) => {
|
||||
const existingIntegration = configIntegrationList.find(
|
||||
(integration) => integration.type === configIntegration.type
|
||||
);
|
||||
if (existingIntegration) {
|
||||
existingIntegration.integration.push(configIntegration);
|
||||
} else {
|
||||
configIntegrationList.push({
|
||||
type: configIntegration.type!,
|
||||
integration: [configIntegration],
|
||||
});
|
||||
}
|
||||
const form = useForm({
|
||||
initialValues: integrations,
|
||||
});
|
||||
// Loop over integrations item
|
||||
|
||||
return (
|
||||
<Accordion variant="separated" multiple>
|
||||
{configIntegrationList.map((configIntegration) => {
|
||||
// Match configIntegration with integrationsList
|
||||
const integration = integrationsList.find(
|
||||
(integration) => integration.value === configIntegration.type
|
||||
);
|
||||
if (!integration) {
|
||||
return null;
|
||||
}
|
||||
{Object.keys(integrations).map((item) => {
|
||||
if (!integrations) return null;
|
||||
const configIntegrations = integrations[item as keyof IntegrationTypeMap];
|
||||
console.log('CONFIG INTEGRATIONS', configIntegrations);
|
||||
const image: string | undefined = integrationsList.find(
|
||||
(i) => i.value === configIntegrations[0].type
|
||||
)?.image;
|
||||
const integration = configIntegrations[0];
|
||||
return (
|
||||
<Accordion.Item
|
||||
value={integration.label ?? integration.value}
|
||||
key={configIntegration.type}
|
||||
>
|
||||
<Accordion.Item value={integration.type ?? integration.name} key={integration.type}>
|
||||
<Accordion.Control
|
||||
icon={
|
||||
<Image
|
||||
src={integration.image}
|
||||
src={image}
|
||||
withPlaceholder
|
||||
width={24}
|
||||
height={24}
|
||||
alt={integration.label ?? integration.value}
|
||||
alt={integration.type ?? integration.name}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{integration.label ?? integration.value}
|
||||
{integration.name}
|
||||
</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
<Accordion variant="contained" radius="md" multiple>
|
||||
{configIntegration.integration.map((item) => (
|
||||
<IntegrationDisplay integration={item} />
|
||||
))}
|
||||
<Accordion variant="separated" radius="md" multiple>
|
||||
{configIntegrations.map((integration, integrationIdx) => {
|
||||
return (
|
||||
<IntegrationDisplay
|
||||
integrationIdx={integrationIdx}
|
||||
form={form}
|
||||
integration={integration}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Accordion>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
|
||||
@@ -51,6 +51,7 @@ export type IntegrationType =
|
||||
export type AppIntegrationType = {
|
||||
type: IntegrationType | null;
|
||||
id: string;
|
||||
url: string;
|
||||
name: string;
|
||||
properties: AppIntegrationPropertyType[];
|
||||
};
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { IWidget } from '../widgets/widgets';
|
||||
import { AppIntegrationType, AppType, ConfigAppType } from './app';
|
||||
import { AppIntegrationType, AppType, ConfigAppType, IntegrationType } from './app';
|
||||
import { CategoryType } from './category';
|
||||
import { SettingsType } from './settings';
|
||||
import { WrapperType } from './wrapper';
|
||||
|
||||
export type IntegrationTypeMap = {
|
||||
[key in IntegrationType]: AppIntegrationType[];
|
||||
};
|
||||
|
||||
export interface ConfigType {
|
||||
schemaVersion: number;
|
||||
configProperties: ConfigPropertiesType;
|
||||
@@ -12,7 +16,7 @@ export interface ConfigType {
|
||||
apps: AppType[];
|
||||
widgets: IWidget<string, any>[];
|
||||
settings: SettingsType;
|
||||
integrations: AppIntegrationType[]
|
||||
integrations: IntegrationTypeMap;
|
||||
}
|
||||
|
||||
export type BackendConfigType = Omit<ConfigType, 'apps'> & {
|
||||
|
||||
Reference in New Issue
Block a user