diff --git a/README.md b/README.md index 56e6bc25..37123c3b 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This is the official repository for the Tipi App Store. It contains all the apps - [gandi-livedns](https://github.com/jbbodart/gandi-livedns) - Update your Gandi DNS zone records with your WAN IP - [Ghost](https://github.com/TryGhost/Ghost) - Ghost - Turn your audience into a business - [Gitea](https://github.com/go-gitea/gitea) - Gitea - A painless self-hosted Git service +- [Gladys Assistant](https://github.com/gladysassistant/gladys) - A privacy-first, open-source home assistant - [Gotify](https://github.com/gotify/server) - Gotify - Simple server for sending and receiving notification messages - [Grafana](https://github.com/grafana/grafana) - The open and composable observability and data visualization platform - [Grav](https://github.com/getgrav/grav) - Fast, Simple, and Flexible, file-based Web-platform. diff --git a/apps/__tests__/apps.test.ts b/apps/__tests__/apps.test.ts index f6eced8c..f971f28f 100644 --- a/apps/__tests__/apps.test.ts +++ b/apps/__tests__/apps.test.ts @@ -1,5 +1,5 @@ -import fs from "fs"; -import jsyaml from "js-yaml"; +import fs from 'fs'; +import jsyaml from 'js-yaml'; interface AppConfig { id: string; @@ -18,17 +18,11 @@ interface AppConfig { available: boolean; } -const networkExceptions = [ - "pihole", - "tailscale", - "homeassistant", - "plex", - "zerotier", -]; +const networkExceptions = ['pihole', 'tailscale', 'homeassistant', 'plex', 'zerotier', 'gladys']; const getAppConfigs = (): AppConfig[] => { const apps: AppConfig[] = []; - const appsDir = fs.readdirSync("./apps"); + const appsDir = fs.readdirSync('./apps'); appsDir.forEach((app: string) => { const path = `./apps/${app}/config.json`; @@ -42,7 +36,7 @@ const getAppConfigs = (): AppConfig[] => { apps.push(config); } } catch (e) { - console.error("Error parsing config file", app); + console.error('Error parsing config file', app); } } }); @@ -50,14 +44,14 @@ const getAppConfigs = (): AppConfig[] => { return apps; }; -describe("App configs", () => { - it("Get app config should return at least one app", () => { +describe('App configs', () => { + it('Get app config should return at least one app', () => { const apps = getAppConfigs(); expect(apps.length).toBeGreaterThan(0); }); - it("Each app should have an id", () => { + it('Each app should have an id', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -65,7 +59,7 @@ describe("App configs", () => { }); }); - it("Each app should have a md description", () => { + it('Each app should have a md description', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -81,7 +75,7 @@ describe("App configs", () => { }); }); - it("Each app should have categories defined as an array", () => { + it('Each app should have categories defined as an array', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -90,7 +84,7 @@ describe("App configs", () => { }); }); - it("Each app should have a name", () => { + it('Each app should have a name', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -98,7 +92,7 @@ describe("App configs", () => { }); }); - it("Each app should have a description", () => { + it('Each app should have a description', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -106,7 +100,7 @@ describe("App configs", () => { }); }); - it("Each app should have a port", () => { + it('Each app should have a port', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -116,19 +110,19 @@ describe("App configs", () => { }); }); - it("Each app should have a different port", () => { + it('Each app should have a different port', () => { const appConfigs = getAppConfigs(); const ports = appConfigs.map((app) => app.port); expect(new Set(ports).size).toBe(appConfigs.length); }); - it("Each app should have a unique id", () => { + it('Each app should have a unique id', () => { const appConfigs = getAppConfigs(); const ids = appConfigs.map((app) => app.id); expect(new Set(ids).size).toBe(appConfigs.length); }); - it("Each app should have a version", () => { + it('Each app should have a version', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -137,7 +131,7 @@ describe("App configs", () => { }); }); - it("Each app should have a docker-compose file beside it", () => { + it('Each app should have a docker-compose file beside it', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -145,7 +139,7 @@ describe("App configs", () => { }); }); - it("Each app should have a metadata folder beside it", () => { + it('Each app should have a metadata folder beside it', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -153,7 +147,7 @@ describe("App configs", () => { }); }); - it("Each app should have a file named logo.jpg in the metadata folder", () => { + it('Each app should have a file named logo.jpg in the metadata folder', () => { const apps = getAppConfigs(); apps.forEach((app) => { @@ -161,13 +155,11 @@ describe("App configs", () => { }); }); - it("Each app should have a container name equals to its id", () => { + it('Each app should have a container name equals to its id', () => { const apps = getAppConfigs(); apps.forEach((app) => { - const dockerComposeFile = fs - .readFileSync(`./apps/${app.id}/docker-compose.yml`) - .toString(); + const dockerComposeFile = fs.readFileSync(`./apps/${app.id}/docker-compose.yml`).toString(); const dockerCompose: any = jsyaml.load(dockerComposeFile); @@ -180,14 +172,12 @@ describe("App configs", () => { }); }); - it("Each app should have network tipi_main_network", () => { + it('Each app should have network tipi_main_network', () => { const apps = getAppConfigs(); apps.forEach((app) => { if (!networkExceptions.includes(app.id)) { - const dockerComposeFile = fs - .readFileSync(`./apps/${app.id}/docker-compose.yml`) - .toString(); + const dockerComposeFile = fs.readFileSync(`./apps/${app.id}/docker-compose.yml`).toString(); const dockerCompose: any = jsyaml.load(dockerComposeFile); @@ -198,9 +188,7 @@ describe("App configs", () => { } expect(dockerCompose.services[app.id].networks).toBeDefined(); - expect(dockerCompose.services[app.id].networks).toStrictEqual([ - "tipi_main_network", - ]); + expect(dockerCompose.services[app.id].networks).toStrictEqual(['tipi_main_network']); } }); }); diff --git a/apps/gladys/config.json b/apps/gladys/config.json new file mode 100644 index 00000000..c628b460 --- /dev/null +++ b/apps/gladys/config.json @@ -0,0 +1,17 @@ +{ + "$schema": "../schema.json", + "name": "Gladys Assistant", + "port": 8270, + "available": true, + "exposable": false, + "id": "gladys", + "tipi_version": 1, + "version": "v4.19.0", + "categories": ["automation"], + "description": "A privacy-first, open-source home assistant", + "short_desc": "A privacy-first, open-source home assistant", + "author": "Gladys Assistant", + "source": "https://github.com/gladysassistant/gladys", + "website": "https://gladysassistant.com/", + "form_fields": [] +} diff --git a/apps/gladys/docker-compose.yml b/apps/gladys/docker-compose.yml new file mode 100644 index 00000000..1f27b6d2 --- /dev/null +++ b/apps/gladys/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3' + +services: + gladys: + container_name: gladys + image: gladysassistant/gladys:v4.19.0 + privileged: true + restart: on-failure + stop_grace_period: 1m + network_mode: host + environment: + - NODE_ENV=production + - SERVER_PORT=8270 + - TZ=${TZ} + - SQLITE_FILE_PATH=/var/lib/gladysassistant/gladys-production.db + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ${APP_DATA_DIR}/data/gladysassistant:/var/lib/gladysassistant + - /dev:/dev + - /run/udev:/run/udev:ro + # Not Exposing like Home Assitant + #labels: + #traefik.enable: ${APP_EXPOSED} + #traefik.http.routers.gladys.rule: Host(`${APP_DOMAIN}`) + #traefik.http.routers.gladys.entrypoints: websecure + #traefik.http.routers.gladys.service: gladys + #traefik.http.routers.gladys.tls.certresolver: myresolver + #traefik.http.services.gladys.loadbalancer.server.port: 8270 diff --git a/apps/gladys/metadata/description.md b/apps/gladys/metadata/description.md new file mode 100644 index 00000000..e806ea34 --- /dev/null +++ b/apps/gladys/metadata/description.md @@ -0,0 +1,21 @@ +Gladys Assistant + +## [Read the Docs](https://gladysassistant.com/docs/) + +#### [](https://github.com/gladysassistant/gladys#a-privacy-first-open-source-home-assistant)A privacy-first, open-source home assistant + +[![](https://camo.githubusercontent.com/c4388e78ec975567952f6587b8f6171be7b8d716c558396afa4622354ab816d5/68747470733a2f2f676c61647973617373697374616e742e636f6d2f656e2f696d672f65787465726e616c2f6769746875622d676c616479732d342d6d6f636b7570732d646576696365732e6a7067)](https://camo.githubusercontent.com/c4388e78ec975567952f6587b8f6171be7b8d716c558396afa4622354ab816d5/68747470733a2f2f676c61647973617373697374616e742e636f6d2f656e2f696d672f65787465726e616c2f6769746875622d676c616479732d342d6d6f636b7570732d646576696365732e6a7067) + +## [](https://github.com/gladysassistant/gladys#try-gladys-assistant)Try Gladys Assistant + +You can try Gladys Assistant on our [demo website](https://demo.gladysassistant.com). + +## [](https://github.com/gladysassistant/gladys#getting-started)Getting Started + +To get started and install Gladys Assistant, you'll find everything on [our website](https://gladysassistant.com). + +## [](https://github.com/gladysassistant/gladys#articles)Articles + +- [EN: Interview in Console #107](https://console.substack.com/p/console-104) +- [EN: Hackster.io - Gladys Assistant Is a Privacy-First Smart Home Platform — and Now Installable in Raspberry Pi Imager](https://www.hackster.io/news/gladys-assistant-is-a-privacy-first-smart-home-platform-and-now-installable-in-raspberry-pi-imager-4a84d5559c63) +- [FR: Framboise 314 - Plus de 500 installations pour l’assistant domotique Gladys !](https://www.framboise314.fr/plus-de-500-installation-pour-lassistant-domotique-gladys/) diff --git a/apps/gladys/metadata/logo.jpg b/apps/gladys/metadata/logo.jpg new file mode 100644 index 00000000..26e0d8aa Binary files /dev/null and b/apps/gladys/metadata/logo.jpg differ