forked from extern/homer
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
a4c1f6a37d | |||
76d30be8e3 | |||
240e3f0e87 | |||
33f75a798a | |||
a2dfffab68 |
8
.github/release.yml
vendored
8
.github/release.yml
vendored
@ -1,8 +0,0 @@
|
||||
changelog:
|
||||
exclude:
|
||||
authors:
|
||||
- dependabot
|
||||
categories:
|
||||
- title: Main changes
|
||||
labels:
|
||||
- "*"
|
44
.github/workflows/dockerhub.yml
vendored
44
.github/workflows/dockerhub.yml
vendored
@ -1,44 +0,0 @@
|
||||
# Build & publish docker images
|
||||
name: Dockerhub
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [v*]
|
||||
branches: [ main ]
|
||||
|
||||
|
||||
jobs:
|
||||
dockerhub:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Set tag name
|
||||
run: |
|
||||
if [[ ${{ github.ref_type }} == "tag" ]]; then
|
||||
echo "IMAGE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IMAGE_TAG=latest" >> $GITHUB_ENV
|
||||
fi
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
tags: b4bz/homer:${{env.IMAGE_TAG}}
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
|
24
.github/workflows/release.yml
vendored
24
.github/workflows/release.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
name: Upload Release Asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build project
|
||||
run: |
|
||||
yarn install
|
||||
@ -20,9 +20,21 @@ jobs:
|
||||
run: zip -r ../homer.zip ./*
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
homer.zip
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./homer.zip
|
||||
asset_name: homer.zip
|
||||
asset_content_type: application/zip
|
||||
|
24
Dockerfile
24
Dockerfile
@ -10,30 +10,24 @@ COPY . .
|
||||
RUN yarn build
|
||||
|
||||
# production stage
|
||||
FROM alpine:3.16
|
||||
FROM alpine:3.15
|
||||
|
||||
ENV GID 1000
|
||||
ENV UID 1000
|
||||
ENV USER darkhttpd
|
||||
ENV GROUP darkhttpd
|
||||
ENV GID 911
|
||||
ENV UID 911
|
||||
ENV PORT 8080
|
||||
ENV SUBFOLDER "/_"
|
||||
ENV INIT_ASSETS 1
|
||||
|
||||
RUN addgroup -S lighttpd -g ${GID} && adduser -D -S -u ${UID} lighttpd lighttpd && \
|
||||
apk add -U --no-cache lighttpd
|
||||
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
|
||||
apk add -U --no-cache su-exec darkhttpd
|
||||
|
||||
WORKDIR /www
|
||||
|
||||
COPY lighttpd.conf /lighttpd.conf
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
COPY --from=build-stage --chown=${UID}:${GID} /app/dist /www/
|
||||
COPY --from=build-stage --chown=${UID}:${GID} /app/dist/assets /www/default-assets
|
||||
|
||||
USER ${UID}:${GID}
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1
|
||||
|
||||
EXPOSE ${PORT}
|
||||
VOLUME /www/assets
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
|
||||
|
43
Dockerfile.arm32v7
Normal file
43
Dockerfile.arm32v7
Normal file
@ -0,0 +1,43 @@
|
||||
# build stage
|
||||
FROM node:lts-alpine as build-stage
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
RUN yarn build
|
||||
|
||||
# Multi arch build support
|
||||
FROM alpine as qemu
|
||||
|
||||
ARG QEMU_VERSION="v4.2.0-7"
|
||||
|
||||
RUN wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-arm-static && chmod +x qemu-arm-static
|
||||
|
||||
# production stage
|
||||
FROM arm32v7/alpine:3.11
|
||||
|
||||
COPY --from=qemu qemu-arm-static /usr/bin/
|
||||
|
||||
ENV USER darkhttpd
|
||||
ENV GROUP darkhttpd
|
||||
ENV GID 911
|
||||
ENV UID 911
|
||||
ENV PORT 8080
|
||||
|
||||
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
|
||||
apk add -U --no-cache darkhttpd su-exec && \
|
||||
rm /usr/bin/qemu-arm-static
|
||||
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1
|
||||
|
||||
EXPOSE ${PORT}
|
||||
VOLUME /www/assets
|
||||
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
|
43
Dockerfile.arm64v8
Normal file
43
Dockerfile.arm64v8
Normal file
@ -0,0 +1,43 @@
|
||||
# build stage
|
||||
FROM node:lts-alpine as build-stage
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
RUN yarn build
|
||||
|
||||
# Multi arch build support
|
||||
FROM alpine as qemu
|
||||
|
||||
ARG QEMU_VERSION="v4.2.0-7"
|
||||
|
||||
RUN wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-aarch64-static && chmod +x qemu-aarch64-static
|
||||
|
||||
# production stage
|
||||
FROM arm64v8/alpine:3.11
|
||||
|
||||
COPY --from=qemu qemu-aarch64-static /usr/bin/
|
||||
|
||||
ENV USER darkhttpd
|
||||
ENV GROUP darkhttpd
|
||||
ENV GID 911
|
||||
ENV UID 911
|
||||
ENV PORT 8080
|
||||
|
||||
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
|
||||
apk add -U --no-cache darkhttpd su-exec && \
|
||||
rm /usr/bin/qemu-aarch64-static
|
||||
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
|
||||
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1
|
||||
|
||||
EXPOSE ${PORT}
|
||||
VOLUME /www/assets
|
||||
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
|
25
README.md
25
README.md
@ -71,6 +71,8 @@ See [documentation](docs/configuration.md) for information about the configurati
|
||||
|
||||
### Using docker
|
||||
|
||||
To launch container:
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
@ -79,19 +81,12 @@ docker run -d \
|
||||
b4bz/homer:latest
|
||||
```
|
||||
|
||||
Environment variables:
|
||||
|
||||
* **`INIT_ASSETS`** (default: `1`)
|
||||
Install example configuration file & assets (favicons, ...) to help you get started.
|
||||
|
||||
* **`SUBFOLDER`** (default: `null`)
|
||||
If you would like to host Homer in a subfolder, (ex: *http://my-domain/**homer***), set this to the subfolder path (ex `/homer`).
|
||||
|
||||
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner (`docker run -e "UID=1000" -e "GID=1000" [...]`).
|
||||
|
||||
### Using docker-compose
|
||||
|
||||
The `docker-compose.yml` file must be edited to match your needs.
|
||||
You probably want to set the port mapping and volume binding (equivalent to `-p` and `-v` arguments):
|
||||
Set the port and volume (equivalent to `-p` and `-v` arguments):
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
@ -100,13 +95,21 @@ ports:
|
||||
- 8080:8080
|
||||
```
|
||||
|
||||
Then launch the container:
|
||||
To launch container:
|
||||
|
||||
```sh
|
||||
cd /path/to/docker-compose.yml/
|
||||
cd /path/to/docker-compose.yml
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner, also in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
```
|
||||
|
||||
### Using the release tarball (prebuilt, ready to use)
|
||||
|
||||
Download and extract the latest release (`homer.zip`) from the [release page](https://github.com/bastienwirtz/homer/releases), rename the `assets/config.yml.dist` file to `assets/config.yml`, and put it behind a web server.
|
||||
|
@ -10,6 +10,7 @@ services:
|
||||
- /your/local/assets/:/www/assets
|
||||
ports:
|
||||
- 8080:8080
|
||||
user: 1000:1000 # default
|
||||
environment:
|
||||
- INIT_ASSETS=1 # default
|
||||
#environment:
|
||||
# - UID=1000
|
||||
# - GID=1000
|
||||
restart: unless-stopped
|
||||
|
@ -25,8 +25,7 @@ header: true # Set to false to hide the header
|
||||
footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
|
||||
|
||||
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
|
||||
connectivityCheck: true # 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.
|
||||
connectivityCheck: true # whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example)
|
||||
|
||||
# Optional: Proxy / hosting option
|
||||
proxy:
|
||||
@ -128,7 +127,6 @@ services:
|
||||
# icon: "fab fa-jenkins"
|
||||
subtitle: "Bookmark example"
|
||||
tag: "app"
|
||||
keywords: "self hosted reddit" # optional keyword used for searching purpose
|
||||
url: "https://www.reddit.com/r/selfhosted/"
|
||||
target: "_blank" # optional html tag target attribute
|
||||
- name: "Another one"
|
||||
|
@ -16,9 +16,7 @@ within Homer:
|
||||
+ [Prometheus](#prometheus)
|
||||
+ [AdGuard Home](#adguard-home)
|
||||
+ [Portainer](#portainer)
|
||||
+ [Emby / Jellyfin](#emby--jellyfin)
|
||||
+ [Uptime Kuma](#uptime-kuma)
|
||||
+ [Tautulli](#tautulli)
|
||||
+ [Emby](#emby)
|
||||
|
||||
If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page.
|
||||
|
||||
@ -169,7 +167,7 @@ See https://docs.portainer.io/v/ce-2.11/user/account-settings#access-tokens
|
||||
# - "local"
|
||||
```
|
||||
|
||||
## Emby / Jellyfin
|
||||
## Emby
|
||||
|
||||
You need to set the type to Emby, provide an api key and choose which stats to show if the subtitle is disabled.
|
||||
|
||||
@ -181,45 +179,3 @@ You need to set the type to Emby, provide an api key and choose which stats to s
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
libraryType: "music" #Choose which stats to show. Can be one of: music, series or movies.
|
||||
```
|
||||
|
||||
## Uptime Kuma
|
||||
|
||||
Using the Uptime Kuma service you can display info about your instance uptime right on your Homer dashboard.
|
||||
|
||||
The following configuration is available for the UptimeKuma service. Needs v1.13.1 or later because of the change in APIs due to [multiple status pages support](https://github.com/louislam/uptime-kuma/releases/tag/1.13.1).
|
||||
|
||||
```yaml
|
||||
- name: "Uptime Kuma"
|
||||
logo: "assets/tools/sample.png"
|
||||
# subtitle: "A fancy self-hosted monitoring tool" # optional, if no subtitle is defined, Uptime Kuma incidents, if any, will be shown
|
||||
url: "http://192.168.0.151:3001"
|
||||
slug: "myCustomDashboard" # Defaults to "default" if not provided.
|
||||
type: "UptimeKuma"
|
||||
```
|
||||
|
||||
## Tautulli
|
||||
|
||||
The Tautulli service can allow you to show the number of currently active
|
||||
streams on you Plex instance. An API key is required, and can be obtained from
|
||||
the "Web Interface" section of settings on the Tautulli web UI.
|
||||
|
||||
```yaml
|
||||
- name: "Tautulli"
|
||||
logo: "assets/tools/sample.png"
|
||||
url: "http://192.168.0.151:8181"
|
||||
type: "Tautulli"
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
```
|
||||
|
||||
Because the service type and link don't necessarily have to match, you could
|
||||
even make the service type Tautulli on your Plex card and provide a separate
|
||||
endpoint pointing to Tautulli!
|
||||
|
||||
```yaml
|
||||
- name: "Plex"
|
||||
logo: "assets/tools/sample.png"
|
||||
url: "http://192.168.0.151:32400/web" # Plex
|
||||
endpoint: "http://192.168.0.151:8181" # Tautulli
|
||||
type: "Tautulli"
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
```
|
||||
|
@ -17,9 +17,3 @@ To resolve this, you can either:
|
||||
* Host all your target service under the same domain & port.
|
||||
* Modify the target server configuration so that the response of the server included following header- `Access-Control-Allow-Origin: *` (<https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests>). It might be an option in the targeted service, otherwise depending on how the service is hosted, the proxy or web server can seamlessly add it.
|
||||
* Use a cors proxy server like [`cors-container`](https://github.com/imjacobclark/cors-container), [`cors-anywhere`](https://github.com/Rob--W/cors-anywhere) or many others.
|
||||
|
||||
## I am using an authentication proxy and homer says I am offline
|
||||
|
||||
This should be a configuration issue.
|
||||
* Make sure the option `connectivityCheck` is set to `true` in configuration.
|
||||
* Check your proxy configuration, the expected behavior is to redirect user using a 302 to the login page when user is not authenticated.
|
||||
|
@ -1,18 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
PERMISSION_ERROR="Check assets directory permissions & docker user or skip default assets install by setting the INIT_ASSETS env var to 0"
|
||||
# Ensure default assets are present.
|
||||
while true; do echo n; done | cp -Ri /www/default-assets/* /www/assets/ &> /dev/null
|
||||
|
||||
# Default assets & exemple configuration installation if possible.
|
||||
if [[ "${INIT_ASSETS}" == "1" ]] && [[ ! -f "/www/config.yml" ]]; then
|
||||
echo "No configuration found, installing default config & assets"
|
||||
if [[ ! -w "/www/assets/" ]]; then echo "Assets directory not writable. $PERMISSION_ERROR" && exit 1; fi
|
||||
|
||||
while true; do echo n; done | cp -Ri /www/default-assets/* /www/assets/ &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then echo "Fail to copy default assets. $PERMISSION_ERROR" && exit 1; fi
|
||||
|
||||
yes n | cp -i /www/default-assets/config.yml.dist /www/assets/config.yml &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then echo "Fail to copy default config file. $PERMISSION_ERROR" && exit 1; fi
|
||||
# Ensure compatibility with previous version (config.yml was in the root directory)
|
||||
if [ -f "/www/config.yml" ]; then
|
||||
yes n | cp -i /www/config.yml /www/assets/ &> /dev/null
|
||||
fi
|
||||
|
||||
echo "Starting webserver"
|
||||
lighttpd -D -f /lighttpd.conf
|
||||
# Install default config if no one is available.
|
||||
yes n | cp -i /www/default-assets/config.yml.dist /www/assets/config.yml &> /dev/null
|
||||
|
||||
chown -R $UID:$GID /www/assets
|
||||
exec su-exec $UID:$GID darkhttpd /www/ --no-listing --port "$PORT"
|
||||
|
8
hooks/post_push
Normal file
8
hooks/post_push
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
IFS='-' read -r TAG string <<< "$DOCKER_TAG"
|
||||
|
||||
docker manifest create b4bz/homer:$TAG b4bz/homer:$TAG-amd64 b4bz/homer:$TAG-arm32v7 b4bz/homer:$TAG-arm64v8
|
||||
docker manifest annotate b4bz/homer:$TAG b4bz/homer:$TAG-arm32v7 --os linux --arch arm
|
||||
docker manifest annotate b4bz/homer:$TAG b4bz/homer:$TAG-arm64v8 --os linux --arch arm64 --variant v8
|
||||
docker manifest push --purge b4bz/homer:$TAG
|
8
hooks/pre_build
Normal file
8
hooks/pre_build
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Update to docker-ee 18.x for manifests
|
||||
apt-get -y update
|
||||
apt-get -y --only-upgrade install docker-ee
|
||||
# Register qemu-*-static for all supported processors except the
|
||||
# current one, but also remove all registered binfmt_misc before
|
||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
@ -1,10 +0,0 @@
|
||||
include "/etc/lighttpd/mime-types.conf"
|
||||
|
||||
server.port = env.PORT
|
||||
server.modules = ( "mod_alias" )
|
||||
server.username = "lighttpd"
|
||||
server.groupname = "lighttpd"
|
||||
server.document-root = "/www"
|
||||
alias.url = ( env.SUBFOLDER => "/www" )
|
||||
server.indexfiles = ("index.html")
|
||||
server.follow-symlink = "enable"
|
14
package.json
14
package.json
@ -7,19 +7,19 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"bulma": "^0.9.4",
|
||||
"core-js": "^3.22.7",
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"bulma": "^0.9.3",
|
||||
"core-js": "^3.21.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"vue": "^2.6.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.17",
|
||||
"@vue/cli-plugin-eslint": "~4.5.17",
|
||||
"@vue/cli-plugin-pwa": "~4.5.17",
|
||||
"@vue/cli-service": "~4.5.17",
|
||||
"@vue/cli-plugin-babel": "~4.5.15",
|
||||
"@vue/cli-plugin-eslint": "~4.5.15",
|
||||
"@vue/cli-plugin-pwa": "~4.5.15",
|
||||
"@vue/cli-service": "~4.5.15",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
|
@ -75,7 +75,6 @@ services:
|
||||
logo: "assets/tools/sample.png"
|
||||
subtitle: "Bookmark example"
|
||||
tag: "app"
|
||||
keywords: "self hosted reddit"
|
||||
url: "https://www.reddit.com/r/selfhosted/"
|
||||
target: "_blank" # optional html a tag target attribute
|
||||
- name: "Another one"
|
||||
|
39
src/App.vue
39
src/App.vue
@ -18,10 +18,7 @@
|
||||
</a>
|
||||
<i v-if="config.icon" :class="config.icon"></i>
|
||||
</div>
|
||||
<div
|
||||
class="dashboard-title"
|
||||
:class="{ 'no-logo': !config.icon || !config.logo }"
|
||||
>
|
||||
<div class="dashboard-title">
|
||||
<span class="headline">{{ config.subtitle }}</span>
|
||||
<h1>{{ config.title }}</h1>
|
||||
</div>
|
||||
@ -64,7 +61,7 @@
|
||||
@network-status-update="offline = $event"
|
||||
/>
|
||||
|
||||
<GetStarted v-if="configurationNeeded" />
|
||||
<GetStarted v-if="loaded && !services" />
|
||||
|
||||
<div v-if="!offline">
|
||||
<!-- Optional messages -->
|
||||
@ -72,12 +69,8 @@
|
||||
|
||||
<!-- Horizontal layout -->
|
||||
<div v-if="!vlayout || filter" class="columns is-multiline">
|
||||
<template v-for="(group, groupIndex) in services">
|
||||
<h2
|
||||
v-if="group.name"
|
||||
class="column is-full group-title"
|
||||
:key="`header-${groupIndex}`"
|
||||
>
|
||||
<template v-for="group in services">
|
||||
<h2 v-if="group.name" class="column is-full group-title">
|
||||
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
|
||||
<div v-else-if="group.logo" class="group-logo media-left">
|
||||
<figure class="image is-48x48">
|
||||
@ -88,9 +81,10 @@
|
||||
</h2>
|
||||
<Service
|
||||
v-for="(item, index) in group.items"
|
||||
:key="`service-${groupIndex}-${index}`"
|
||||
:key="index"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:forwarder="config.forwarder"
|
||||
:class="['column', `is-${12 / config.columns}`]"
|
||||
/>
|
||||
</template>
|
||||
@ -103,8 +97,8 @@
|
||||
>
|
||||
<div
|
||||
:class="['column', `is-${12 / config.columns}`]"
|
||||
v-for="(group, groupIndex) in services"
|
||||
:key="groupIndex"
|
||||
v-for="group in services"
|
||||
:key="group.name"
|
||||
>
|
||||
<h2 v-if="group.name" class="group-title">
|
||||
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
|
||||
@ -120,6 +114,7 @@
|
||||
:key="index"
|
||||
:item="item"
|
||||
:proxy="config.proxy"
|
||||
:forwarder="config.forwarder"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -171,7 +166,6 @@ export default {
|
||||
data: function () {
|
||||
return {
|
||||
loaded: false,
|
||||
configNotFound: false,
|
||||
config: null,
|
||||
services: null,
|
||||
offline: false,
|
||||
@ -181,11 +175,6 @@ export default {
|
||||
showMenu: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
configurationNeeded: function () {
|
||||
return (this.loaded && !this.services) || this.configNotFound;
|
||||
},
|
||||
},
|
||||
created: async function () {
|
||||
this.buildDashboard();
|
||||
window.onhashchange = this.buildDashboard;
|
||||
@ -231,9 +220,10 @@ export default {
|
||||
},
|
||||
getConfig: function (path = "assets/config.yml") {
|
||||
return fetch(path).then((response) => {
|
||||
if (response.status == 404 || response.redirected) {
|
||||
this.configNotFound = true;
|
||||
return {};
|
||||
if (response.redirected) {
|
||||
// This allows to work with authentication proxies.
|
||||
window.location.href = response.url;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
@ -258,8 +248,7 @@ export default {
|
||||
return (
|
||||
item.name.toLowerCase().includes(this.filter) ||
|
||||
(item.subtitle && item.subtitle.toLowerCase().includes(this.filter)) ||
|
||||
(item.tag && item.tag.toLowerCase().includes(this.filter)) ||
|
||||
(item.keywords && item.keywords.toLowerCase().includes(this.filter))
|
||||
(item.tag && item.tag.toLowerCase().includes(this.filter))
|
||||
);
|
||||
},
|
||||
navigateToFirstService: function (target) {
|
||||
|
@ -104,10 +104,6 @@ body {
|
||||
|
||||
.dashboard-title {
|
||||
padding: 6px 0 0 80px;
|
||||
|
||||
&.no-logo {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.first-line {
|
||||
@ -167,7 +163,8 @@ body {
|
||||
}
|
||||
|
||||
#main-section {
|
||||
padding: 0 0 2.5rem 0;
|
||||
margin-bottom: 2rem;
|
||||
padding: 0;
|
||||
|
||||
h2 {
|
||||
padding-bottom: 0px;
|
||||
@ -289,7 +286,7 @@ body {
|
||||
|
||||
.no-footer {
|
||||
#main-section {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
@ -53,3 +53,4 @@ services: []
|
||||
|
||||
|
||||
proxy: ~
|
||||
forwarder: ~
|
||||
|
@ -17,9 +17,6 @@ export default {
|
||||
};
|
||||
},
|
||||
created: function () {
|
||||
if (/t=\d+/.test(window.location.href)) {
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
}
|
||||
let that = this;
|
||||
this.checkOffline();
|
||||
|
||||
@ -32,44 +29,15 @@ export default {
|
||||
},
|
||||
false
|
||||
);
|
||||
window.addEventListener(
|
||||
"online",
|
||||
function () {
|
||||
that.checkOffline();
|
||||
},
|
||||
false
|
||||
);
|
||||
window.addEventListener(
|
||||
"offline",
|
||||
function () {
|
||||
this.offline = true;
|
||||
},
|
||||
false
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
checkOffline: function () {
|
||||
if (!navigator.onLine) {
|
||||
this.offline = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// extra check to make sure we're not offline
|
||||
let that = this;
|
||||
const aliveCheckUrl = window.location.href + "?t=" + new Date().valueOf();
|
||||
return fetch(aliveCheckUrl, {
|
||||
return fetch(window.location.href + "?alive", {
|
||||
method: "HEAD",
|
||||
cache: "no-store",
|
||||
redirect: "manual",
|
||||
})
|
||||
.then(function (response) {
|
||||
// opaqueredirect means request has been redirected, to auth provider probably
|
||||
if (
|
||||
(response.type === "opaqueredirect" && !response.ok) ||
|
||||
[401, 403].indexOf(response.status) != -1
|
||||
) {
|
||||
window.location.href = aliveCheckUrl;
|
||||
}
|
||||
that.offline = !response.ok;
|
||||
})
|
||||
.catch(function () {
|
||||
|
@ -6,7 +6,7 @@
|
||||
<p>
|
||||
<a
|
||||
class="button is-primary mt-5 has-text-weight-bold"
|
||||
href="https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md#configuration"
|
||||
href="https://github.com/bastienwirtz/homer/blob/main/README.md#getting-started"
|
||||
target="_blank"
|
||||
>
|
||||
Get started
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<component v-bind:is="component" :item="item" :proxy="proxy"></component>
|
||||
<component
|
||||
v-bind:is="component"
|
||||
:item="item"
|
||||
:proxy="proxy"
|
||||
:forwarder="forwarder"
|
||||
></component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -10,6 +15,7 @@ export default {
|
||||
props: {
|
||||
item: Object,
|
||||
proxy: Object,
|
||||
forwarder: Object,
|
||||
},
|
||||
computed: {
|
||||
component() {
|
||||
|
@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<Generic :item="item">
|
||||
<template #indicator>
|
||||
<div class="notifs">
|
||||
<strong
|
||||
v-if="streams > 0"
|
||||
class="notif playing"
|
||||
:title="`${streams} active stream${streams > 1 ? 's' : ''}`"
|
||||
>
|
||||
{{ streams }}
|
||||
</strong>
|
||||
<i
|
||||
v-if="error"
|
||||
class="notif error fa-solid fa-triangle-exclamation"
|
||||
title="Unable to fetch current status"
|
||||
></i>
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "Tautulli",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
data: () => ({
|
||||
stats: null,
|
||||
error: false,
|
||||
}),
|
||||
computed: {
|
||||
streams: function () {
|
||||
if (!this.stats) {
|
||||
return "";
|
||||
}
|
||||
return this.stats.stream_count;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchStatus();
|
||||
},
|
||||
methods: {
|
||||
fetchStatus: async function () {
|
||||
try {
|
||||
const response = await this.fetch(
|
||||
`/api/v2?apikey=${this.item.apikey}&cmd=get_activity`
|
||||
);
|
||||
this.error = false;
|
||||
this.stats = response.response.data;
|
||||
} catch (e) {
|
||||
this.error = true;
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notifs {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
top: 0.3em;
|
||||
right: 0.5em;
|
||||
|
||||
.notif {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.35em;
|
||||
border-radius: 0.25em;
|
||||
position: relative;
|
||||
margin-left: 0.3em;
|
||||
font-size: 0.8em;
|
||||
|
||||
&.playing {
|
||||
background-color: #28a9a3;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-radius: 50%;
|
||||
aspect-ratio: 1;
|
||||
background-color: #e51111;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,154 +0,0 @@
|
||||
<template>
|
||||
<Generic :item="item">
|
||||
<template #content>
|
||||
<p class="title is-4">{{ item.name }}</p>
|
||||
<p class="subtitle is-6">
|
||||
<template v-if="item.subtitle">
|
||||
{{ item.subtitle }}
|
||||
</template>
|
||||
<template v-else-if="status">
|
||||
{{ statusMessage }}
|
||||
</template>
|
||||
</p>
|
||||
</template>
|
||||
<template #indicator>
|
||||
<div v-if="status" class="status" :class="status">
|
||||
{{ uptime }}%
|
||||
</div>
|
||||
</template>
|
||||
</Generic>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import service from "@/mixins/service.js";
|
||||
import Generic from "./Generic.vue";
|
||||
|
||||
export default {
|
||||
name: "UptimeKuma",
|
||||
mixins: [service],
|
||||
props: {
|
||||
item: Object,
|
||||
},
|
||||
components: {
|
||||
Generic,
|
||||
},
|
||||
data: () => ({
|
||||
incident: null,
|
||||
heartbeat: null,
|
||||
}),
|
||||
computed: {
|
||||
dashboard: function () {
|
||||
return this.item.slug ? this.item.slug : "default";
|
||||
},
|
||||
status: function () {
|
||||
if (!this.incident) {
|
||||
return "";
|
||||
}
|
||||
return this.incident.incident == null ? this.pageStatus : "bad";
|
||||
},
|
||||
lastHeartBeatList: function () {
|
||||
let result = {};
|
||||
|
||||
for (let id in this.heartbeat.heartbeatList) {
|
||||
let index = this.heartbeat.heartbeatList[id].length - 1;
|
||||
result[id] = this.heartbeat.heartbeatList[id][index];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
pageStatus: function () {
|
||||
if (!this.heartbeat) {
|
||||
return "";
|
||||
}
|
||||
if (Object.keys(this.heartbeat.heartbeatList).length === 0) {
|
||||
return "";
|
||||
}
|
||||
let result = "good";
|
||||
let hasUp = false;
|
||||
for (let id in this.lastHeartBeatList) {
|
||||
let beat = this.lastHeartBeatList[id];
|
||||
if (beat.status == 1) {
|
||||
hasUp = true;
|
||||
} else {
|
||||
result = "warn";
|
||||
}
|
||||
}
|
||||
if (!hasUp) {
|
||||
result = "bad";
|
||||
}
|
||||
return result;
|
||||
},
|
||||
statusMessage: function () {
|
||||
if (!this.incident) {
|
||||
return "";
|
||||
}
|
||||
if (this.incident.incident) {
|
||||
return this.incident.incident.title;
|
||||
}
|
||||
return this.pageStatus == "warn"
|
||||
? "Partially Degraded Service"
|
||||
: "All Systems Operational";
|
||||
},
|
||||
uptime: function () {
|
||||
if (!this.heartbeat) {
|
||||
return 0;
|
||||
}
|
||||
const data = Object.values(this.heartbeat.uptimeList);
|
||||
const percent = data.reduce((a, b) => a + b, 0) / data.length || 0;
|
||||
return (percent * 100).toFixed(1);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.item.url = `${this.item.url}/status/${this.dashboard}`;
|
||||
this.fetchStatus();
|
||||
},
|
||||
methods: {
|
||||
fetchStatus: function () {
|
||||
this.fetch(`/api/status-page/${this.dashboard}?cachebust=${Date.now()}`)
|
||||
.catch((e) => console.error(e))
|
||||
.then((resp) => (this.incident = resp));
|
||||
|
||||
this.fetch(
|
||||
`/api/status-page/heartbeat/${this.dashboard}?cachebust=${Date.now()}`
|
||||
)
|
||||
.catch((e) => console.error(e))
|
||||
.then((resp) => (this.heartbeat = resp));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.status {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-title);
|
||||
|
||||
&.good:before {
|
||||
background-color: #94e185;
|
||||
border-color: #78d965;
|
||||
box-shadow: 0 0 5px 1px #94e185;
|
||||
}
|
||||
|
||||
&.warn:before {
|
||||
background-color: #f8a306;
|
||||
border-color: #e1b35e;
|
||||
box-shadow: 0 0 5px 1px #f8a306;
|
||||
}
|
||||
|
||||
&.bad:before {
|
||||
background-color: #c9404d;
|
||||
border-color: #c42c3b;
|
||||
box-shadow: 0 0 5px 1px #c9404d;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #000;
|
||||
border-radius: 7px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,6 +1,9 @@
|
||||
const merge = require("lodash.merge");
|
||||
|
||||
export default {
|
||||
props: {
|
||||
proxy: Object,
|
||||
forwarder: Object,
|
||||
},
|
||||
created: function () {
|
||||
// custom service often consume info from an API using the item link (url) as a base url,
|
||||
@ -25,18 +28,28 @@ export default {
|
||||
this.item.useCredentials === true ? "include" : "omit";
|
||||
}
|
||||
|
||||
options = Object.assign(options, init);
|
||||
if (this.forwarder?.apikey) {
|
||||
options.headers = {
|
||||
"X-Homer-Forwarder-Api-Key": this.forwarder.apikey,
|
||||
};
|
||||
}
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
path = path.slice(1);
|
||||
}
|
||||
|
||||
let url = this.endpoint;
|
||||
let url = path ? `${this.endpoint}/${path}` : this.endpoint;
|
||||
|
||||
if (path) {
|
||||
url = `${this.endpoint}/${path}`;
|
||||
if (this.forwarder?.url) {
|
||||
options.headers = {
|
||||
...(options.headers || {}),
|
||||
"X-Homer-Forwarder-Url": url,
|
||||
};
|
||||
url = this.forwarder.url;
|
||||
}
|
||||
|
||||
options = merge(options, init);
|
||||
|
||||
return fetch(url, options).then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Not 2xx response");
|
||||
|
@ -26,7 +26,4 @@ module.exports = {
|
||||
msTileImage: "assets/icons/icon-any.png",
|
||||
},
|
||||
},
|
||||
devServer: {
|
||||
disableHostCheck: true,
|
||||
},
|
||||
};
|
||||
|
162
yarn.lock
162
yarn.lock
@ -2,15 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@achrinza/node-ipc@9.2.2":
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@achrinza/node-ipc/-/node-ipc-9.2.2.tgz#ae1b5d3d6a9362034eea60c8d946b93893c2e4ec"
|
||||
integrity sha512-b90U39dx0cU6emsOvy5hxU4ApNXnE3+Tuo8XQZfiKTGelDwpMwBVgBP7QX6dGTcJgu/miyJuNJ/2naFBliNWEw==
|
||||
dependencies:
|
||||
"@node-ipc/js-queue" "2.0.3"
|
||||
event-pubsub "4.3.0"
|
||||
js-message "1.0.7"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5":
|
||||
version "7.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
|
||||
@ -912,10 +903,10 @@
|
||||
"@babel/helper-validator-identifier" "^7.14.5"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@fortawesome/fontawesome-free@^6.1.1":
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1"
|
||||
integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg==
|
||||
"@fortawesome/fontawesome-free@^5.15.4":
|
||||
version "5.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz#ecda5712b61ac852c760d8b3c79c96adca5554e5"
|
||||
integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
@ -966,13 +957,6 @@
|
||||
call-me-maybe "^1.0.1"
|
||||
glob-to-regexp "^0.3.0"
|
||||
|
||||
"@node-ipc/js-queue@2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@node-ipc/js-queue/-/js-queue-2.0.3.tgz#ac7fe33d766fa53e233ef8fedaf3443a01c5a4cd"
|
||||
integrity sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==
|
||||
dependencies:
|
||||
easy-stack "1.0.1"
|
||||
|
||||
"@nodelib/fs.stat@^1.1.2":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
|
||||
@ -1189,10 +1173,10 @@
|
||||
lodash.kebabcase "^4.1.1"
|
||||
svg-tags "^1.0.0"
|
||||
|
||||
"@vue/babel-preset-app@^4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.5.17.tgz#09c64eedfe868bfa3121fc12a59138518f830bde"
|
||||
integrity sha512-iFv9J3F5VKUPcbx+TqW5qhGmAVyXQxPRpKpPOuTLFIVTzg+iwJnrqVbL4kJU5ECGDxPESW2oCVgxv9bTlDPu7w==
|
||||
"@vue/babel-preset-app@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.5.15.tgz#f6bc08f8f674e98a260004234cde18b966d72eb0"
|
||||
integrity sha512-J+YttzvwRfV1BPczf8r3qCevznYk+jh531agVF+5EYlHF4Sgh/cGXTz9qkkiux3LQgvhEGXgmCteg1n38WuuKg==
|
||||
dependencies:
|
||||
"@babel/core" "^7.11.0"
|
||||
"@babel/helper-compilation-targets" "^7.9.6"
|
||||
@ -1274,61 +1258,61 @@
|
||||
"@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
|
||||
camelcase "^5.0.0"
|
||||
|
||||
"@vue/cli-overlay@^4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.5.17.tgz#4e0e24b7c3b71ff86de86f532821fd3abb48d10c"
|
||||
integrity sha512-QKKp66VbMg+X8Qh0wgXSwgxLfxY7EIkZkV6bZ6nFqBx8xtaJQVDbTL+4zcUPPA6nygbIcQ6gvTinNEqIqX6FUQ==
|
||||
"@vue/cli-overlay@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.5.15.tgz#0700fd6bad39336d4189ba3ff7d25e638e818c9c"
|
||||
integrity sha512-0zI0kANAVmjFO2LWGUIzdGPMeE3+9k+KeRDXsUqB30YfRF7abjfiiRPq5BU9pOzlJbVdpRkisschBrvdJqDuDg==
|
||||
|
||||
"@vue/cli-plugin-babel@~4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.17.tgz#8c468e32ef6546f843201770a294bf599689e004"
|
||||
integrity sha512-6kZuc3PdoUvGAnndUq6+GqjIXn3bqdTR8lOcAb1BH2b4N7IKGlmzcipALGS23HLVMAvDgNuUS7vf0unin9j2cg==
|
||||
"@vue/cli-plugin-babel@~4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.15.tgz#ae4fb2ed54255fe3d84df381dab68509641179ed"
|
||||
integrity sha512-hBLrwYfFkHldEe34op/YNgPhpOWI5n5DB2Qt9I/1Epeif4M4iFaayrgjvOR9AVM6WbD3Yx7WCFszYpWrQZpBzQ==
|
||||
dependencies:
|
||||
"@babel/core" "^7.11.0"
|
||||
"@vue/babel-preset-app" "^4.5.17"
|
||||
"@vue/cli-shared-utils" "^4.5.17"
|
||||
"@vue/babel-preset-app" "^4.5.15"
|
||||
"@vue/cli-shared-utils" "^4.5.15"
|
||||
babel-loader "^8.1.0"
|
||||
cache-loader "^4.1.0"
|
||||
thread-loader "^2.1.3"
|
||||
webpack "^4.0.0"
|
||||
|
||||
"@vue/cli-plugin-eslint@~4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.17.tgz#7667bf87bdfdb39faeb3baed58657622354a17bc"
|
||||
integrity sha512-bVNDP+SuWcuJrBMc+JLaKvlxx25XKIlZBa+zzFnxhHZlwPZ7CeBD3e2wnsygJyPoKgDZcZwDgmEz1BZzMEjsNw==
|
||||
"@vue/cli-plugin-eslint@~4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.15.tgz#5781824a941f34c26336a67b1f6584a06c6a24ff"
|
||||
integrity sha512-/2Fl6wY/5bz3HD035oSnFRMsKNxDxU396KqBdpCQdwdvqk4mm6JAbXqihpcBRTNPeTO6w+LwGe6FE56PVbJdbg==
|
||||
dependencies:
|
||||
"@vue/cli-shared-utils" "^4.5.17"
|
||||
"@vue/cli-shared-utils" "^4.5.15"
|
||||
eslint-loader "^2.2.1"
|
||||
globby "^9.2.0"
|
||||
inquirer "^7.1.0"
|
||||
webpack "^4.0.0"
|
||||
yorkie "^2.0.0"
|
||||
|
||||
"@vue/cli-plugin-pwa@~4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-4.5.17.tgz#73b2f9dd1203de46761a9843e972966e2717fe87"
|
||||
integrity sha512-IaODWmj5eQjv97ne0CTOgPZA8QmVS7zYX64C+SivWPw0uevJAhNUdDHgyrUODP7fEfyufKliStLMQJTowohGNQ==
|
||||
"@vue/cli-plugin-pwa@~4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-4.5.15.tgz#eb800c418d96b496deec9d063a1798fe6e9c2db8"
|
||||
integrity sha512-yQzsspaIkjeQyN6btF8ATgbJFU023q1HC8uUpmiBa4QE9EyBlR8fSrKFhcJ0EmT6KnU7PMwlnOJ/OqjguFnufA==
|
||||
dependencies:
|
||||
"@vue/cli-shared-utils" "^4.5.17"
|
||||
"@vue/cli-shared-utils" "^4.5.15"
|
||||
webpack "^4.0.0"
|
||||
workbox-webpack-plugin "^4.3.1"
|
||||
|
||||
"@vue/cli-plugin-router@^4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.5.17.tgz#9de189a7a8740817cde2a4e57aade14552ff68c3"
|
||||
integrity sha512-9r9CSwqv2+39XHQPDZJ0uaTtTP7oe0Gx17m7kBhHG3FA7R7AOSk2aVzhHZmDRhzlOxjx9kQSvrOSMfUG0kV4dQ==
|
||||
"@vue/cli-plugin-router@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.5.15.tgz#1e75c8c89df42c694f143b9f1028de3cf5d61e1e"
|
||||
integrity sha512-q7Y6kP9b3k55Ca2j59xJ7XPA6x+iSRB+N4ac0ZbcL1TbInVQ4j5wCzyE+uqid40hLy4fUdlpl4X9fHJEwuVxPA==
|
||||
dependencies:
|
||||
"@vue/cli-shared-utils" "^4.5.17"
|
||||
"@vue/cli-shared-utils" "^4.5.15"
|
||||
|
||||
"@vue/cli-plugin-vuex@^4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.17.tgz#eb6f597c775f3c847bf5a638ad65a0d03c11dcbf"
|
||||
integrity sha512-ck/ju2T2dmPKLWK/5QctNJs9SCb+eSZbbmr8neFkMc7GlbXw6qLWw5v3Vpd4KevdQA8QuQOA1pjUmzpCiU/mYQ==
|
||||
"@vue/cli-plugin-vuex@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.15.tgz#466c1f02777d02fef53a9bb49a36cc3a3bcfec4e"
|
||||
integrity sha512-fqap+4HN+w+InDxlA3hZTOGE0tzBTgXhKLoDydhywqgmhQ1D9JA6Feh94ze6tG8DsWX58/ujYUqA8jAz17FJtg==
|
||||
|
||||
"@vue/cli-service@~4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.5.17.tgz#6f796056363b70b69065d95815ac170b7772d0c6"
|
||||
integrity sha512-MqfkRYIcIUACe3nYlzNrYstJTWRXHlIqh6JCkbWbdnXWN+IfaVdlG8zw5Q0DVcSdGvkevUW7zB4UhtZB4uyAcA==
|
||||
"@vue/cli-service@~4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.5.15.tgz#0e9a186d51550027d0e68e95042077eb4d115b45"
|
||||
integrity sha512-sFWnLYVCn4zRfu45IcsIE9eXM0YpDV3S11vlM2/DVbIPAGoYo5ySpSof6aHcIvkeGsIsrHFpPHzNvDZ/efs7jA==
|
||||
dependencies:
|
||||
"@intervolga/optimize-cssnano-plugin" "^1.0.5"
|
||||
"@soda/friendly-errors-webpack-plugin" "^1.7.1"
|
||||
@ -1336,10 +1320,10 @@
|
||||
"@types/minimist" "^1.2.0"
|
||||
"@types/webpack" "^4.0.0"
|
||||
"@types/webpack-dev-server" "^3.11.0"
|
||||
"@vue/cli-overlay" "^4.5.17"
|
||||
"@vue/cli-plugin-router" "^4.5.17"
|
||||
"@vue/cli-plugin-vuex" "^4.5.17"
|
||||
"@vue/cli-shared-utils" "^4.5.17"
|
||||
"@vue/cli-overlay" "^4.5.15"
|
||||
"@vue/cli-plugin-router" "^4.5.15"
|
||||
"@vue/cli-plugin-vuex" "^4.5.15"
|
||||
"@vue/cli-shared-utils" "^4.5.15"
|
||||
"@vue/component-compiler-utils" "^3.1.2"
|
||||
"@vue/preload-webpack-plugin" "^1.1.0"
|
||||
"@vue/web-component-wrapper" "^1.2.0"
|
||||
@ -1388,17 +1372,17 @@
|
||||
optionalDependencies:
|
||||
vue-loader-v16 "npm:vue-loader@^16.1.0"
|
||||
|
||||
"@vue/cli-shared-utils@^4.5.17":
|
||||
version "4.5.17"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.5.17.tgz#bb4aac8b816036cf5c0adf3af3cc1cb9c425501e"
|
||||
integrity sha512-VoFNdxvTW4vZu3ne+j1Mf7mU99J2SAoRVn9XPrsouTUUJablglM8DASk7Ixhsh6ymyL/W9EADQFR6Pgj8Ujjuw==
|
||||
"@vue/cli-shared-utils@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.5.15.tgz#dba3858165dbe3465755f256a4890e69084532d6"
|
||||
integrity sha512-SKaej9hHzzjKSOw1NlFmc6BSE0vcqUQMQiv1cxQ2DhVyy4QxZXBmzmiLBUBe+hYZZs1neXW7n//udeN9bCAY+Q==
|
||||
dependencies:
|
||||
"@achrinza/node-ipc" "9.2.2"
|
||||
"@hapi/joi" "^15.0.1"
|
||||
chalk "^2.4.2"
|
||||
execa "^1.0.0"
|
||||
launch-editor "^2.2.1"
|
||||
lru-cache "^5.1.1"
|
||||
node-ipc "^9.1.1"
|
||||
open "^6.3.0"
|
||||
ora "^3.4.0"
|
||||
read-pkg "^5.1.1"
|
||||
@ -1839,9 +1823,9 @@ async-limiter@~1.0.0:
|
||||
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
|
||||
|
||||
async@^2.6.2:
|
||||
version "2.6.4"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
|
||||
integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
|
||||
dependencies:
|
||||
lodash "^4.17.14"
|
||||
|
||||
@ -2226,10 +2210,10 @@ builtin-status-codes@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||
|
||||
bulma@^0.9.4:
|
||||
version "0.9.4"
|
||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.4.tgz#0ca8aeb1847a34264768dba26a064c8be72674a1"
|
||||
integrity sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==
|
||||
bulma@^0.9.3:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.3.tgz#ddccb7436ebe3e21bf47afe01d3c43a296b70243"
|
||||
integrity sha512-0d7GNW1PY4ud8TWxdNcP6Cc8Bu7MxcntD/RRLGWuiw/s0a9P+XlH/6QoOIrmbj6o8WWJzJYhytiu9nFjTszk1g==
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
@ -2789,10 +2773,10 @@ core-js@^2.4.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
||||
|
||||
core-js@^3.22.7:
|
||||
version "3.22.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.7.tgz#8d6c37f630f6139b8732d10f2c114c3f1d00024f"
|
||||
integrity sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==
|
||||
core-js@^3.21.1:
|
||||
version "3.21.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94"
|
||||
integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==
|
||||
|
||||
core-js@^3.6.5:
|
||||
version "3.15.2"
|
||||
@ -3355,7 +3339,7 @@ duplexify@^3.4.2, duplexify@^3.6.0:
|
||||
readable-stream "^2.0.0"
|
||||
stream-shift "^1.0.0"
|
||||
|
||||
easy-stack@1.0.1:
|
||||
easy-stack@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066"
|
||||
integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==
|
||||
@ -3678,9 +3662,9 @@ events@^3.0.0:
|
||||
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
||||
|
||||
eventsource@^1.0.7:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.1.tgz#4544a35a57d7120fba4fa4c86cb4023b2c09df2f"
|
||||
integrity sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf"
|
||||
integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==
|
||||
dependencies:
|
||||
original "^1.0.0"
|
||||
|
||||
@ -5082,6 +5066,13 @@ js-message@1.0.7:
|
||||
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
|
||||
integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==
|
||||
|
||||
js-queue@2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/js-queue/-/js-queue-2.0.2.tgz#0be590338f903b36c73d33c31883a821412cd482"
|
||||
integrity sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==
|
||||
dependencies:
|
||||
easy-stack "^1.0.1"
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
@ -5754,6 +5745,15 @@ node-forge@^0.10.0:
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
||||
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
|
||||
|
||||
node-ipc@^9.1.1:
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-ipc/-/node-ipc-9.2.1.tgz#b32f66115f9d6ce841dc4ec2009d6a733f98bb6b"
|
||||
integrity sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ==
|
||||
dependencies:
|
||||
event-pubsub "4.3.0"
|
||||
js-message "1.0.7"
|
||||
js-queue "2.0.2"
|
||||
|
||||
node-libs-browser@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
|
||||
|
Reference in New Issue
Block a user