feat: add crud for integrations (#11)

* wip: add crud for services and integrations

* feat: remove services

* feat: move integration definitions to homarr/definitions, add temporary test connection solution without actual request

* feat: add integration count badge

* feat: add translation for integrations

* feat: add notifications and translate them

* feat: add notice to integration forms about test connection

* chore: fix ci check issues

* feat: add confirm modals for integration deletion and secret card cancellation, change ordering for list page, add name property to integrations

* refactor: move revalidate path action

* chore: fix ci check issues

* chore: install missing dependencies

* chore: fix ci check issues

* chore: address pull request feedback
This commit is contained in:
Meier Lukas
2024-01-02 17:12:26 +01:00
committed by GitHub
parent 2809e01b03
commit 367beb6759
52 changed files with 2164 additions and 23 deletions

View File

@@ -0,0 +1 @@
export * from "./src";

View File

@@ -0,0 +1,38 @@
{
"name": "@homarr/definitions",
"private": true,
"version": "0.1.0",
"exports": {
".": "./index.ts"
},
"typesVersions": {
"*": {
"*": [
"src/*"
]
}
},
"license": "MIT",
"scripts": {
"clean": "rm -rf .turbo node_modules",
"lint": "eslint .",
"format": "prettier --check . --ignore-path ../../.gitignore",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^8.53.0",
"typescript": "^5.3.3"
},
"eslintConfig": {
"extends": [
"@homarr/eslint-config/base"
]
},
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/common": "workspace:^0.1.0"
}
}

View File

@@ -0,0 +1 @@
export * from "./integration";

View File

@@ -0,0 +1,155 @@
import { objectKeys } from "@homarr/common";
export const integrationSecretKindObject = {
apiKey: { isPublic: false },
username: { isPublic: true },
password: { isPublic: false },
} satisfies Record<string, { isPublic: boolean }>;
export const integrationSecretKinds = objectKeys(integrationSecretKindObject);
export const integrationDefs = {
sabNzbd: {
name: "SABnzbd",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sabnzbd.png",
category: ["useNetClient"],
},
nzbGet: {
name: "NZBGet",
secretKinds: ["username", "password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/nzbget.png",
category: ["useNetClient"],
},
deluge: {
name: "Deluge",
secretKinds: ["password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/deluge.png",
category: ["downloadClient"],
},
transmission: {
name: "Transmission",
secretKinds: ["username", "password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/transmission.png",
category: ["downloadClient"],
},
qBittorrent: {
name: "qBittorrent",
secretKinds: ["username", "password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/qbittorrent.png",
category: ["downloadClient"],
},
sonarr: {
name: "Sonarr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sonarr.png",
category: ["calendar"],
},
radarr: {
name: "Radarr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/radarr.png",
category: ["calendar"],
},
lidarr: {
name: "Lidarr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/lidarr.png",
category: ["calendar"],
},
readarr: {
name: "Readarr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png",
category: ["calendar"],
},
jellyfin: {
name: "Jellyfin",
secretKinds: ["username", "password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyfin.png",
category: ["mediaService"],
},
plex: {
name: "Plex",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/plex.png",
category: ["mediaService"],
},
jellyseerr: {
name: "Jellyseerr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png",
category: ["mediaSearch", "mediaRequest"],
},
overseerr: {
name: "Overseerr",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/overseerr.png",
category: ["mediaSearch", "mediaRequest"],
},
piHole: {
name: "Pi-hole",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/pi-hole.png",
category: ["dnsHole"],
},
adGuardHome: {
name: "AdGuard Home",
secretKinds: ["username", "password"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png",
category: ["dnsHole"],
},
homeAssistant: {
name: "Home Assistant",
secretKinds: ["apiKey"],
iconUrl:
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png",
category: [],
},
} satisfies Record<
string,
{
name: string;
iconUrl: string;
secretKinds: IntegrationSecretKind[];
category: IntegrationCategory[];
}
>;
export const getIconUrl = (integration: IntegrationKind) =>
integrationDefs[integration]?.iconUrl ?? null;
export const getIntegrationName = (integration: IntegrationKind) =>
integrationDefs[integration].name;
export const getSecretKinds = (
integration: IntegrationKind,
): IntegrationSecretKind[] => integrationDefs[integration]?.secretKinds ?? null;
export const integrationKinds = objectKeys(integrationDefs);
export type IntegrationSecretKind = (typeof integrationSecretKinds)[number];
export type IntegrationKind = (typeof integrationKinds)[number];
export type IntegrationCategory =
| "dnsHole"
| "mediaService"
| "calendar"
| "mediaSearch"
| "mediaRequest"
| "downloadClient"
| "useNetClient";

View File

@@ -0,0 +1,8 @@
{
"extends": "@homarr/tsconfig/base.json",
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["*.ts", "src"],
"exclude": ["node_modules"]
}