aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/integration.yml2
-rw-r--r--Dockerfile2
-rw-r--r--docs/configuration.md1
-rw-r--r--docs/customservices.md2
-rw-r--r--package.json14
-rw-r--r--src/App.vue2
-rw-r--r--src/components/SearchInput.vue4
-rw-r--r--src/components/services/AdGuardHome.vue3
-rw-r--r--src/components/services/Mealie.vue106
-rw-r--r--src/components/services/Medusa.vue142
-rw-r--r--src/components/services/PaperlessNG.vue79
-rw-r--r--src/components/services/PiHole.vue85
-rw-r--r--src/components/services/Radarr.vue137
-rw-r--r--src/components/services/Sonarr.vue140
-rw-r--r--yarn.lock90
15 files changed, 304 insertions, 505 deletions
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 196113d..8d1a7ad 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -1,7 +1,7 @@
1# 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 1# 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
2# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 2# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 3
4name: Node.js CI 4name: Integration
5 5
6on: 6on:
7 push: 7 push:
diff --git a/Dockerfile b/Dockerfile
index e31d97d..0a43027 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,7 @@ COPY . .
10RUN yarn build 10RUN yarn build
11 11
12# production stage 12# production stage
13FROM alpine:3.11 13FROM alpine:3.15
14 14
15ENV USER darkhttpd 15ENV USER darkhttpd
16ENV GROUP darkhttpd 16ENV GROUP darkhttpd
diff --git a/docs/configuration.md b/docs/configuration.md
index e2b5506..552b22a 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -29,7 +29,6 @@ connectivityCheck: true # whether you want to display a message when the apps ar
29 29
30# Optional: Proxy / hosting option 30# Optional: Proxy / hosting option
31proxy: 31proxy:
32 # NOT All custom services implements this new option YET. Support will be extended very soon.
33 useCredentials: false # send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level. 32 useCredentials: false # send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level.
34 33
35# Optional theming 34# Optional theming
diff --git a/docs/customservices.md b/docs/customservices.md
index 311a4f2..7d47542 100644
--- a/docs/customservices.md
+++ b/docs/customservices.md
@@ -18,8 +18,6 @@ If you experiencing any issue, please have a look to the [troubleshooting](troub
18 type: "<type>" 18 type: "<type>"
19``` 19```
20 20
21⚠️🚧 `endpoint` & `useCredentials` new options are not yet supported by all custom services (but will be very soon).
22
23## PiHole 21## PiHole
24 22
25Using the PiHole service you can display info about your local PiHole instance right on your Homer dashboard. 23Using the PiHole service you can display info about your local PiHole instance right on your Homer dashboard.
diff --git a/package.json b/package.json
index c5486bb..8c8f219 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,6 @@
1{ 1{
2 "name": "homer", 2 "name": "homer",
3 "version": "21.09.1", 3 "version": "21.09.1",
4 "license": "Apache-2.0",
5 "scripts": { 4 "scripts": {
6 "serve": "vue-cli-service serve", 5 "serve": "vue-cli-service serve",
7 "build": "vue-cli-service build", 6 "build": "vue-cli-service build",
@@ -10,17 +9,17 @@
10 "dependencies": { 9 "dependencies": {
11 "@fortawesome/fontawesome-free": "^5.15.4", 10 "@fortawesome/fontawesome-free": "^5.15.4",
12 "bulma": "^0.9.3", 11 "bulma": "^0.9.3",
13 "core-js": "^3.17.3", 12 "core-js": "^3.19.3",
14 "js-yaml": "^4.1.0", 13 "js-yaml": "^4.1.0",
15 "lodash.merge": "^4.6.2", 14 "lodash.merge": "^4.6.2",
16 "register-service-worker": "^1.7.2", 15 "register-service-worker": "^1.7.2",
17 "vue": "^2.6.14" 16 "vue": "^2.6.14"
18 }, 17 },
19 "devDependencies": { 18 "devDependencies": {
20 "@vue/cli-plugin-babel": "~4.5.0", 19 "@vue/cli-plugin-babel": "~4.5.15",
21 "@vue/cli-plugin-eslint": "~4.5.0", 20 "@vue/cli-plugin-eslint": "~4.5.15",
22 "@vue/cli-plugin-pwa": "~4.5.0", 21 "@vue/cli-plugin-pwa": "~4.5.15",
23 "@vue/cli-service": "~4.5.0", 22 "@vue/cli-service": "~4.5.15",
24 "@vue/eslint-config-prettier": "^6.0.0", 23 "@vue/eslint-config-prettier": "^6.0.0",
25 "babel-eslint": "^10.1.0", 24 "babel-eslint": "^10.1.0",
26 "eslint": "^6.7.2", 25 "eslint": "^6.7.2",
@@ -31,5 +30,6 @@
31 "sass": "^1.26.5", 30 "sass": "^1.26.5",
32 "sass-loader": "^8.0.2", 31 "sass-loader": "^8.0.2",
33 "vue-template-compiler": "^2.6.12" 32 "vue-template-compiler": "^2.6.12"
34 } 33 },
34 "license": "Apache-2.0"
35} 35}
diff --git a/src/App.vue b/src/App.vue
index 5c62a7f..4eb112d 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -41,7 +41,7 @@
41 41
42 <SearchInput 42 <SearchInput
43 class="navbar-item is-inline-block-mobile" 43 class="navbar-item is-inline-block-mobile"
44 :hotkey=searchHotkey() 44 :hotkey="searchHotkey()"
45 @input="filterServices" 45 @input="filterServices"
46 @search-focus="showMenu = true" 46 @search-focus="showMenu = true"
47 @search-open="navigateToFirstService" 47 @search-open="navigateToFirstService"
diff --git a/src/components/SearchInput.vue b/src/components/SearchInput.vue
index 586ff71..165c992 100644
--- a/src/components/SearchInput.vue
+++ b/src/components/SearchInput.vue
@@ -19,8 +19,8 @@ export default {
19 value: String, 19 value: String,
20 hotkey: { 20 hotkey: {
21 type: String, 21 type: String,
22 default: "/" 22 default: "/",
23 } 23 },
24 }, 24 },
25 mounted() { 25 mounted() {
26 this._keyListener = function (event) { 26 this._keyListener = function (event) {
diff --git a/src/components/services/AdGuardHome.vue b/src/components/services/AdGuardHome.vue
index b01f0f4..4c53398 100644
--- a/src/components/services/AdGuardHome.vue
+++ b/src/components/services/AdGuardHome.vue
@@ -76,9 +76,6 @@ export default {
76</script> 76</script>
77 77
78<style scoped lang="scss"> 78<style scoped lang="scss">
79.media-left img {
80 max-height: 100%;
81}
82.status { 79.status {
83 font-size: 0.8rem; 80 font-size: 0.8rem;
84 color: var(--text-title); 81 color: var(--text-title);
diff --git a/src/components/services/Mealie.vue b/src/components/services/Mealie.vue
index 790a9b1..b5b2255 100644
--- a/src/components/services/Mealie.vue
+++ b/src/components/services/Mealie.vue
@@ -1,47 +1,33 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #content>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <p class="title is-4">{{ item.name }}</p>
5 <div class="card-content"> 5 <p class="subtitle is-6">
6 <div class="media"> 6 <template v-if="item.subtitle">
7 <div v-if="item.logo" class="media-left"> 7 {{ item.subtitle }}
8 <figure class="image is-48x48"> 8 </template>
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 <template v-else-if="meal"> Today: {{ meal.name }} </template>
10 </figure> 10 <template v-else-if="stats">
11 </div> 11 happily keeping {{ stats.totalRecipes }} recipes organized
12 <div v-if="item.icon" class="media-left"> 12 </template>
13 <figure class="image is-48x48"> 13 </p>
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 </template>
15 </figure> 15 </Generic>
16 </div>
17 <div class="media-content">
18 <p class="title is-4">{{ item.name }}</p>
19 <p class="subtitle is-6">
20 <template v-if="item.subtitle">
21 {{ item.subtitle }}
22 </template>
23 <template v-else-if="meal"> Today: {{ meal.name }} </template>
24 <template v-else-if="stats">
25 happily keeping {{ stats.totalRecipes }} recipes organized
26 </template>
27 </p>
28 </div>
29 </div>
30 <div class="tag" :class="item.tagstyle" v-if="item.tag">
31 <strong class="tag-text">#{{ item.tag }}</strong>
32 </div>
33 </div>
34 </a>
35 </div>
36 </div>
37</template> 16</template>
38 17
39<script> 18<script>
19import service from "@/mixins/service.js";
20import Generic from "./Generic.vue";
21
40export default { 22export default {
41 name: "Mealie", 23 name: "Mealie",
24 mixins: [service],
42 props: { 25 props: {
43 item: Object, 26 item: Object,
44 }, 27 },
28 components: {
29 Generic,
30 },
45 data: () => ({ 31 data: () => ({
46 stats: null, 32 stats: null,
47 meal: null, 33 meal: null,
@@ -51,44 +37,20 @@ export default {
51 }, 37 },
52 methods: { 38 methods: {
53 fetchStatus: async function () { 39 fetchStatus: async function () {
54 if (this.item.subtitle != null) return; // omitting unnecessary ajax call as the subtitle is showing 40 const headers = {
55 this.meal = await fetch(`${this.item.url}/api/meal-plans/today/`, { 41 Authorization: "Bearer " + this.item.apikey,
56 headers: { 42 Accept: "application/json",
57 Authorization: "Bearer " + this.item.apikey, 43 };
58 Accept: "application/json", 44
59 }, 45 if (this.item.subtitle != null) return;
60 }) 46
61 .then(function (response) { 47 this.meal = await this.fetch("/api/meal-plans/today/", { headers }).catch(
62 if (!response.ok) { 48 (e) => console.log(e)
63 throw new Error("Not 2xx response"); 49 );
64 } else { 50 this.stats = await this.fetch("/api/debug/statistics/", {
65 if (response != null) { 51 headers,
66 return response.json(); 52 }).catch((e) => console.log(e));
67 }
68 }
69 })
70 .catch((e) => console.log(e));
71 this.stats = await fetch(`${this.item.url}/api/debug/statistics/`, {
72 headers: {
73 Authorization: "Bearer " + this.item.apikey,
74 Accept: "application/json",
75 },
76 })
77 .then(function (response) {
78 if (!response.ok) {
79 throw new Error("Not 2xx response");
80 } else {
81 return response.json();
82 }
83 })
84 .catch((e) => console.log(e));
85 }, 53 },
86 }, 54 },
87}; 55};
88</script> 56</script>
89
90<style scoped lang="scss">
91.media-left img {
92 max-height: 100%;
93}
94</style>
diff --git a/src/components/services/Medusa.vue b/src/components/services/Medusa.vue
index 5720649..43b5651 100644
--- a/src/components/services/Medusa.vue
+++ b/src/components/services/Medusa.vue
@@ -1,65 +1,49 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #indicator>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <div class="notifs">
5 <div class="card-content"> 5 <strong
6 <div class="media"> 6 v-if="config !== null && config.system.news.unread > 0"
7 <div v-if="item.logo" class="media-left"> 7 class="notif news"
8 <figure class="image is-48x48"> 8 title="News"
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 >{{ config.system.news.unread }}</strong
10 </figure> 10 >
11 </div> 11 <strong
12 <div v-if="item.icon" class="media-left"> 12 v-if="config !== null && config.main.logs.numWarnings > 0"
13 <figure class="image is-48x48"> 13 class="notif warnings"
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 title="Warning"
15 </figure> 15 >{{ config.main.logs.numWarnings }}</strong
16 </div> 16 >
17 <div class="media-content"> 17 <strong
18 <p class="title is-4">{{ item.name }}</p> 18 v-if="config !== null && config.main.logs.numErrors > 0"
19 <p class="subtitle is-6">{{ item.subtitle }}</p> 19 class="notif errors"
20 </div> 20 title="Error"
21 <div class="notifs"> 21 >{{ config.main.logs.numErrors }}</strong
22 <strong 22 >
23 v-if="config !== null && config.system.news.unread > 0" 23 <strong
24 class="notif news" 24 v-if="serverError"
25 title="News" 25 class="notif errors"
26 >{{ config.system.news.unread }}</strong 26 title="Connection error to Medusa API, check url and apikey in config.yml"
27 > 27 >?</strong
28 <strong 28 >
29 v-if="config !== null && config.main.logs.numWarnings > 0" 29 </div>
30 class="notif warnings" 30 </template>
31 title="Warning" 31 </Generic>
32 >{{ config.main.logs.numWarnings }}</strong
33 >
34 <strong
35 v-if="config !== null && config.main.logs.numErrors > 0"
36 class="notif errors"
37 title="Error"
38 >{{ config.main.logs.numErrors }}</strong
39 >
40 <strong
41 v-if="serverError"
42 class="notif errors"
43 title="Connection error to Medusa API, check url and apikey in config.yml"
44 >?</strong
45 >
46 </div>
47 </div>
48 <div class="tag" :class="item.tagstyle" v-if="item.tag">
49 <strong class="tag-text">#{{ item.tag }}</strong>
50 </div>
51 </div>
52 </a>
53 </div>
54 </div>
55</template> 32</template>
56 33
57<script> 34<script>
35import service from "@/mixins/service.js";
36import Generic from "./Generic.vue";
37
58export default { 38export default {
59 name: "Medusa", 39 name: "Medusa",
40 mixins: [service],
60 props: { 41 props: {
61 item: Object, 42 item: Object,
62 }, 43 },
44 components: {
45 Generic,
46 },
63 data: () => { 47 data: () => {
64 return { 48 return {
65 config: null, 49 config: null,
@@ -71,16 +55,9 @@ export default {
71 }, 55 },
72 methods: { 56 methods: {
73 fetchConfig: function () { 57 fetchConfig: function () {
74 fetch(`${this.item.url}/api/v2/config`, { 58 this.fetch("/api/v2/config", {
75 credentials: "include", 59 headers: { "X-Api-Key": this.item.apikey },
76 headers: { "X-Api-Key": `${this.item.apikey}` },
77 }) 60 })
78 .then((response) => {
79 if (response.status != 200) {
80 throw new Error(response.statusText);
81 }
82 return response.json();
83 })
84 .then((conf) => { 61 .then((conf) => {
85 this.config = conf; 62 this.config = conf;
86 }) 63 })
@@ -94,35 +71,32 @@ export default {
94</script> 71</script>
95 72
96<style scoped lang="scss"> 73<style scoped lang="scss">
97.media-left img {
98 max-height: 100%;
99}
100.notifs { 74.notifs {
101 position: absolute; 75 position: absolute;
102 color: white; 76 color: white;
103 font-family: sans-serif; 77 font-family: sans-serif;
104 top: 0.3em; 78 top: 0.3em;
105 right: 0.5em; 79 right: 0.5em;
106} 80 .notif {
107.notif { 81 padding-right: 0.35em;
108 padding-right: 0.35em; 82 padding-left: 0.35em;
109 padding-left: 0.35em; 83 padding-top: 0.2em;
110 padding-top: 0.2em; 84 padding-bottom: 0.2em;
111 padding-bottom: 0.2em; 85 border-radius: 0.25em;
112 border-radius: 0.25em; 86 position: relative;
113 position: relative; 87 margin-left: 0.3em;
114 margin-left: 0.3em; 88 font-size: 0.8em;
115 font-size: 0.8em; 89 &.news {
116} 90 background-color: #777777;
117.news { 91 }
118 background-color: #777777;
119}
120 92
121.warnings { 93 &.warnings {
122 background-color: #d08d2e; 94 background-color: #d08d2e;
123} 95 }
124 96
125.errors { 97 &.errors {
126 background-color: #e51111; 98 background-color: #e51111;
99 }
100 }
127} 101}
128</style> 102</style>
diff --git a/src/components/services/PaperlessNG.vue b/src/components/services/PaperlessNG.vue
index af13317..69f2437 100644
--- a/src/components/services/PaperlessNG.vue
+++ b/src/components/services/PaperlessNG.vue
@@ -1,46 +1,32 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #content>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <p class="title is-4">{{ item.name }}</p>
5 <div class="card-content"> 5 <p class="subtitle is-6">
6 <div class="media"> 6 <template v-if="item.subtitle">
7 <div v-if="item.logo" class="media-left"> 7 {{ item.subtitle }}
8 <figure class="image is-48x48"> 8 </template>
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 <template v-else-if="api">
10 </figure> 10 happily storing {{ api.count }} documents
11 </div> 11 </template>
12 <div v-if="item.icon" class="media-left"> 12 </p>
13 <figure class="image is-48x48"> 13 </template>
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 </Generic>
15 </figure>
16 </div>
17 <div class="media-content">
18 <p class="title is-4">{{ item.name }}</p>
19 <p class="subtitle is-6">
20 <template v-if="item.subtitle">
21 {{ item.subtitle }}
22 </template>
23 <template v-else-if="api">
24 happily storing {{ api.count }} documents
25 </template>
26 </p>
27 </div>
28 </div>
29 <div class="tag" :class="item.tagstyle" v-if="item.tag">
30 <strong class="tag-text">#{{ item.tag }}</strong>
31 </div>
32 </div>
33 </a>
34 </div>
35 </div>
36</template> 15</template>
37 16
38<script> 17<script>
18import service from "@/mixins/service.js";
19import Generic from "./Generic.vue";
20
39export default { 21export default {
40 name: "Paperless", 22 name: "Paperless",
23 mixins: [service],
41 props: { 24 props: {
42 item: Object, 25 item: Object,
43 }, 26 },
27 components: {
28 Generic,
29 },
44 data: () => ({ 30 data: () => ({
45 api: null, 31 api: null,
46 }), 32 }),
@@ -49,36 +35,21 @@ export default {
49 }, 35 },
50 methods: { 36 methods: {
51 fetchStatus: async function () { 37 fetchStatus: async function () {
52 if (this.item.subtitle != null) return; // omitting unnecessary ajax call as the subtitle is showing 38 if (this.item.subtitle != null) return;
53 var apikey = this.item.apikey; 39
40 const apikey = this.item.apikey;
54 if (!apikey) { 41 if (!apikey) {
55 console.error( 42 console.error(
56 "apikey is not present in config.yml for the paperless entry!" 43 "apikey is not present in config.yml for the paperless entry!"
57 ); 44 );
58 return; 45 return;
59 } 46 }
60 const url = `${this.item.url}/api/documents/`; 47 this.api = await this.fetch("/api/documents/", {
61 this.api = await fetch(url, {
62 credentials: "include",
63 headers: { 48 headers: {
64 Authorization: "Token " + this.item.apikey, 49 Authorization: "Token " + this.item.apikey,
65 }, 50 },
66 }) 51 }).catch((e) => console.log(e));
67 .then(function (response) {
68 if (!response.ok) {
69 throw new Error("Not 2xx response");
70 } else {
71 return response.json();
72 }
73 })
74 .catch((e) => console.log(e));
75 }, 52 },
76 }, 53 },
77}; 54};
78</script> 55</script>
79
80<style scoped lang="scss">
81.media-left img {
82 max-height: 100%;
83}
84</style>
diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue
index 87f7090..9aac016 100644
--- a/src/components/services/PiHole.vue
+++ b/src/components/services/PiHole.vue
@@ -1,59 +1,45 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #content>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <p class="title is-4">{{ item.name }}</p>
5 <div class="card-content"> 5 <p class="subtitle is-6">
6 <div class="media"> 6 <template v-if="item.subtitle">
7 <div v-if="item.logo" class="media-left"> 7 {{ item.subtitle }}
8 <figure class="image is-48x48"> 8 </template>
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 <template v-else-if="percentage">
10 </figure> 10 {{ percentage }}&percnt; blocked
11 </div> 11 </template>
12 <div v-if="item.icon" class="media-left"> 12 </p>
13 <figure class="image is-48x48"> 13 </template>
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 <template #indicator>
15 </figure> 15 <div v-if="status" class="status" :class="status">
16 </div> 16 {{ status }}
17 <div class="media-content"> 17 </div>
18 <p class="title is-4">{{ item.name }}</p> 18 </template>
19 <p class="subtitle is-6"> 19 </Generic>
20 <template v-if="item.subtitle">
21 {{ item.subtitle }}
22 </template>
23 <template v-else-if="api">
24 {{ percentage }}&percnt; blocked
25 </template>
26 </p>
27 </div>
28 <div v-if="api" class="status" :class="api.status">
29 {{ api.status }}
30 </div>
31 </div>
32 <div class="tag" :class="item.tagstyle" v-if="item.tag">
33 <strong class="tag-text">#{{ item.tag }}</strong>
34 </div>
35 </div>
36 </a>
37 </div>
38 </div>
39</template> 20</template>
40 21
41<script> 22<script>
23import service from "@/mixins/service.js";
24import Generic from "./Generic.vue";
25
42export default { 26export default {
43 name: "PiHole", 27 name: "PiHole",
28 mixins: [service],
44 props: { 29 props: {
45 item: Object, 30 item: Object,
46 }, 31 },
32 components: {
33 Generic,
34 },
47 data: () => ({ 35 data: () => ({
48 api: { 36 status: "",
49 status: "", 37 ads_percentage_today: 0,
50 ads_percentage_today: 0,
51 },
52 }), 38 }),
53 computed: { 39 computed: {
54 percentage: function () { 40 percentage: function () {
55 if (this.api) { 41 if (this.ads_percentage_today) {
56 return this.api.ads_percentage_today.toFixed(1); 42 return this.ads_percentage_today.toFixed(1);
57 } 43 }
58 return ""; 44 return "";
59 }, 45 },
@@ -63,21 +49,16 @@ export default {
63 }, 49 },
64 methods: { 50 methods: {
65 fetchStatus: async function () { 51 fetchStatus: async function () {
66 const url = `${this.item.url}/api.php`; 52 const result = await this.fetch("/api.php").catch((e) => console.log(e));
67 this.api = await fetch(url, { 53
68 credentials: "include", 54 this.status = result.status;
69 }) 55 this.ads_percentage_today = result.ads_percentage_today;
70 .then((response) => response.json())
71 .catch((e) => console.log(e));
72 }, 56 },
73 }, 57 },
74}; 58};
75</script> 59</script>
76 60
77<style scoped lang="scss"> 61<style scoped lang="scss">
78.media-left img {
79 max-height: 100%;
80}
81.status { 62.status {
82 font-size: 0.8rem; 63 font-size: 0.8rem;
83 color: var(--text-title); 64 color: var(--text-title);
diff --git a/src/components/services/Radarr.vue b/src/components/services/Radarr.vue
index a9cdedf..a57c895 100644
--- a/src/components/services/Radarr.vue
+++ b/src/components/services/Radarr.vue
@@ -1,62 +1,40 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #indicator>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <div class="notifs">
5 <div class="card-content"> 5 <strong v-if="activity > 0" class="notif activity" title="Activity">
6 <div class="media"> 6 {{ activity }}
7 <div v-if="item.logo" class="media-left"> 7 </strong>
8 <figure class="image is-48x48"> 8 <strong v-if="warnings > 0" class="notif warnings" title="Warning">
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 {{ warnings }}
10 </figure> 10 </strong>
11 </div> 11 <strong v-if="errors > 0" class="notif errors" title="Error">
12 <div v-if="item.icon" class="media-left"> 12 {{ errors }}
13 <figure class="image is-48x48"> 13 </strong>
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 <strong
15 </figure> 15 v-if="serverError"
16 </div> 16 class="notif errors"
17 <div class="media-content"> 17 title="Connection error to Radarr API, check url and apikey in config.yml"
18 <p class="title is-4">{{ item.name }}</p> 18 >?</strong
19 <p class="subtitle is-6">{{ item.subtitle }}</p> 19 >
20 </div> 20 </div>
21 <div class="notifs"> 21 </template>
22 <strong 22 </Generic>
23 v-if="activity > 0"
24 class="notif activity"
25 title="Activity"
26 >{{ activity }}</strong
27 >
28 <strong
29 v-if="warnings > 0"
30 class="notif warnings"
31 title="Warning"
32 >{{ warnings }}</strong
33 >
34 <strong v-if="errors > 0" class="notif errors" title="Error">{{
35 errors
36 }}</strong>
37 <strong
38 v-if="serverError"
39 class="notif errors"
40 title="Connection error to Radarr API, check url and apikey in config.yml"
41 >?</strong
42 >
43 </div>
44 </div>
45 <div class="tag" :class="item.tagstyle" v-if="item.tag">
46 <strong class="tag-text">#{{ item.tag }}</strong>
47 </div>
48 </div>
49 </a>
50 </div>
51 </div>
52</template> 23</template>
53 24
54<script> 25<script>
26import service from "@/mixins/service.js";
27import Generic from "./Generic.vue";
28
55export default { 29export default {
56 name: "Radarr", 30 name: "Radarr",
31 mixins: [service],
57 props: { 32 props: {
58 item: Object, 33 item: Object,
59 }, 34 },
35 components: {
36 Generic,
37 },
60 data: () => { 38 data: () => {
61 return { 39 return {
62 activity: null, 40 activity: null,
@@ -70,15 +48,7 @@ export default {
70 }, 48 },
71 methods: { 49 methods: {
72 fetchConfig: function () { 50 fetchConfig: function () {
73 fetch(`${this.item.url}/api/health?apikey=${this.item.apikey}`, { 51 this.fetch(`/api/health?apikey=${this.item.apikey}`)
74 credentials: "include",
75 })
76 .then((response) => {
77 if (response.status != 200) {
78 throw new Error(response.statusText);
79 }
80 return response.json();
81 })
82 .then((health) => { 52 .then((health) => {
83 this.warnings = 0; 53 this.warnings = 0;
84 this.errors = 0; 54 this.errors = 0;
@@ -94,15 +64,7 @@ export default {
94 console.error(e); 64 console.error(e);
95 this.serverError = true; 65 this.serverError = true;
96 }); 66 });
97 fetch(`${this.item.url}/api/queue?apikey=${this.item.apikey}`, { 67 this.fetch(`/api/queue?apikey=${this.item.apikey}`)
98 credentials: "include",
99 })
100 .then((response) => {
101 if (response.status != 200) {
102 throw new Error(response.statusText);
103 }
104 return response.json();
105 })
106 .then((queue) => { 68 .then((queue) => {
107 this.activity = 0; 69 this.activity = 0;
108 for (var i = 0; i < queue.length; i++) { 70 for (var i = 0; i < queue.length; i++) {
@@ -121,35 +83,30 @@ export default {
121</script> 83</script>
122 84
123<style scoped lang="scss"> 85<style scoped lang="scss">
124.media-left img {
125 max-height: 100%;
126}
127.notifs { 86.notifs {
128 position: absolute; 87 position: absolute;
129 color: white; 88 color: white;
130 font-family: sans-serif; 89 font-family: sans-serif;
131 top: 0.3em; 90 top: 0.3em;
132 right: 0.5em; 91 right: 0.5em;
133} 92 .notif {
134.notif { 93 display: inline-block;
135 padding-right: 0.35em; 94 padding: 0.2em 0.35em;
136 padding-left: 0.35em; 95 border-radius: 0.25em;
137 padding-top: 0.2em; 96 position: relative;
138 padding-bottom: 0.2em; 97 margin-left: 0.3em;
139 border-radius: 0.25em; 98 font-size: 0.8em;
140 position: relative; 99 &.activity {
141 margin-left: 0.3em; 100 background-color: #4fb5d6;
142 font-size: 0.8em; 101 }
143}
144.activity {
145 background-color: #4fb5d6;
146}
147 102
148.warnings { 103 &.warnings {
149 background-color: #d08d2e; 104 background-color: #d08d2e;
150} 105 }
151 106
152.errors { 107 &.errors {
153 background-color: #e51111; 108 background-color: #e51111;
109 }
110 }
154} 111}
155</style> 112</style>
diff --git a/src/components/services/Sonarr.vue b/src/components/services/Sonarr.vue
index 0270255..f8dd0d1 100644
--- a/src/components/services/Sonarr.vue
+++ b/src/components/services/Sonarr.vue
@@ -1,62 +1,41 @@
1<template> 1<template>
2 <div> 2 <Generic :item="item">
3 <div class="card" :class="item.class"> 3 <template #indicator>
4 <a :href="item.url" :target="item.target" rel="noreferrer"> 4 <div class="notifs">
5 <div class="card-content"> 5 <strong v-if="activity > 0" class="notif activity" title="Activity">
6 <div class="media"> 6 {{ activity }}
7 <div v-if="item.logo" class="media-left"> 7 </strong>
8 <figure class="image is-48x48"> 8 <strong v-if="warnings > 0" class="notif warnings" title="Warning">
9 <img :src="item.logo" :alt="`${item.name} logo`" /> 9 {{ warnings }}
10 </figure> 10 </strong>
11 </div> 11 <strong v-if="errors > 0" class="notif errors" title="Error">
12 <div v-if="item.icon" class="media-left"> 12 {{ errors }}
13 <figure class="image is-48x48"> 13 </strong>
14 <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> 14 <strong
15 </figure> 15 v-if="serverError"
16 </div> 16 class="notif errors"
17 <div class="media-content"> 17 title="Connection error to Sonarr API, check url and apikey in config.yml"
18 <p class="title is-4">{{ item.name }}</p> 18 >
19 <p class="subtitle is-6">{{ item.subtitle }}</p> 19 ?
20 </div> 20 </strong>
21 <div class="notifs"> 21 </div>
22 <strong 22 </template>
23 v-if="activity > 0" 23 </Generic>
24 class="notif activity"
25 title="Activity"
26 >{{ activity }}</strong
27 >
28 <strong
29 v-if="warnings > 0"
30 class="notif warnings"
31 title="Warning"
32 >{{ warnings }}</strong
33 >
34 <strong v-if="errors > 0" class="notif errors" title="Error">{{
35 errors
36 }}</strong>
37 <strong
38 v-if="serverError"
39 class="notif errors"
40 title="Connection error to Sonarr API, check url and apikey in config.yml"
41 >?</strong
42 >
43 </div>
44 </div>
45 <div class="tag" :class="item.tagstyle" v-if="item.tag">
46 <strong class="tag-text">#{{ item.tag }}</strong>
47 </div>
48 </div>
49 </a>
50 </div>
51 </div>
52</template> 24</template>
53 25
54<script> 26<script>
27import service from "@/mixins/service.js";
28import Generic from "./Generic.vue";
29
55export default { 30export default {
56 name: "Sonarr", 31 name: "Sonarr",
32 mixins: [service],
57 props: { 33 props: {
58 item: Object, 34 item: Object,
59 }, 35 },
36 components: {
37 Generic,
38 },
60 data: () => { 39 data: () => {
61 return { 40 return {
62 activity: null, 41 activity: null,
@@ -70,15 +49,7 @@ export default {
70 }, 49 },
71 methods: { 50 methods: {
72 fetchConfig: function () { 51 fetchConfig: function () {
73 fetch(`${this.item.url}/api/health?apikey=${this.item.apikey}`, { 52 this.fetch(`/api/health?apikey=${this.item.apikey}`)
74 credentials: "include",
75 })
76 .then((response) => {
77 if (response.status != 200) {
78 throw new Error(response.statusText);
79 }
80 return response.json();
81 })
82 .then((health) => { 53 .then((health) => {
83 this.warnings = 0; 54 this.warnings = 0;
84 this.errors = 0; 55 this.errors = 0;
@@ -94,15 +65,7 @@ export default {
94 console.error(e); 65 console.error(e);
95 this.serverError = true; 66 this.serverError = true;
96 }); 67 });
97 fetch(`${this.item.url}/api/queue?apikey=${this.item.apikey}`, { 68 this.fetch(`/api/queue?apikey=${this.item.apikey}`)
98 credentials: "include",
99 })
100 .then((response) => {
101 if (response.status != 200) {
102 throw new Error(response.statusText);
103 }
104 return response.json();
105 })
106 .then((queue) => { 69 .then((queue) => {
107 this.activity = 0; 70 this.activity = 0;
108 for (var i = 0; i < queue.length; i++) { 71 for (var i = 0; i < queue.length; i++) {
@@ -121,35 +84,32 @@ export default {
121</script> 84</script>
122 85
123<style scoped lang="scss"> 86<style scoped lang="scss">
124.media-left img {
125 max-height: 100%;
126}
127.notifs { 87.notifs {
128 position: absolute; 88 position: absolute;
129 color: white; 89 color: white;
130 font-family: sans-serif; 90 font-family: sans-serif;
131 top: 0.3em; 91 top: 0.3em;
132 right: 0.5em; 92 right: 0.5em;
133}
134.notif {
135 padding-right: 0.35em;
136 padding-left: 0.35em;
137 padding-top: 0.2em;
138 padding-bottom: 0.2em;
139 border-radius: 0.25em;
140 position: relative;
141 margin-left: 0.3em;
142 font-size: 0.8em;
143}
144.activity {
145 background-color: #4fb5d6;
146}
147 93
148.warnings { 94 .notif {
149 background-color: #d08d2e; 95 display: inline-block;
150} 96 padding: 0.2em 0.35em;
97 border-radius: 0.25em;
98 position: relative;
99 margin-left: 0.3em;
100 font-size: 0.8em;
101
102 &.activity {
103 background-color: #4fb5d6;
104 }
105
106 &.warnings {
107 background-color: #d08d2e;
108 }
151 109
152.errors { 110 &.errors {
153 background-color: #e51111; 111 background-color: #e51111;
112 }
113 }
154} 114}
155</style> 115</style>
diff --git a/yarn.lock b/yarn.lock
index 18906e1..ca36eb7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1173,10 +1173,10 @@
1173 lodash.kebabcase "^4.1.1" 1173 lodash.kebabcase "^4.1.1"
1174 svg-tags "^1.0.0" 1174 svg-tags "^1.0.0"
1175 1175
1176"@vue/babel-preset-app@^4.5.13": 1176"@vue/babel-preset-app@^4.5.15":
1177 version "4.5.13" 1177 version "4.5.15"
1178 resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.5.13.tgz#cb475321e4c73f7f110dac29a48c2a9cb80afeb6" 1178 resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.5.15.tgz#f6bc08f8f674e98a260004234cde18b966d72eb0"
1179 integrity sha512-pM7CR3yXB6L8Gfn6EmX7FLNE3+V/15I3o33GkSNsWvgsMp6HVGXKkXgojrcfUUauyL1LZOdvTmu4enU2RePGHw== 1179 integrity sha512-J+YttzvwRfV1BPczf8r3qCevznYk+jh531agVF+5EYlHF4Sgh/cGXTz9qkkiux3LQgvhEGXgmCteg1n38WuuKg==
1180 dependencies: 1180 dependencies:
1181 "@babel/core" "^7.11.0" 1181 "@babel/core" "^7.11.0"
1182 "@babel/helper-compilation-targets" "^7.9.6" 1182 "@babel/helper-compilation-targets" "^7.9.6"
@@ -1258,61 +1258,61 @@
1258 "@vue/babel-plugin-transform-vue-jsx" "^1.2.1" 1258 "@vue/babel-plugin-transform-vue-jsx" "^1.2.1"
1259 camelcase "^5.0.0" 1259 camelcase "^5.0.0"
1260 1260
1261"@vue/cli-overlay@^4.5.13": 1261"@vue/cli-overlay@^4.5.15":
1262 version "4.5.13" 1262 version "4.5.15"
1263 resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.5.13.tgz#4f1fd2161be8f69d6cba8079f3f0d7dc4dee47a7" 1263 resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-4.5.15.tgz#0700fd6bad39336d4189ba3ff7d25e638e818c9c"
1264 integrity sha512-jhUIg3klgi5Cxhs8dnat5hi/W2tQJvsqCxR0u6hgfSob0ORODgUBlN+F/uwq7cKIe/pzedVUk1y07F13GQvPqg== 1264 integrity sha512-0zI0kANAVmjFO2LWGUIzdGPMeE3+9k+KeRDXsUqB30YfRF7abjfiiRPq5BU9pOzlJbVdpRkisschBrvdJqDuDg==
1265 1265
1266"@vue/cli-plugin-babel@~4.5.0": 1266"@vue/cli-plugin-babel@~4.5.15":
1267 version "4.5.13" 1267 version "4.5.15"
1268 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.13.tgz#a89c482edcc4ea1d135645cec502a7f5fd4c30e7" 1268 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.15.tgz#ae4fb2ed54255fe3d84df381dab68509641179ed"
1269 integrity sha512-ykvEAfD8PgGs+dGMGqr7l/nRmIS39NRzWLhMluPLTvDV1L+IxcoB73HNLGA/aENDpl8CuWrTE+1VgydcOhp+wg== 1269 integrity sha512-hBLrwYfFkHldEe34op/YNgPhpOWI5n5DB2Qt9I/1Epeif4M4iFaayrgjvOR9AVM6WbD3Yx7WCFszYpWrQZpBzQ==
1270 dependencies: 1270 dependencies:
1271 "@babel/core" "^7.11.0" 1271 "@babel/core" "^7.11.0"
1272 "@vue/babel-preset-app" "^4.5.13" 1272 "@vue/babel-preset-app" "^4.5.15"
1273 "@vue/cli-shared-utils" "^4.5.13" 1273 "@vue/cli-shared-utils" "^4.5.15"
1274 babel-loader "^8.1.0" 1274 babel-loader "^8.1.0"
1275 cache-loader "^4.1.0" 1275 cache-loader "^4.1.0"
1276 thread-loader "^2.1.3" 1276 thread-loader "^2.1.3"
1277 webpack "^4.0.0" 1277 webpack "^4.0.0"
1278 1278
1279"@vue/cli-plugin-eslint@~4.5.0": 1279"@vue/cli-plugin-eslint@~4.5.15":
1280 version "4.5.13" 1280 version "4.5.15"
1281 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.13.tgz#8baf22d0d96d76720c7506646b96f4f62c05bdfa" 1281 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.15.tgz#5781824a941f34c26336a67b1f6584a06c6a24ff"
1282 integrity sha512-yc2uXX6aBiy3vEf5TwaueaDqQbdIXIhk0x0KzEtpPo23jBdLkpOSoU5NCgE06g/ZiGAcettpmBSv73Hfp4wHEw== 1282 integrity sha512-/2Fl6wY/5bz3HD035oSnFRMsKNxDxU396KqBdpCQdwdvqk4mm6JAbXqihpcBRTNPeTO6w+LwGe6FE56PVbJdbg==
1283 dependencies: 1283 dependencies:
1284 "@vue/cli-shared-utils" "^4.5.13" 1284 "@vue/cli-shared-utils" "^4.5.15"
1285 eslint-loader "^2.2.1" 1285 eslint-loader "^2.2.1"
1286 globby "^9.2.0" 1286 globby "^9.2.0"
1287 inquirer "^7.1.0" 1287 inquirer "^7.1.0"
1288 webpack "^4.0.0" 1288 webpack "^4.0.0"
1289 yorkie "^2.0.0" 1289 yorkie "^2.0.0"
1290 1290
1291"@vue/cli-plugin-pwa@~4.5.0": 1291"@vue/cli-plugin-pwa@~4.5.15":
1292 version "4.5.13" 1292 version "4.5.15"
1293 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-4.5.13.tgz#a800639814b6f62a38f04198c340cfaee7295c3f" 1293 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-4.5.15.tgz#eb800c418d96b496deec9d063a1798fe6e9c2db8"
1294 integrity sha512-uU5pp94VU0YscfKq/mNRsKOdxG+CTqVlZWaYkRc+HCcwkJ/m/CnxgaEqQFr0QpHC8zmlX4gILO1RVYygJoR9tw== 1294 integrity sha512-yQzsspaIkjeQyN6btF8ATgbJFU023q1HC8uUpmiBa4QE9EyBlR8fSrKFhcJ0EmT6KnU7PMwlnOJ/OqjguFnufA==
1295 dependencies: 1295 dependencies:
1296 "@vue/cli-shared-utils" "^4.5.13" 1296 "@vue/cli-shared-utils" "^4.5.15"
1297 webpack "^4.0.0" 1297 webpack "^4.0.0"
1298 workbox-webpack-plugin "^4.3.1" 1298 workbox-webpack-plugin "^4.3.1"
1299 1299
1300"@vue/cli-plugin-router@^4.5.13": 1300"@vue/cli-plugin-router@^4.5.15":
1301 version "4.5.13" 1301 version "4.5.15"
1302 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.5.13.tgz#0b67c8898a2bf132941919a2a2e5f3aacbd9ffbe" 1302 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-router/-/cli-plugin-router-4.5.15.tgz#1e75c8c89df42c694f143b9f1028de3cf5d61e1e"
1303 integrity sha512-tgtMDjchB/M1z8BcfV4jSOY9fZSMDTPgF9lsJIiqBWMxvBIsk9uIZHxp62DibYME4CCKb/nNK61XHaikFp+83w== 1303 integrity sha512-q7Y6kP9b3k55Ca2j59xJ7XPA6x+iSRB+N4ac0ZbcL1TbInVQ4j5wCzyE+uqid40hLy4fUdlpl4X9fHJEwuVxPA==
1304 dependencies: 1304 dependencies:
1305 "@vue/cli-shared-utils" "^4.5.13" 1305 "@vue/cli-shared-utils" "^4.5.15"
1306 1306
1307"@vue/cli-plugin-vuex@^4.5.13": 1307"@vue/cli-plugin-vuex@^4.5.15":
1308 version "4.5.13" 1308 version "4.5.15"
1309 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.13.tgz#98646d8bc1e69cf6c6a6cba2fed3eace0356c360" 1309 resolved "https://registry.yarnpkg.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.15.tgz#466c1f02777d02fef53a9bb49a36cc3a3bcfec4e"
1310 integrity sha512-I1S9wZC7iI0Wn8kw8Zh+A2Qkf6s1M6vTGBkx8boXjuzfwEEyEHRxadsVCecZc8Mkpydo0nykj+MyYF96TKFuVA== 1310 integrity sha512-fqap+4HN+w+InDxlA3hZTOGE0tzBTgXhKLoDydhywqgmhQ1D9JA6Feh94ze6tG8DsWX58/ujYUqA8jAz17FJtg==
1311 1311
1312"@vue/cli-service@~4.5.0": 1312"@vue/cli-service@~4.5.15":
1313 version "4.5.13" 1313 version "4.5.15"
1314 resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.5.13.tgz#a09e684a801684b6e24e5414ad30650970eec9ed" 1314 resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-4.5.15.tgz#0e9a186d51550027d0e68e95042077eb4d115b45"
1315 integrity sha512-CKAZN4iokMMsaUyJRU22oUAz3oS/X9sVBSKAF2/shFBV5xh3jqAlKl8OXZYz4cXGFLA6djNuYrniuLAo7Ku97A== 1315 integrity sha512-sFWnLYVCn4zRfu45IcsIE9eXM0YpDV3S11vlM2/DVbIPAGoYo5ySpSof6aHcIvkeGsIsrHFpPHzNvDZ/efs7jA==
1316 dependencies: 1316 dependencies:
1317 "@intervolga/optimize-cssnano-plugin" "^1.0.5" 1317 "@intervolga/optimize-cssnano-plugin" "^1.0.5"
1318 "@soda/friendly-errors-webpack-plugin" "^1.7.1" 1318 "@soda/friendly-errors-webpack-plugin" "^1.7.1"
@@ -1320,10 +1320,10 @@
1320 "@types/minimist" "^1.2.0" 1320 "@types/minimist" "^1.2.0"
1321 "@types/webpack" "^4.0.0" 1321 "@types/webpack" "^4.0.0"
1322 "@types/webpack-dev-server" "^3.11.0" 1322 "@types/webpack-dev-server" "^3.11.0"
1323 "@vue/cli-overlay" "^4.5.13" 1323 "@vue/cli-overlay" "^4.5.15"
1324 "@vue/cli-plugin-router" "^4.5.13" 1324 "@vue/cli-plugin-router" "^4.5.15"
1325 "@vue/cli-plugin-vuex" "^4.5.13" 1325 "@vue/cli-plugin-vuex" "^4.5.15"
1326 "@vue/cli-shared-utils" "^4.5.13" 1326 "@vue/cli-shared-utils" "^4.5.15"
1327 "@vue/component-compiler-utils" "^3.1.2" 1327 "@vue/component-compiler-utils" "^3.1.2"
1328 "@vue/preload-webpack-plugin" "^1.1.0" 1328 "@vue/preload-webpack-plugin" "^1.1.0"
1329 "@vue/web-component-wrapper" "^1.2.0" 1329 "@vue/web-component-wrapper" "^1.2.0"
@@ -1372,10 +1372,10 @@
1372 optionalDependencies: 1372 optionalDependencies:
1373 vue-loader-v16 "npm:vue-loader@^16.1.0" 1373 vue-loader-v16 "npm:vue-loader@^16.1.0"
1374 1374
1375"@vue/cli-shared-utils@^4.5.13": 1375"@vue/cli-shared-utils@^4.5.15":
1376 version "4.5.13" 1376 version "4.5.15"
1377 resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.5.13.tgz#acd40f31b4790f1634292bdaa5fca95dc1e0ff50" 1377 resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.5.15.tgz#dba3858165dbe3465755f256a4890e69084532d6"
1378 integrity sha512-HpnOrkLg42RFUsQGMJv26oTG3J3FmKtO2WSRhKIIL+1ok3w9OjGCtA3nMMXN27f9eX14TqO64M36DaiSZ1fSiw== 1378 integrity sha512-SKaej9hHzzjKSOw1NlFmc6BSE0vcqUQMQiv1cxQ2DhVyy4QxZXBmzmiLBUBe+hYZZs1neXW7n//udeN9bCAY+Q==
1379 dependencies: 1379 dependencies:
1380 "@hapi/joi" "^15.0.1" 1380 "@hapi/joi" "^15.0.1"
1381 chalk "^2.4.2" 1381 chalk "^2.4.2"