migrating some state to pinia stores.
This commit is contained in:
parent
62d5d29bfc
commit
f7b610434f
5 changed files with 175 additions and 95 deletions
|
|
@ -223,20 +223,13 @@ import { defineProps, computed, ref, watch, defineEmits } from 'vue';
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
import LazyLoader from './LazyLoader'
|
import LazyLoader from './LazyLoader'
|
||||||
import { makeDownload, formatBytes, ucFirst } from '../utils/index'
|
import { makeDownload, formatBytes, ucFirst } from '~/utils/index'
|
||||||
|
import { useConfigStore } from '~/store/ConfigStore';
|
||||||
|
import { useStateStore } from '~/store/StateStore';
|
||||||
|
|
||||||
const emits = defineEmits(['deleteItem', 'addItem', 'playItem', 'archiveItem']);
|
const emits = defineEmits(['deleteItem', 'addItem', 'playItem', 'archiveItem'])
|
||||||
|
const config = useConfigStore()
|
||||||
const props = defineProps({
|
const stateStore = useStateStore()
|
||||||
completed: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectedElms = ref([]);
|
const selectedElms = ref([]);
|
||||||
const masterSelectAll = ref(false);
|
const masterSelectAll = ref(false);
|
||||||
|
|
@ -244,8 +237,8 @@ const showCompleted = useStorage('showCompleted', true)
|
||||||
const direction = useStorage('sortCompleted', 'desc')
|
const direction = useStorage('sortCompleted', 'desc')
|
||||||
|
|
||||||
watch(masterSelectAll, (value) => {
|
watch(masterSelectAll, (value) => {
|
||||||
for (const key in props.completed) {
|
for (const key in stateStore.history) {
|
||||||
const element = props.completed[key];
|
const element = stateStore.history[key];
|
||||||
if (value) {
|
if (value) {
|
||||||
selectedElms.value.push(element._id);
|
selectedElms.value.push(element._id);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -256,16 +249,17 @@ watch(masterSelectAll, (value) => {
|
||||||
|
|
||||||
const sortCompleted = computed(() => {
|
const sortCompleted = computed(() => {
|
||||||
const thisDirection = direction.value;
|
const thisDirection = direction.value;
|
||||||
return Object.values(props.completed).sort((a, b) => {
|
return Object.values(stateStore.history).sort((a, b) => {
|
||||||
if (thisDirection === 'asc') {
|
if ('asc' === thisDirection) {
|
||||||
return new Date(a.datetime) - new Date(b.datetime);
|
return new Date(a.datetime) - new Date(b.datetime);
|
||||||
}
|
}
|
||||||
return new Date(b.datetime) - new Date(a.datetime);
|
return new Date(b.datetime) - new Date(a.datetime);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasSelected = computed(() => selectedElms.value.length > 0)
|
const hasSelected = computed(() => selectedElms.value.length > 0)
|
||||||
const hasItems = computed(() => Object.keys(props.completed)?.length > 0)
|
const hasItems = computed(() => stateStore.count('history') > 0)
|
||||||
const getTotal = computed(() => Object.keys(props.completed)?.length);
|
const getTotal = computed(() => stateStore.count('history'));
|
||||||
|
|
||||||
const showMessage = (item) => {
|
const showMessage = (item) => {
|
||||||
if (!item?.msg || item.msg === item?.error) {
|
if (!item?.msg || item.msg === item?.error) {
|
||||||
|
|
@ -276,12 +270,12 @@ const showMessage = (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasIncomplete = computed(() => {
|
const hasIncomplete = computed(() => {
|
||||||
if (Object.keys(props.completed)?.length < 0) {
|
if (Object.keys(stateStore.history)?.length < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in props.completed) {
|
for (const key in stateStore.history) {
|
||||||
const element = props.completed[key];
|
const element = stateStore.history[key];
|
||||||
if (element.status !== 'finished') {
|
if (element.status !== 'finished') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -290,12 +284,12 @@ const hasIncomplete = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasCompleted = computed(() => {
|
const hasCompleted = computed(() => {
|
||||||
if (Object.keys(props.completed)?.length < 0) {
|
if (Object.keys(stateStore.history)?.length < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in props.completed) {
|
for (const key in stateStore.history) {
|
||||||
const element = props.completed[key];
|
const element = stateStore.history[key];
|
||||||
if (element.status === 'finished') {
|
if (element.status === 'finished') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -311,33 +305,27 @@ const clearCompleted = () => {
|
||||||
|
|
||||||
const keys = {};
|
const keys = {};
|
||||||
|
|
||||||
for (const key in props.completed) {
|
for (const key in stateStore.history) {
|
||||||
if (props.completed[key].status === 'finished') {
|
if (stateStore.history[key].status === 'finished') {
|
||||||
keys[key] = props.completed[key]._id;
|
keys[key] = stateStore.history[key]._id;
|
||||||
|
stateStore.remove('history', key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emits('deleteItem', 'completed', keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearIncomplete = () => {
|
const clearIncomplete = () => {
|
||||||
const state = confirm('Are you sure you want to clear all incomplete downloads?');
|
if (false === confirm('Are you sure you want to clear all incomplete downloads?')) {
|
||||||
if (false === state) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = {};
|
for (const key in stateStore.history) {
|
||||||
|
if (stateStore.history[key].status !== 'finished') {
|
||||||
for (const key in props.completed) {
|
stateStore.remove('history', key);
|
||||||
if (props.completed[key].status !== 'finished') {
|
|
||||||
keys[key] = props.completed[key]._id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emits('deleteItem', 'completed', keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setIcon = (item) => {
|
const setIcon = item => {
|
||||||
if (item.status === 'finished' && item.is_live) {
|
if (item.status === 'finished' && item.is_live) {
|
||||||
return 'fa-solid fa-globe';
|
return 'fa-solid fa-globe';
|
||||||
}
|
}
|
||||||
|
|
@ -362,8 +350,8 @@ const requeueIncomplete = () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in props.completed) {
|
for (const key in stateStore.history) {
|
||||||
const item = props.completed[key];
|
const item = stateStore.history[key];
|
||||||
if (item.status !== 'finished') {
|
if (item.status !== 'finished') {
|
||||||
emits('deleteItem', 'completed', key);
|
emits('deleteItem', 'completed', key);
|
||||||
emits('addItem', {
|
emits('addItem', {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
<LazyLoader :unrender="true" :min-height="265" class="column is-6" v-for="item in queue" :key="item._id">
|
<LazyLoader :unrender="true" :min-height="265" class="column is-6" v-for="item in stateStore.queue"
|
||||||
|
:key="item._id">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<header class="card-header has-tooltip" v-tooltip="item.title">
|
<header class="card-header has-tooltip" v-tooltip="item.title">
|
||||||
<div class="card-header-title has-text-centered is-text-overflow is-block">
|
<div class="card-header-title has-text-centered is-text-overflow is-block">
|
||||||
|
|
@ -126,27 +127,21 @@ import { defineProps, defineEmits, ref, watch, computed } from 'vue';
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
import LazyLoader from './LazyLoader'
|
import LazyLoader from './LazyLoader'
|
||||||
|
import { useConfigStore } from '~/store/ConfigStore';
|
||||||
|
import { useStateStore } from '~/store/StateStore';
|
||||||
|
|
||||||
const emit = defineEmits(['deleteItem']);
|
const emit = defineEmits(['deleteItem']);
|
||||||
|
|
||||||
const props = defineProps({
|
const config = useConfigStore();
|
||||||
queue: {
|
const stateStore = useStateStore();
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectedElms = ref([]);
|
const selectedElms = ref([]);
|
||||||
const masterSelectAll = ref(false);
|
const masterSelectAll = ref(false);
|
||||||
const showQueue = useStorage('showQueue', true)
|
const showQueue = useStorage('showQueue', true)
|
||||||
|
|
||||||
watch(masterSelectAll, (value) => {
|
watch(masterSelectAll, (value) => {
|
||||||
for (const key in props.queue) {
|
for (const key in stateStore.queue) {
|
||||||
const element = props.queue[key];
|
const element = stateStore.queue[key];
|
||||||
if (value) {
|
if (value) {
|
||||||
selectedElms.value.push(element._id);
|
selectedElms.value.push(element._id);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -156,10 +151,10 @@ watch(masterSelectAll, (value) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasSelected = computed(() => selectedElms.value.length > 0)
|
const hasSelected = computed(() => selectedElms.value.length > 0)
|
||||||
const hasQueuedItems = computed(() => Object.keys(props.queue)?.length > 0)
|
const hasQueuedItems = computed(() => stateStore.count('queue') > 0)
|
||||||
const getTotal = computed(() => Object.keys(props.queue)?.length);
|
const getTotal = computed(() => stateStore.count('queue'));
|
||||||
|
|
||||||
const setIcon = (item) => {
|
const setIcon = item => {
|
||||||
if (item.status === 'downloading' && item.is_live) {
|
if (item.status === 'downloading' && item.is_live) {
|
||||||
return 'fa-solid fa-globe';
|
return 'fa-solid fa-globe';
|
||||||
}
|
}
|
||||||
|
|
@ -231,6 +226,7 @@ const confirmDelete = (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('deleteItem', 'queue', item._id);
|
emit('deleteItem', 'queue', item._id);
|
||||||
|
stateStore.remove('queue', item._id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Queue :config="config" :queue="downloading" @deleteItem="deleteItem" />
|
<Queue />
|
||||||
<History :config="config" :completed="completed" @deleteItem="deleteItem" @addItem="addItem"
|
<History />
|
||||||
@playItem="playItem" @archiveItem="archiveItem" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client"
|
||||||
const bus = useEventBus('item_added', 'show_form', 'task_edit')
|
import { useConfigStore } from "~/store/ConfigStore"
|
||||||
|
import { useStateStore } from "~/store/StateStore"
|
||||||
|
|
||||||
const config = reactive({
|
const bus = useEventBus('item_added', 'show_form', 'task_edit')
|
||||||
isConnected: false,
|
const config = useConfigStore()
|
||||||
app: {},
|
|
||||||
tasks: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const socket = ref()
|
const socket = ref()
|
||||||
const downloading = reactive({})
|
const downloading = reactive({})
|
||||||
const completed = reactive({})
|
|
||||||
const cli_output = ref([])
|
const cli_output = ref([])
|
||||||
const cli_isLoading = ref(false)
|
const cli_isLoading = ref(false)
|
||||||
|
const stateStore = useStateStore()
|
||||||
|
|
||||||
useHead({ title: 'Index' })
|
useHead({ title: 'Index' })
|
||||||
|
|
||||||
|
|
@ -34,23 +31,20 @@ onMounted(() => {
|
||||||
socket.value.on('disconnect', () => config.isConnected = false);
|
socket.value.on('disconnect', () => config.isConnected = false);
|
||||||
|
|
||||||
socket.value.on('initial_data', stream => {
|
socket.value.on('initial_data', stream => {
|
||||||
const initialData = JSON.parse(stream);
|
const initialData = JSON.parse(stream)
|
||||||
config.app = initialData['config'];
|
|
||||||
config.tasks = initialData['tasks'];
|
|
||||||
config.directories = initialData['directories'];
|
|
||||||
|
|
||||||
for (const id in initialData['queue']) {
|
config.setAll({
|
||||||
downloading[id] = initialData['queue'][id];
|
app: initialData['config'],
|
||||||
}
|
tasks: initialData['tasks'],
|
||||||
|
directories: initialData['directories'],
|
||||||
for (const id in initialData['done']) {
|
})
|
||||||
completed[id] = initialData['done'][id];
|
stateStore.addAll('queue', initialData['queue'] ?? {})
|
||||||
}
|
stateStore.addAll('history', initialData['done'] ?? {})
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.value.on('added', stream => {
|
socket.value.on('added', stream => {
|
||||||
const item = JSON.parse(stream);
|
const item = JSON.parse(stream);
|
||||||
downloading[item._id] = item;
|
stateStore.add('queue', item);
|
||||||
toast.success(`Item queued successfully: ${downloading[item._id]?.title}`);
|
toast.success(`Item queued successfully: ${downloading[item._id]?.title}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -61,15 +55,17 @@ onMounted(() => {
|
||||||
|
|
||||||
socket.value.on('completed', stream => {
|
socket.value.on('completed', stream => {
|
||||||
const item = JSON.parse(stream);
|
const item = JSON.parse(stream);
|
||||||
if (item._id in downloading) {
|
if (true === stateStore.has('queue', item._id)) {
|
||||||
delete downloading[item._id];
|
stateStore.move('queue', 'history', item._id);
|
||||||
|
return
|
||||||
}
|
}
|
||||||
completed[item._id] = item;
|
stateStore.add('history', item);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.value.on('canceled', stream => {
|
socket.value.on('canceled', stream => {
|
||||||
const id = JSON.parse(stream);
|
const id = JSON.parse(stream);
|
||||||
if (false === (id in downloading)) {
|
|
||||||
|
if (true !== stateStore.has('queue', id)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,31 +75,28 @@ onMounted(() => {
|
||||||
|
|
||||||
socket.value.on('cleared', stream => {
|
socket.value.on('cleared', stream => {
|
||||||
const id = JSON.parse(stream);
|
const id = JSON.parse(stream);
|
||||||
if (false === (id in completed)) {
|
if (true !== stateStore.has('history', id)) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
stateStore.remove('history', id);
|
||||||
delete completed[id];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.value.on("updated", stream => {
|
socket.value.on("updated", stream => {
|
||||||
const data = JSON.parse(stream);
|
const data = JSON.parse(stream);
|
||||||
let dl = downloading[data._id] ?? {};
|
let dl = stateStore.get('queue', data._id, {});
|
||||||
data.deleting = dl?.deleting;
|
data.deleting = dl?.deleting;
|
||||||
downloading[data._id] = data;
|
stateStore.update('queue', data._id, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.value.on("update", stream => {
|
socket.value.on("update", stream => {
|
||||||
const data = JSON.parse(stream);
|
const data = JSON.parse(stream);
|
||||||
if (false === (data._id in completed)) {
|
if (true === stateStore.has('history', data._id)) {
|
||||||
|
stateStore.update('history', data._id, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
completed[data._id] = data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.value.on('cli_close', () => cli_isLoading.value = false);
|
socket.value.on('cli_close', () => cli_isLoading.value = false);
|
||||||
socket.value.on('cli_output', s => cli_output.value.push(s));
|
socket.value.on('cli_output', s => cli_output.value.push(s));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
58
ui/store/ConfigStore.js
Normal file
58
ui/store/ConfigStore.js
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
const CONFIG_KEYS = {
|
||||||
|
isConnected: false,
|
||||||
|
tasks: [],
|
||||||
|
app: {
|
||||||
|
host: '',
|
||||||
|
prefix: '',
|
||||||
|
keep_archive: false,
|
||||||
|
output_template: '',
|
||||||
|
},
|
||||||
|
directories: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useConfigStore = defineStore('config', () => {
|
||||||
|
const state = reactive(CONFIG_KEYS);
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
add(key, value) {
|
||||||
|
if (key.includes('.')) {
|
||||||
|
const [parentKey, subKey] = key.split('.');
|
||||||
|
state[parentKey][subKey] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state[key] = value;
|
||||||
|
},
|
||||||
|
get(key, defaultValue = null) {
|
||||||
|
if (key.includes('.')) {
|
||||||
|
const [parentKey, subKey] = key.split('.');
|
||||||
|
return state[parentKey][subKey] || defaultValue;
|
||||||
|
}
|
||||||
|
return state[key] || defaultValue;
|
||||||
|
},
|
||||||
|
update(key, value) {
|
||||||
|
if (key.includes('.')) {
|
||||||
|
const [parentKey, subKey] = key.split('.');
|
||||||
|
state[parentKey][subKey] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state[key] = value;
|
||||||
|
},
|
||||||
|
getAll() {
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
setAll(data) {
|
||||||
|
Object.keys(data).forEach((key) => {
|
||||||
|
if (key.includes('.')) {
|
||||||
|
const [parentKey, subKey] = key.split('.');
|
||||||
|
state[parentKey][subKey] = data[key];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state[key] = data[key];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...toRefs(state), ...actions };
|
||||||
|
});
|
||||||
45
ui/store/StateStore.js
Normal file
45
ui/store/StateStore.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useStateStore = defineStore('state', () => {
|
||||||
|
const state = reactive({
|
||||||
|
queue: {},
|
||||||
|
history: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
add(type, key, value) {
|
||||||
|
state[type][key] = value;
|
||||||
|
},
|
||||||
|
update(type, key, value) {
|
||||||
|
state[type][key] = value;
|
||||||
|
},
|
||||||
|
remove(type, key) {
|
||||||
|
if (state[type][key]) {
|
||||||
|
delete state[type][key];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get(type, key, defaultValue = null) {
|
||||||
|
return state[type][key] || defaultValue;
|
||||||
|
},
|
||||||
|
has(type, key) {
|
||||||
|
return !!state[type][key];
|
||||||
|
},
|
||||||
|
clearAll(type) {
|
||||||
|
state[type] = {};
|
||||||
|
},
|
||||||
|
addAll(type, data) {
|
||||||
|
state[type] = data;
|
||||||
|
},
|
||||||
|
move(fromType, toType, key) {
|
||||||
|
if (state[fromType][key]) {
|
||||||
|
state[toType][key] = state[fromType][key];
|
||||||
|
delete state[fromType][key];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count(type) {
|
||||||
|
return Object.keys(state[type]).length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...toRefs(state), ...actions };
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue