Migrate data management to OpenAPI-based approach
Replaced manual data handling and filtering logic with an auto-generated OpenAPI client. Introduced new modular Pinia stores for stats and packages, improving maintainability and decoupling data management. Removed outdated custom implementations to streamline the codebase.
This commit is contained in:
212
frontend/src/stores/packagesStore.ts
Normal file
212
frontend/src/stores/packagesStore.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { reactive } from 'vue'
|
||||
import { components, getPackages } from '@/api'
|
||||
|
||||
export interface PackageFilters {
|
||||
status?: components['schemas']['Package']['status'][]
|
||||
pkgbase?: components['schemas']['Package']['pkgbase']
|
||||
exact?: boolean | undefined
|
||||
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,
|
||||
error: null as string | null,
|
||||
lastUpdated: Date.now(),
|
||||
filters: {
|
||||
status: undefined as components['schemas']['Package']['status'][] | undefined,
|
||||
pkgbase: undefined as components['schemas']['Package']['pkgbase'] | undefined,
|
||||
exact: undefined as boolean | undefined,
|
||||
repo: undefined as components['schemas']['Package']['repo'] | undefined
|
||||
} as PackageFilters
|
||||
})
|
||||
|
||||
// Actions
|
||||
const fetchPackages = (init = false) => {
|
||||
state.loading = true
|
||||
state.error = null
|
||||
|
||||
if (init) {
|
||||
initFromUrl()
|
||||
}
|
||||
|
||||
const filter = {}
|
||||
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'] = ''
|
||||
}
|
||||
if (state.filters.repo) {
|
||||
filter['repo'] = state.filters.repo
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
const fetchCurrentlyBuilding = () => {
|
||||
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.error =
|
||||
err instanceof Error ? err.message : 'Failed to fetch currently building packages'
|
||||
console.error('Error fetching queued packages:', err)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.loading = 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 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) => {
|
||||
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.limitq
|
||||
}
|
||||
|
||||
if (urlParams.has('status')) {
|
||||
state.filters.status = urlParams.getAll('status')
|
||||
}
|
||||
|
||||
if (urlParams.has('pkgbase')) {
|
||||
state.filters.pkgbase = urlParams.get('pkgbase')
|
||||
}
|
||||
|
||||
if (urlParams.has('repo')) {
|
||||
state.filters.repo = urlParams.get('repo')
|
||||
}
|
||||
|
||||
if (urlParams.has('exact')) {
|
||||
state.filters.exact = true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
|
||||
// Actions
|
||||
fetchPackages,
|
||||
fetchCurrentlyBuilding,
|
||||
goToPage,
|
||||
setFilters,
|
||||
resetFilters
|
||||
}
|
||||
})
|
Reference in New Issue
Block a user