Skip to content

Commit

Permalink
Runner per location (#617)
Browse files Browse the repository at this point in the history
* Update actions/mutations to use new options

* Create getters for combined properties

* Make sure time actually changed

* Use combinedRescans in library view

* Lint

* Fix combinedRescans

* Allow user to scan one specific location

* Fix trigger of loadData

* Pass id and rescan

* Create our own button-group styling instead of VBtnToggle

* Use strict comparison

* Use api-client-js 0.15.0
  • Loading branch information
robbevp authored Dec 4, 2021
1 parent cc39090 commit fc02bc4
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 44 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'"
},
"dependencies": {
"@accentor/api-client-js": "^0.13.0",
"@accentor/api-client-js": "^0.15.0",
"@mdi/font": "^6.5.95",
"@mdi/svg": "^6.5.95",
"fetch-retry": "^5.0.1",
Expand Down
12 changes: 12 additions & 0 deletions src/Main.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ a {
}
}
.button-group {
border-radius: 4px;
overflow: hidden;
box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2),
0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
&__button {
margin: 0;
border-radius: 0;
}
}
// Additional utility classes
.white-space-nowrap {
white-space: nowrap;
Expand Down
114 changes: 102 additions & 12 deletions src/store/rescan.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,86 @@
import api from "@/api";
import { fetchAll } from "./actions";

export default {
namespaced: true,
state: {
rescan: null,
rescans: {},
lastClick: new Date(0),
loading: false,
},
mutations: {
setRescans(state, payload) {
const oldRescans = state.rescans;
state.rescans = {};
for (let id in oldRescans) {
state.rescans[id] = oldRescans[id];
}
const loaded = new Date();
for (let rescan of payload) {
rescan.loaded = loaded;
state.rescans[rescan.id] = rescan;
}
},
setRescan(state, { id, rescan }) {
const oldRescans = state.rescans;
state.rescans = {};
for (let id in oldRescans) {
state.rescans[id] = oldRescans[id];
}
rescan.loaded = new Date();
state.rescans[id] = rescan;
},
setStartLoading(state) {
state.startLoading = new Date();
},
removeOld(state) {
const oldRescans = state.rescans;
state.rescans = {};
for (let id in oldRescans) {
if (oldRescans[id].loaded > state.startLoading) {
state.rescans[id] = oldRescans[id];
}
}
},
setLastClick(state, payload) {
state.lastClick = payload;
},
setLoading(state, payload) {
state.loading = payload;
},
setRescan(state, payload) {
state.rescan = payload;
},
},
actions: {
async show({ commit, rootState }) {
async index({ commit, rootState, getters }) {
if (rootState.rescan.loading) {
return true;
}
try {
commit("setLoading", true);
do {
const generator = api.rescans.index(rootState.auth);
await fetchAll(commit, generator, "setRescans");
await new Promise((resolve) => setTimeout(resolve, 1000));
} while (
rootState.rescan.lastClick > new Date(getters.finishedAt) ||
getters.running
);
commit("setLoading", false);
return true;
} catch (error) {
commit("addError", error, { root: true });
return false;
}
},
async show({ commit, rootState }, id) {
if (rootState.rescan.loading) {
return true;
}
try {
commit("setLoading", true);
let result = null;
do {
result = await api.rescan.show(rootState.auth);
commit("setRescan", result);
result = await api.rescans.show(rootState.auth, id);
commit("setRescan", { id, rescan: result });
await new Promise((resolve) => setTimeout(resolve, 1000));
} while (
rootState.rescan.lastClick > new Date(result.finished_at) ||
Expand All @@ -42,13 +94,24 @@ export default {
return false;
}
},
async start({ commit, dispatch, rootState }) {
async startAll({ commit, dispatch, rootState }) {
commit("setLastClick", new Date());
try {
await api.rescans.startAll(rootState.auth);
setTimeout(() => dispatch("index"), 2500);
return true;
} catch (error) {
commit("addError", error, { root: true });
return false;
}
},
async start({ commit, dispatch, rootState }, id) {
commit("setLastClick", new Date());
try {
const result = await api.rescan.start(rootState.auth);
const result = await api.rescans.start(rootState.auth, id);
result.running = true;
commit("setRescan", result);
setTimeout(() => dispatch("show"), 1000);
commit("setRescan", { id, rescan: result });
setTimeout(() => dispatch("show", id), 1000);
return true;
} catch (error) {
commit("addError", error, { root: true });
Expand All @@ -57,6 +120,33 @@ export default {
},
},
getters: {
finishedAt: (state) => state.rescan?.finished_at,
rescans: (state) => Object.values(state.rescans),
running: (state, getters) => getters.rescans.some((r) => r.running),
combinedRescans: (state, getters) =>
getters.rescans.reduce(
(acc, rescan) => {
acc.finished_at =
acc.finished_at < new Date(rescan.finished_at)
? new Date(rescan.finished_at)
: acc.finished_at;
acc.processed += rescan.processed;
acc.error_text += rescan.error_text;
acc.warning_text += rescan.warning_text;
return acc;
},
{
running: false,
finished_at: 0,
processed: 0,
error_text: "",
warning_text: "",
}
),
finishedAt: (state, getters) =>
getters.rescans.reduce((acc, rescan) => {
return acc < new Date(rescan.finished_at)
? new Date(rescan.finished_at)
: acc;
}, null),
},
};
6 changes: 5 additions & 1 deletion src/views/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ export default {
this.$i18n.locale = this.locale;
},
finishedAt(newValue, oldValue) {
if (!this.loading && typeof oldValue !== "undefined") {
if (
!this.loading &&
oldValue !== null &&
oldValue.getTime() !== newValue.getTime()
) {
this.loadData();
}
},
Expand Down
87 changes: 61 additions & 26 deletions src/views/Library.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,79 @@
<VRow class="mb-2">
<h2 class="text-h5">{{ $t("library.rescan") }}</h2>
</VRow>
<VRow v-if="rescan" class="mb-2">
<VBtn
@click="start"
:disabled="rescanRunning"
color="success"
class="ma-2"
>
<VIcon left>
mdi-refresh
{{ rescanRunning ? "mdi-spin" : "" }}
</VIcon>
{{ $t("library.start-scan") }}
</VBtn>
<VRow v-if="combinedRescans" class="mb-2">
<div class="button-group ma-2">
<VBtn
@click="startAll"
:disabled="rescans.length === 0 || rescanRunning"
color="success"
class="button-group__button"
depressed
>
<VIcon left class="white--text">
mdi-refresh
{{ rescanRunning ? "mdi-spin" : "" }}
</VIcon>
{{ $t("library.start-scan") }}
</VBtn>
<VMenu offset-y bottom left close-on-click v-if="rescans.length > 1">
<template v-slot:activator="{ on, attrs }">
<VBtn
color="success"
depressed
v-bind="attrs"
v-on="on"
class="button-group__button"
>
<VIcon class="white--text">mdi-menu-down</VIcon>
</VBtn>
</template>
<VList>
<VListItem
v-for="(rescan, index) in rescans"
:key="index"
@click="start(rescan.id)"
>
<VListItemTitle :disabled="rescan.running">
Rescan {{ locations[rescan.location_id].path }}
</VListItemTitle>
</VListItem>
</VList>
</VMenu>
</div>
</VRow>
<VRow class="flex-column mb-4" v-if="rescan">
<VRow class="flex-column mb-4" v-if="combinedRescans">
<div>
<strong>{{ $t("library.finished-at") }}: </strong>
{{
rescanRunning
? $t("library.currently-running")
: $d(new Date(rescan.finished_at), "long")
: $d(new Date(combinedRescans.finished_at), "long")
}}
</div>
<div>
<strong>{{ $t("library.processed") }}: </strong>
{{ rescan.processed }}
{{ combinedRescans.processed }}
</div>
<div v-if="rescan.warning_text">
<div v-if="combinedRescans.warning_text">
<div>
<h3 class="text-h6">{{ $t("library.warnings") }}</h3>
</div>
<pre class="text-body-2">{{ rescan.warning_text }}</pre>
<pre class="text-body-2">{{ combinedRescans.warning_text }}</pre>
</div>
<div v-if="rescan.error_text">
<div v-if="combinedRescans.error_text">
<div>
<h3 class="text-h6">{{ $t("library.errors") }}</h3>
</div>
<pre class="text-body-2">{{ rescan.error_text }}</pre>
<pre class="text-body-2">{{ combinedRescans.error_text }}</pre>
</div>
<div v-if="!rescanRunning && !rescan.error_text && !rescan.warning_text">
<div
v-if="
!rescanRunning &&
!combinedRescans.error_text &&
!combinedRescans.warning_text
"
>
<h3 class="text-h6">{{ $t("library.no-errors-warnings") }}</h3>
</div>
</VRow>
Expand Down Expand Up @@ -124,21 +157,23 @@ export default {
},
computed: {
...mapGetters("auth", ["isModerator"]),
...mapState("rescan", ["rescan"]),
...mapGetters("rescan", ["rescans"]),
...mapGetters("rescan", ["combinedRescans"]),
...mapState("locations", ["locations"]),
...mapState("rescan", ["lastClick"]),
rescanRunning() {
return this.rescan.running ||
this.lastClick > new Date(this.rescan.finished_at)
return this.combinedRescans.running ||
this.lastClick > new Date(this.combinedRescans.finished_at)
? true
: false;
},
},
methods: {
...mapActions("rescan", ["start"]),
...mapActions("rescan", ["start", "startAll"]),
async loadData() {
let pendingResults = [];
if (this.isModerator) {
pendingResults.push(this.$store.dispatch("rescan/show"));
pendingResults.push(this.$store.dispatch("rescan/index"));
pendingResults.push(this.$store.dispatch("codecs/index"));
pendingResults.push(this.$store.dispatch("codecConversions/index"));
pendingResults.push(this.$store.dispatch("coverFilenames/index"));
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit fc02bc4

Please sign in to comment.