aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBastien Wirtz <bastien.wirtz@gmail.com>2021-12-12 16:28:20 +0100
committerBastien Wirtz <bastien.wirtz@gmail.com>2021-12-12 16:28:20 +0100
commitb4a2db6e37859abfa5477685b7547bb78e71a76b (patch)
tree8dcfb4c495032f0b960bc9bcab0f23081abceb7f
parente6ba84d35a8f2761e849b9c2cdc09984e8390035 (diff)
downloadhomer-b4a2db6e37859abfa5477685b7547bb78e71a76b.tar.gz
homer-b4a2db6e37859abfa5477685b7547bb78e71a76b.tar.zst
homer-b4a2db6e37859abfa5477685b7547bb78e71a76b.zip
Services refactoring
-rw-r--r--src/App.vue2
-rw-r--r--src/components/SearchInput.vue4
-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
6 files changed, 153 insertions, 265 deletions
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/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);