Files
alhp-web/frontend/src/stores/packagesStore.ts
vikingowl 145de73133 Add separate loading and error states for currently building
Introduced `loadingCurrentlyBuilding` and `errorCurrentlyBuilding` states to manage the fetching of currently building packages independently. Updated the logic in `fetchCurrentlyBuilding` and related UI bindings to reflect this change, ensuring clearer state handling and improved error tracking.
2025-05-04 23:57:45 +02:00

230 lines
6.0 KiB
TypeScript

import { defineStore } from 'pinia'
import { reactive } from 'vue'
import { components, getPackages } from '@/api'
interface PackageFilters {
status?: components['schemas']['Package']['status'][]
pkgbase?: components['schemas']['Package']['pkgbase']
exact?: boolean
repo?: components['schemas']['Package']['repo']
}
export const usePackagesStore = defineStore('packages', () => {
const state = reactive({
packages: [] as components['schemas']['Package'][],
currentlyBuildingPackages: [] as components['schemas']['Package'][],
total: 0,
offset: 0,
limit: Number(import.meta.env.VITE_LIMIT) || 50,
loading: false,
loadingCurrentlyBuilding: false,
error: null as string | null,
errorCurrentlyBuilding: null as string | null,
lastUpdated: Date.now(),
filters: {
status: undefined,
pkgbase: undefined,
exact: undefined,
repo: undefined
} as PackageFilters
})
// Actions
const fetchPackages = (init = false) => {
state.loading = true
state.error = null
state.packages = []
state.total = 0
if (init) {
initFromUrl()
}
const filter: PackageFilters = {}
if (state.filters.status && state.filters.status.length > 0) {
filter.status = state.filters.status
}
if (state.filters.pkgbase) {
filter.pkgbase = state.filters.pkgbase
}
if (state.filters.exact === true) {
filter.exact = state.filters.exact
}
if (state.filters.repo) {
filter.repo = state.filters.repo
}
// @ts-ignore
getPackages({
limit: state.limit,
offset: state.offset,
...filter
})
.then((response) => {
if (!response) throw new Error('No response from API')
state.packages = response.packages || []
state.total = response.total || 0
state.offset = response.offset || 0
state.limit = response.limit || state.limit
})
.catch((err) => {
if (err.statusCode === 404) {
state.packages = []
state.total = 0
state.offset = 0
state.limit = Number(import.meta.env.VITE_LIMIT) || 50
} else {
state.error = err instanceof Error ? err.message : 'Failed to fetch packages'
console.error('Error fetching packages:', err)
}
})
.finally(() => {
state.loading = false
state.lastUpdated = Date.now()
})
}
const fetchCurrentlyBuilding = () => {
state.loadingCurrentlyBuilding = true
state.errorCurrentlyBuilding = null
state.currentlyBuildingPackages = []
getPackages({
limit: 0,
offset: 0,
status: ['queued', 'building', 'built']
})
.then((response) => {
state.currentlyBuildingPackages = response?.packages || []
})
.catch((err) => {
if (err.statusCode === 404) {
state.currentlyBuildingPackages = []
} else {
state.errorCurrentlyBuilding =
err instanceof Error ? err.message : 'Failed to fetch currently building packages'
console.error('Error fetching queued packages:', err)
}
})
.finally(() => {
state.loadingCurrentlyBuilding = false
})
}
const goToPage = (page: number) => {
state.offset = (page - 1) * state.limit
updateUrlParams()
fetchPackages()
}
const setFilters = (newFilters: PackageFilters, page?: number) => {
state.filters = JSON.parse(JSON.stringify(newFilters))
if (state.filters.exact === false) {
state.filters.exact = undefined
}
if (page) {
state.offset = (page - 1) * state.limit
}
updateUrlParams()
fetchPackages()
}
const resetFilters = () => {
state.filters = {
status: undefined,
pkgbase: undefined,
exact: undefined,
repo: undefined
}
state.offset = 0
state.limit = Number(import.meta.env.VITE_LIMIT) || 50
updateUrlParams()
fetchPackages()
}
const updateUrlParams = () => {
const params = new URLSearchParams()
let page = state.offset / state.limit + 1
// Only add a page parameter if it's not the first page
if (page > 1) {
params.set('page', page.toString())
}
if (state.filters.status && state.filters.status.length > 0) {
state.filters.status.forEach((status: components['schemas']['Package']['status']) => {
if (status) {
params.append('status', status)
}
})
}
if (state.filters.pkgbase) {
params.set('pkgbase', state.filters.pkgbase.toLowerCase())
}
if (state.filters.repo) {
params.set('repo', state.filters.repo)
}
if (state.filters.exact === true) {
params.set('exact', '')
} else {
params.delete('exact')
}
const paramsString = params.toString()
if (paramsString) {
window.history.pushState(null, '', `${window.location.pathname}?${paramsString}`)
} else {
window.history.pushState(null, '', window.location.pathname)
}
}
const initFromUrl = () => {
const urlParams = new URLSearchParams(window.location.search)
if (urlParams.has('page')) {
const pageParam = urlParams.get('page') || '1'
const parsedPage = parseInt(pageParam, 10)
const page = !isNaN(parsedPage) && parsedPage > 0 ? parsedPage : 1
state.offset = (page - 1) * state.limit
}
if (urlParams.has('status')) {
const status = urlParams.getAll('status')
state.filters.status = status as components['schemas']['Package']['status'][]
}
if (urlParams.has('pkgbase')) {
const pkgbase = urlParams.get('pkgbase')
if (pkgbase === null) return
state.filters.pkgbase = pkgbase as components['schemas']['Package']['pkgbase']
}
if (urlParams.has('repo')) {
const repo = urlParams.get('repo')
if (repo === null) return
state.filters.repo = repo as components['schemas']['Package']['repo']
}
if (urlParams.has('exact')) {
state.filters.exact = true
}
}
return {
state,
// Actions
fetchPackages,
fetchCurrentlyBuilding,
goToPage,
setFilters,
resetFilters
}
})