migrating some state to pinia stores.

This commit is contained in:
ArabCoders 2024-12-13 20:15:05 +03:00
parent 62d5d29bfc
commit f7b610434f
5 changed files with 175 additions and 95 deletions

View file

@ -223,20 +223,13 @@ import { defineProps, computed, ref, watch, defineEmits } from 'vue';
import moment from "moment";
import { useStorage } from '@vueuse/core'
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 props = defineProps({
completed: {
type: Object,
required: true
},
config: {
type: Object,
required: true
},
})
const emits = defineEmits(['deleteItem', 'addItem', 'playItem', 'archiveItem'])
const config = useConfigStore()
const stateStore = useStateStore()
const selectedElms = ref([]);
const masterSelectAll = ref(false);
@ -244,8 +237,8 @@ const showCompleted = useStorage('showCompleted', true)
const direction = useStorage('sortCompleted', 'desc')
watch(masterSelectAll, (value) => {
for (const key in props.completed) {
const element = props.completed[key];
for (const key in stateStore.history) {
const element = stateStore.history[key];
if (value) {
selectedElms.value.push(element._id);
} else {
@ -256,16 +249,17 @@ watch(masterSelectAll, (value) => {
const sortCompleted = computed(() => {
const thisDirection = direction.value;
return Object.values(props.completed).sort((a, b) => {
if (thisDirection === 'asc') {
return Object.values(stateStore.history).sort((a, b) => {
if ('asc' === thisDirection) {
return new Date(a.datetime) - new Date(b.datetime);
}
return new Date(b.datetime) - new Date(a.datetime);
})
})
const hasSelected = computed(() => selectedElms.value.length > 0)
const hasItems = computed(() => Object.keys(props.completed)?.length > 0)
const getTotal = computed(() => Object.keys(props.completed)?.length);
const hasItems = computed(() => stateStore.count('history') > 0)
const getTotal = computed(() => stateStore.count('history'));
const showMessage = (item) => {
if (!item?.msg || item.msg === item?.error) {
@ -276,12 +270,12 @@ const showMessage = (item) => {
}
const hasIncomplete = computed(() => {
if (Object.keys(props.completed)?.length < 0) {
if (Object.keys(stateStore.history)?.length < 0) {
return false;
}
for (const key in props.completed) {
const element = props.completed[key];
for (const key in stateStore.history) {
const element = stateStore.history[key];
if (element.status !== 'finished') {
return true;
}
@ -290,12 +284,12 @@ const hasIncomplete = computed(() => {
})
const hasCompleted = computed(() => {
if (Object.keys(props.completed)?.length < 0) {
if (Object.keys(stateStore.history)?.length < 0) {
return false;
}
for (const key in props.completed) {
const element = props.completed[key];
for (const key in stateStore.history) {
const element = stateStore.history[key];
if (element.status === 'finished') {
return true;
}
@ -311,33 +305,27 @@ const clearCompleted = () => {
const keys = {};
for (const key in props.completed) {
if (props.completed[key].status === 'finished') {
keys[key] = props.completed[key]._id;
for (const key in stateStore.history) {
if (stateStore.history[key].status === 'finished') {
keys[key] = stateStore.history[key]._id;
stateStore.remove('history', key);
}
}
emits('deleteItem', 'completed', keys);
}
const clearIncomplete = () => {
const state = confirm('Are you sure you want to clear all incomplete downloads?');
if (false === state) {
if (false === confirm('Are you sure you want to clear all incomplete downloads?')) {
return;
}
const keys = {};
for (const key in props.completed) {
if (props.completed[key].status !== 'finished') {
keys[key] = props.completed[key]._id;
for (const key in stateStore.history) {
if (stateStore.history[key].status !== 'finished') {
stateStore.remove('history', key);
}
}
emits('deleteItem', 'completed', keys);
}
const setIcon = (item) => {
const setIcon = item => {
if (item.status === 'finished' && item.is_live) {
return 'fa-solid fa-globe';
}
@ -362,8 +350,8 @@ const requeueIncomplete = () => {
return false;
}
for (const key in props.completed) {
const item = props.completed[key];
for (const key in stateStore.history) {
const item = stateStore.history[key];
if (item.status !== 'finished') {
emits('deleteItem', 'completed', key);
emits('addItem', {

View file

@ -35,7 +35,8 @@
</div>
<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">
<header class="card-header has-tooltip" v-tooltip="item.title">
<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 { useStorage } from '@vueuse/core'
import LazyLoader from './LazyLoader'
import { useConfigStore } from '~/store/ConfigStore';
import { useStateStore } from '~/store/StateStore';
const emit = defineEmits(['deleteItem']);
const props = defineProps({
queue: {
type: Object,
required: true
},
config: {
type: Object,
required: true
},
})
const config = useConfigStore();
const stateStore = useStateStore();
const selectedElms = ref([]);
const masterSelectAll = ref(false);
const showQueue = useStorage('showQueue', true)
watch(masterSelectAll, (value) => {
for (const key in props.queue) {
const element = props.queue[key];
for (const key in stateStore.queue) {
const element = stateStore.queue[key];
if (value) {
selectedElms.value.push(element._id);
} else {
@ -156,10 +151,10 @@ watch(masterSelectAll, (value) => {
})
const hasSelected = computed(() => selectedElms.value.length > 0)
const hasQueuedItems = computed(() => Object.keys(props.queue)?.length > 0)
const getTotal = computed(() => Object.keys(props.queue)?.length);
const hasQueuedItems = computed(() => stateStore.count('queue') > 0)
const getTotal = computed(() => stateStore.count('queue'));
const setIcon = (item) => {
const setIcon = item => {
if (item.status === 'downloading' && item.is_live) {
return 'fa-solid fa-globe';
}
@ -231,6 +226,7 @@ const confirmDelete = (item) => {
}
emit('deleteItem', 'queue', item._id);
stateStore.remove('queue', item._id);
return true;
}

View file

@ -1,27 +1,24 @@
<template>
<div>
<Queue :config="config" :queue="downloading" @deleteItem="deleteItem" />
<History :config="config" :completed="completed" @deleteItem="deleteItem" @addItem="addItem"
@playItem="playItem" @archiveItem="archiveItem" />
<Queue />
<History />
</div>
</template>
<script setup>
import { io } from "socket.io-client";
const bus = useEventBus('item_added', 'show_form', 'task_edit')
import { io } from "socket.io-client"
import { useConfigStore } from "~/store/ConfigStore"
import { useStateStore } from "~/store/StateStore"
const config = reactive({
isConnected: false,
app: {},
tasks: [],
})
const bus = useEventBus('item_added', 'show_form', 'task_edit')
const config = useConfigStore()
const runtimeConfig = useRuntimeConfig()
const socket = ref()
const downloading = reactive({})
const completed = reactive({})
const cli_output = ref([])
const cli_isLoading = ref(false)
const stateStore = useStateStore()
useHead({ title: 'Index' })
@ -34,23 +31,20 @@ onMounted(() => {
socket.value.on('disconnect', () => config.isConnected = false);
socket.value.on('initial_data', stream => {
const initialData = JSON.parse(stream);
config.app = initialData['config'];
config.tasks = initialData['tasks'];
config.directories = initialData['directories'];
const initialData = JSON.parse(stream)
for (const id in initialData['queue']) {
downloading[id] = initialData['queue'][id];
}
for (const id in initialData['done']) {
completed[id] = initialData['done'][id];
}
config.setAll({
app: initialData['config'],
tasks: initialData['tasks'],
directories: initialData['directories'],
})
stateStore.addAll('queue', initialData['queue'] ?? {})
stateStore.addAll('history', initialData['done'] ?? {})
})
socket.value.on('added', stream => {
const item = JSON.parse(stream);
downloading[item._id] = item;
stateStore.add('queue', item);
toast.success(`Item queued successfully: ${downloading[item._id]?.title}`);
});
@ -61,15 +55,17 @@ onMounted(() => {
socket.value.on('completed', stream => {
const item = JSON.parse(stream);
if (item._id in downloading) {
delete downloading[item._id];
if (true === stateStore.has('queue', item._id)) {
stateStore.move('queue', 'history', item._id);
return
}
completed[item._id] = item;
stateStore.add('history', item);
});
socket.value.on('canceled', stream => {
const id = JSON.parse(stream);
if (false === (id in downloading)) {
if (true !== stateStore.has('queue', id)) {
return
}
@ -79,31 +75,28 @@ onMounted(() => {
socket.value.on('cleared', stream => {
const id = JSON.parse(stream);
if (false === (id in completed)) {
return;
if (true !== stateStore.has('history', id)) {
return
}
delete completed[id];
stateStore.remove('history', id);
});
socket.value.on("updated", stream => {
const data = JSON.parse(stream);
let dl = downloading[data._id] ?? {};
let dl = stateStore.get('queue', data._id, {});
data.deleting = dl?.deleting;
downloading[data._id] = data;
stateStore.update('queue', data._id, data);
});
socket.value.on("update", 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;
}
completed[data._id] = data;
});
socket.value.on('cli_close', () => cli_isLoading.value = false);
socket.value.on('cli_output', s => cli_output.value.push(s));
});
</script>

58
ui/store/ConfigStore.js Normal file
View 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
View 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 };
});