Repository: bastienwirtz/homer Branch: main Commit: 6367012675c1 Files: 204 Total size: 444.9 KB Directory structure: gitextract_exiv45ti/ ├── .dockerignore ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── release.yml │ └── workflows/ │ ├── dockerhub.yml │ ├── integration.yml │ └── release.yml ├── .gitignore ├── .jsconfig.json ├── .schema/ │ └── config-schema.json ├── AGENTS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── docs/ │ ├── configuration.md │ ├── customservices.md │ ├── development.md │ ├── kubernetes.md │ ├── theming.md │ ├── tips-and-tricks.md │ └── troubleshooting.md ├── dummy-data/ │ ├── README.md │ ├── _headers │ ├── adguardhome/ │ │ └── control/ │ │ ├── stats │ │ └── status │ ├── dockersocketproxy/ │ │ └── containers/ │ │ └── json │ ├── docuseal/ │ │ └── version │ ├── emby/ │ │ ├── System/ │ │ │ └── info/ │ │ │ └── public │ │ └── items/ │ │ └── counts │ ├── freshrss/ │ │ └── api/ │ │ └── greader.php/ │ │ ├── accounts/ │ │ │ └── ClientLogin │ │ └── reader/ │ │ └── api/ │ │ └── 0/ │ │ ├── subscription/ │ │ │ └── list │ │ └── unread-count │ ├── gatus/ │ │ └── api/ │ │ └── v1/ │ │ └── endpoints/ │ │ └── statuses │ ├── gitea/ │ │ └── swagger.v1.json │ ├── glances/ │ │ └── api/ │ │ └── 4/ │ │ └── quicklook │ ├── gotify/ │ │ ├── health │ │ └── message │ ├── healthchecks/ │ │ └── api/ │ │ └── v1/ │ │ └── checks │ ├── homeassistant/ │ │ ├── api/ │ │ │ ├── config │ │ │ └── states │ │ └── api_root │ ├── immich/ │ │ └── api/ │ │ ├── server/ │ │ │ └── statistics │ │ └── server-info/ │ │ └── stats │ ├── jellystat/ │ │ └── proxy/ │ │ └── getSessions │ ├── lidarr/ │ │ └── api/ │ │ └── v1/ │ │ ├── health │ │ ├── queue/ │ │ │ └── status │ │ └── wanted/ │ │ └── missing │ ├── linkding/ │ │ └── api/ │ │ └── bookmarks │ ├── matrix/ │ │ └── _matrix/ │ │ └── federation/ │ │ └── v1/ │ │ └── version │ ├── mealie/ │ │ └── api/ │ │ ├── admin/ │ │ │ └── about/ │ │ │ └── statistics │ │ └── groups/ │ │ └── mealplans/ │ │ └── today │ ├── medusa/ │ │ └── api/ │ │ └── v2/ │ │ └── config │ ├── miniflux/ │ │ └── v1/ │ │ └── entries │ ├── nextcloud/ │ │ └── status.php │ ├── octoprint/ │ │ └── api/ │ │ ├── job │ │ ├── printer │ │ ├── status_printer_offline-error.json │ │ ├── status_printer_offline.json │ │ ├── status_printer_operational.json │ │ ├── status_printer_printing.json │ │ ├── status_printer_printing_1of2.json │ │ ├── status_printer_printing_2of2.json │ │ └── status_printing_completion.json │ ├── olivetin/ │ │ └── webUiSettings.json │ ├── openHAB/ │ │ └── rest/ │ │ └── systeminfo │ ├── openweather/ │ │ └── weather │ ├── paperlessng/ │ │ └── api/ │ │ └── documents │ ├── peanut/ │ │ └── api/ │ │ └── v1/ │ │ └── devices/ │ │ └── ups │ ├── pialert/ │ │ └── php/ │ │ └── server/ │ │ └── devices.php │ ├── pihole/ │ │ └── api.php │ ├── plex/ │ │ ├── library/ │ │ │ ├── sections │ │ │ ├── sections1all │ │ │ └── sections2all │ │ └── status/ │ │ └── sessions │ ├── portainer/ │ │ └── api/ │ │ ├── endpoints │ │ ├── endpoints.backup │ │ └── status │ ├── prometheus/ │ │ └── api/ │ │ └── v1/ │ │ └── alerts │ ├── prowlarr/ │ │ └── api/ │ │ └── v1/ │ │ └── health │ ├── proxmox/ │ │ └── api2/ │ │ └── json/ │ │ └── nodes/ │ │ └── node1/ │ │ ├── lxc │ │ ├── qemu │ │ └── status │ ├── qBittorrent/ │ │ └── api/ │ │ └── v2/ │ │ ├── torrents/ │ │ │ └── info │ │ └── transfer/ │ │ └── info │ ├── radarr/ │ │ └── api/ │ │ └── v3/ │ │ ├── health │ │ ├── queue │ │ ├── queuedetails │ │ └── wanted/ │ │ └── missing │ ├── rtorrent/ │ │ ├── download_list │ │ ├── global_down │ │ └── global_up │ ├── sabnzbd/ │ │ └── api │ ├── scrutiny/ │ │ └── api/ │ │ └── summary │ ├── sonarr/ │ │ └── api/ │ │ └── v3/ │ │ ├── health │ │ ├── queue │ │ └── wanted/ │ │ └── missing │ ├── speedtesttracker/ │ │ └── api/ │ │ └── speedtest/ │ │ └── latest │ ├── tautulli/ │ │ └── api/ │ │ └── v2 │ ├── tdarr/ │ │ └── api/ │ │ └── v2/ │ │ └── cruddb │ ├── traefik/ │ │ └── api/ │ │ └── version │ ├── truenasscale/ │ │ └── api/ │ │ └── v2.0/ │ │ └── system/ │ │ └── version │ ├── uptimekuma/ │ │ └── api/ │ │ └── status-page/ │ │ ├── default │ │ └── heartbeat/ │ │ └── default │ ├── vaultwarden/ │ │ └── api/ │ │ └── version │ ├── wallabag/ │ │ └── api/ │ │ └── version │ └── wud/ │ └── api/ │ └── containers ├── entrypoint.sh ├── eslint.config.js ├── index.html ├── lighttpd-ipv6.sh ├── lighttpd.conf ├── package.json ├── public/ │ └── assets/ │ ├── additional-page.yml.dist │ ├── config-demo.yml.dist │ ├── config.yml.dist │ ├── custom.css.sample │ └── icons/ │ └── README.md ├── src/ │ ├── App.vue │ ├── assets/ │ │ ├── app.scss │ │ ├── components/ │ │ │ ├── base.scss │ │ │ ├── highlights.scss │ │ │ ├── layers.scss │ │ │ └── status.scss │ │ ├── defaults.yml │ │ ├── themes/ │ │ │ ├── classic.scss │ │ │ ├── neon.scss │ │ │ └── walkxcode.scss │ │ └── webfonts/ │ │ ├── noto/ │ │ │ ├── OFL.txt │ │ │ └── README.txt │ │ └── webfonts.scss │ ├── components/ │ │ ├── ConnectivityChecker.vue │ │ ├── DarkMode.vue │ │ ├── DynamicTheme.vue │ │ ├── GetStarted.vue │ │ ├── GroupHeader.vue │ │ ├── Message.vue │ │ ├── Navbar.vue │ │ ├── SearchInput.vue │ │ ├── Service.vue │ │ ├── ServiceGroup.vue │ │ ├── SettingToggle.vue │ │ └── services/ │ │ ├── AdGuardHome.vue │ │ ├── CopyToClipboard.vue │ │ ├── DockerSocketProxy.vue │ │ ├── Docuseal.vue │ │ ├── Emby.vue │ │ ├── FreshRSS.vue │ │ ├── Gatus.vue │ │ ├── Generic.vue │ │ ├── Gitea.vue │ │ ├── Glances.vue │ │ ├── Gotify.vue │ │ ├── Healthchecks.vue │ │ ├── HomeAssistant.vue │ │ ├── Immich.vue │ │ ├── Jellystat.vue │ │ ├── Lidarr.vue │ │ ├── Linkding.vue │ │ ├── Matrix.vue │ │ ├── Mealie.vue │ │ ├── Medusa.vue │ │ ├── Miniflux.vue │ │ ├── Mylar.vue │ │ ├── Nextcloud.vue │ │ ├── OctoPrint.vue │ │ ├── Olivetin.vue │ │ ├── OpenHAB.vue │ │ ├── OpenWeather.vue │ │ ├── PaperlessNG.vue │ │ ├── PeaNUT.vue │ │ ├── PiAlert.vue │ │ ├── PiHole.vue │ │ ├── Ping.vue │ │ ├── Plex.vue │ │ ├── Portainer.vue │ │ ├── Prometheus.vue │ │ ├── Prowlarr.vue │ │ ├── Proxmox.vue │ │ ├── Radarr.vue │ │ ├── Readarr.vue │ │ ├── Rtorrent.vue │ │ ├── SABnzbd.vue │ │ ├── Scrutiny.vue │ │ ├── Sonarr.vue │ │ ├── SpeedtestTracker.vue │ │ ├── Tautulli.vue │ │ ├── Tdarr.vue │ │ ├── ThemeChooser.vue │ │ ├── Traefik.vue │ │ ├── Transmission.vue │ │ ├── TruenasScale.vue │ │ ├── UptimeKuma.vue │ │ ├── Vaultwarden.vue │ │ ├── WUD.vue │ │ ├── Wallabag.vue │ │ ├── _error.vue │ │ └── qBittorrent.vue │ ├── main.js │ └── mixins/ │ └── service.js └── vite.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ assets/* dockerfile *.md .git screenshot.png node_modules ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms # These are supported funding model platforms github: [bastienwirtz] buy_me_a_coffee: bastien ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **Expected behavior** A clear and concise description of what you expected to happen. **Logs & errors** Please include any usefull information: - Errors in your browser console (`ctrl+shift+i` or `F12`) - If applicable, your docker container logs. **Screenshots** If applicable, add screenshots to help explain your problem. **Configuration** If applicable, copy related homer yaml configuration here. ```yml ``` ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Description Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. Fixes # (issue) ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactoring ## Checklist: - [ ] I've read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/main/CONTRIBUTING.md) - [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers. - [ ] I have made corresponding changes to the documentation (`README.md`). - [ ] I've checked my modifications for any breaking changes, especially in the `config.yml` file ================================================ FILE: .github/release.yml ================================================ changelog: exclude: authors: - dependabot categories: - title: Main changes labels: - "*" ================================================ FILE: .github/workflows/dockerhub.yml ================================================ # Build & publish docker images name: Dockerhub on: push: tags: [v*] jobs: dockerhub: runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ github.token }} - name: Build and push uses: docker/build-push-action@v6 with: push: true tags: | b4bz/homer:latest b4bz/homer:${{ github.ref_name }} ghcr.io/${{ github.repository }}:latest ghcr.io/${{ github.repository }}:${{ github.ref_name }} platforms: linux/amd64,linux/arm/v7,linux/arm/v6,linux/arm64 build-args: | VERSION_TAG=${{ github.ref_name }} ================================================ FILE: .github/workflows/integration.yml ================================================ # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Integration on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v4 - name: pnpm setup uses: pnpm/action-setup@v4 - name: Node.js setup uses: actions/setup-node@v4 with: node-version: 22 cache: 'pnpm' - name: install dependencies run: pnpm install --frozen-lockfile - name: Check code style & potentential issues run: pnpm lint ================================================ FILE: .github/workflows/release.yml ================================================ # Publish pre-build release name: Create Github release on: push: tags: [v*] jobs: build: name: Upload Release Asset runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v4 - name: pnpm setup uses: pnpm/action-setup@v4 - name: Node.js setup uses: actions/setup-node@v4 with: node-version: 22 cache: 'pnpm' - name: Build project run: | pnpm install --frozen-lockfile pnpm build - name: Create artifact working-directory: "dist" run: zip -r ../homer.zip ./* - name: Create Release id: create_release uses: softprops/action-gh-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} generate_release_notes: true files: | homer.zip ================================================ FILE: .gitignore ================================================ .DS_Store node_modules /dist # local env files .env.local .env.*.local # Log files npm-debug.log* yarn-debug.log* yarn-error.log* # Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw? # App configuration config.yml .drone.yml # Specific Agent file CLAUDE.md GEMINI.md ================================================ FILE: .jsconfig.json ================================================ { "compilerOptions": { "paths": { "@/*": ["./src/*"] } }, "exclude": ["node_modules", "dist"] } ================================================ FILE: .schema/config-schema.json ================================================ { "$id": "https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json", "$schema": "http://json-schema.org/draft-07/schema", "description": "https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md", "examples": [], "title": "Homer Dashboard configuration", "type": "object", "definitions": { "Colors": { "type": "object", "additionalProperties": false, "properties": { "light": { "$ref": "#/definitions/ColorSet" }, "dark": { "$ref": "#/definitions/ColorSet" } }, "title": "Colors" }, "ColorSet": { "type": "object", "additionalProperties": false, "properties": { "highlight-primary": { "type": "string" }, "highlight-secondary": { "type": "string" }, "highlight-hover": { "type": "string" }, "background": { "type": "string" }, "card-background": { "type": "string" }, "text": { "type": "string" }, "text-header": { "type": "string" }, "text-title": { "type": "string" }, "text-subtitle": { "type": "string" }, "card-shadow": { "type": "string" }, "link": { "type": "string" }, "link-hover": { "type": "string" }, "background-image": { "type": "string" } } }, "Defaults": { "type": "object", "additionalProperties": false, "properties": { "layout": { "enum": [ "columns", "list" ], "description": "Layout of the dashboard, either 'columns' or 'list'" }, "colorTheme": { "enum": [ "auto", "light", "dark" ], "description": "One of 'auto', 'light', or 'dark'" } }, "title": "Defaults" }, "Hotkey": { "type": "object", "additionalProperties": false, "properties": { "search": { "type": "string", "description": "hotkey for search, e.g. Shift" } }, "required": [ "search" ] }, "Link": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "Name as seen in the navbar" }, "icon": { "type": "string", "description": "Fontawesome icon" }, "url": { "type": "string", "description": "Url of the link. When #filename is used, it is a link to another homer page, while 'filename' is the name of the config file" }, "target": { "type": "string", "description": "html tag target attribute like _blank for a new page" } }, "required": [ "url" ], "title": "Link" }, "Message": { "type": "object", "additionalProperties": false, "properties": { "url": { "type": "string", "format": "uri" }, "mapping": { "$ref": "#/definitions/Mapping", "description": "Mapping for the content loaded from the URL" }, "refreshInterval": { "type": "integer", "description": "The refresh interval in milliseconds for reloading the message url" }, "style": { "type": "string", "description": "See https://bulma.io/documentation/components/message/#colors for styling options" }, "title": { "type": "string", "description": "Title of the message box" }, "icon": { "type": "string", "description": "Fontawesome icon for the message box" }, "content": { "type": "string", "description": "HTML content for the message box" } }, "title": "Messagebox" }, "Mapping": { "type": "object", "additionalProperties": true, "title": "Mapping" }, "Proxy": { "type": "object", "additionalProperties": false, "properties": { "useCredentials": { "type": "boolean", "description": "# send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level. " }, "headers": { "$ref": "#/definitions/Headers", "description": "send custom headers when fetching service specific data. Can also be set on a service level." } }, "title": "Proxy" }, "Headers": { "type": "object", "additionalProperties": true, "title": "Headers" }, "Service": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "Service name" }, "icon": { "type": "string", "description": "Fontawesome icon for the service" }, "logo": { "type": "string", "description": "A path to an image can also be provided. Note that icon take precedence if both icon and logo are set." }, "class": { "type": "string", "description": "Optional css class to add on the service group. Example 'highlight-purple'" }, "items": { "type": "array", "items": { "$ref": "#/definitions/Item" } } }, "required": [ "items" ], "title": "Service" }, "Item": { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string" }, "logo": { "type": "string", "description": "Path to a logo. Alternatively a fa icon can be provided" }, "icon": { "type": "string", "description": "Fontawesome icon for the item, alternative for logo" }, "subtitle": { "type": "string" }, "tag": { "type": "string", "description": "Show tag" }, "keywords": { "type": "string", "description": "Optional keyword used for searching purpose" }, "url": { "type": "string", "description": "Url of this item" }, "target": { "type": "string", "description": "html tag target attribute like _blank for a new page" }, "tagstyle": { "type": "string", "description": "Styleclass for the tag" }, "type": { "type": "string", "description": "Optional, loads a specific component that provides extra features. MUST MATCH a file name (without file extension) available in `src/components/services`" } }, "title": "Item" } }, "properties": { "externalConfig": { "type": "string", "description": "Use external configuration file. Using this will ignore remaining config in this file externalConfig: https://example.com/server-luci/config.yaml" }, "title": { "type": "string", "description": "Title of the dashboard" }, "subtitle": { "type": "string", "description": "Subtitle of the dashboard" }, "documentTitle": { "type": "string", "description": "Title of the document. When not filled, title (and subtitle will be used)" }, "logo": { "type": "string", "description": "Path to logo image" }, "icon": { "type": "string", "description": "Dashboard icon" }, "header": { "type": "boolean", "description": "Show header, default is true" }, "hotkey": { "$ref": "#/definitions/Hotkey", "description": "Define hotkeys, for example for search" }, "footer": { "anyOf": [ { "type": "boolean" }, { "type": "string" } ], "description": "footer Line content. HTML is supported. Set false if you want to hide it." }, "columns": { "type": "string", "description": "'auto' or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)", "format": "integer" }, "connectivityCheck": { "type": "boolean", "description": "# whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example). You should set it to true when using an authentication proxy, it also reloads the page when a redirection is detected when checking connectivity." }, "proxy": { "$ref": "#/definitions/Proxy", "description": "Optional: Proxy / hosting option" }, "defaults": { "$ref": "#/definitions/Defaults" }, "theme": { "type": "string", "description": "'default' or one of the themes available in 'src/assets/themes'" }, "stylesheet": { "type": "array", "items": { "type": "string" }, "description": "Will load custom CSS files. Especially useful for custom icon sets. Entries are paths to the stylesheets" }, "colors": { "$ref": "#/definitions/Colors" }, "message": { "$ref": "#/definitions/Message", "description": "Messagebox" }, "links": { "description": "Links in the navigation bar", "type": "array", "items": { "$ref": "#/definitions/Link" } }, "services": { "description": "Services", "type": "array", "items": { "$ref": "#/definitions/Service" } } } } ================================================ FILE: AGENTS.md ================================================ # AGENTS Instructions This file provides guidance to AI Agents when working with code in this repository. ## Development Commands ```bash pnpm install # Install dependencies (PNPM enforced via packageManager) pnpm dev # Start development server on http://localhost:3000 pnpm mock # Start mock API server for testing service integrations pnpm build # Build for production pnpm preview # Preview production build pnpm lint # Run ESLint with auto-fix ``` ## Architecture Overview Homer is a static Vue.js 3 PWA dashboard that loads configuration from YAML files. The architecture is service-oriented with dynamic component loading. ### Core Application Structure - **Entry Point**: `src/main.js` mounts the Vue app - **Root Component**: `src/App.vue` handles layout, configuration loading, and routing - **Configuration System**: YAML-based with runtime merging of defaults (`src/assets/defaults.yml`) and user config (`/assets/config.yml`) - **Service Components**: 53 specialized integrations in `src/components/services/` that extend a Generic component pattern ### Service Integration Pattern All service components follow this architecture: - Extend `Generic.vue` using Vue slots (`