119 lines
4.6 KiB
JavaScript
119 lines
4.6 KiB
JavaScript
|
|
import { defineStore } from 'pinia'
|
||
|
|
import { call, on } from './api'
|
||
|
|
|
||
|
|
export const useAppStore = defineStore('app', {
|
||
|
|
state: () => ({
|
||
|
|
bootstrap: { state: 'loading' },
|
||
|
|
projects: [],
|
||
|
|
projectGroups: [],
|
||
|
|
selectedProjectGroupId: Number(localStorage.getItem('cc-project-group-id') || 0),
|
||
|
|
dashboard: { projects: 0, totalLines: 0, commits: 0 },
|
||
|
|
settings: { theme: 'dark', locale: 'zh-CN', glassOpacity: 55, gitScope: 'current', autoRefresh: true, loadingStyle: 'fullscreen-orbit' },
|
||
|
|
tasks: {},
|
||
|
|
batchTaskIds: [],
|
||
|
|
toast: null,
|
||
|
|
toastTimer: null,
|
||
|
|
toastLeaveTimer: null,
|
||
|
|
loading: false
|
||
|
|
}),
|
||
|
|
actions: {
|
||
|
|
async boot() {
|
||
|
|
this.bootstrap = await call('GetBootstrapStatus')
|
||
|
|
if (this.bootstrap.state === 'ready') {
|
||
|
|
this.settings = await call('GetSettings')
|
||
|
|
this.applyAppearance(this.settings)
|
||
|
|
await this.refresh()
|
||
|
|
}
|
||
|
|
},
|
||
|
|
applyAppearance(settings) {
|
||
|
|
this.settings = { ...this.settings, ...settings }
|
||
|
|
let theme = this.settings.theme || 'dark'
|
||
|
|
if (theme === 'system') theme = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||
|
|
document.documentElement.dataset.theme = theme
|
||
|
|
document.documentElement.style.setProperty('--glass-user-opacity', String((this.settings.glassOpacity || 55) / 100))
|
||
|
|
localStorage.setItem('cc-settings', JSON.stringify(this.settings))
|
||
|
|
},
|
||
|
|
async saveSettings(patch) {
|
||
|
|
const next = { ...this.settings, ...patch }
|
||
|
|
await call('SaveSettings', next)
|
||
|
|
this.applyAppearance(next)
|
||
|
|
return next
|
||
|
|
},
|
||
|
|
showToast(payload) {
|
||
|
|
clearTimeout(this.toastTimer)
|
||
|
|
clearTimeout(this.toastLeaveTimer)
|
||
|
|
this.toast = { ...payload, leaving: false, muted: false, id: Date.now() }
|
||
|
|
this.toastTimer = setTimeout(() => {
|
||
|
|
if (this.toast) this.toast.muted = true
|
||
|
|
}, 3000)
|
||
|
|
this.toastLeaveTimer = setTimeout(() => {
|
||
|
|
if (this.toast) this.toast.leaving = true
|
||
|
|
setTimeout(() => {
|
||
|
|
this.toast = null
|
||
|
|
}, 360)
|
||
|
|
}, 5000)
|
||
|
|
},
|
||
|
|
closeToast() {
|
||
|
|
clearTimeout(this.toastTimer)
|
||
|
|
clearTimeout(this.toastLeaveTimer)
|
||
|
|
if (this.toast) this.toast.leaving = true
|
||
|
|
setTimeout(() => {
|
||
|
|
this.toast = null
|
||
|
|
}, 220)
|
||
|
|
},
|
||
|
|
async refresh() {
|
||
|
|
this.loading = true
|
||
|
|
try {
|
||
|
|
this.projectGroups = await call('ListProjectGroups')
|
||
|
|
if (this.selectedProjectGroupId && !this.projectGroups.some(g => g.id === this.selectedProjectGroupId)) {
|
||
|
|
this.setProjectGroup(0)
|
||
|
|
}
|
||
|
|
const groupId = this.selectedProjectGroupId || 0
|
||
|
|
;[this.projects, this.dashboard] = await Promise.all([
|
||
|
|
groupId ? call('ListProjectsByGroup', groupId) : call('ListProjects'),
|
||
|
|
groupId ? call('GetDashboardByGroup', groupId) : call('GetDashboard')
|
||
|
|
])
|
||
|
|
} finally {
|
||
|
|
this.loading = false
|
||
|
|
}
|
||
|
|
},
|
||
|
|
async changeProjectGroup(groupId) {
|
||
|
|
this.setProjectGroup(groupId)
|
||
|
|
await this.refresh()
|
||
|
|
},
|
||
|
|
setProjectGroup(groupId, persist = true) {
|
||
|
|
this.selectedProjectGroupId = Number(groupId) || 0
|
||
|
|
if (persist) localStorage.setItem('cc-project-group-id', String(this.selectedProjectGroupId))
|
||
|
|
},
|
||
|
|
listen() {
|
||
|
|
return on('analysis:progress', e => {
|
||
|
|
delete this.tasks.__batch_pending__
|
||
|
|
this.tasks[e.taskId] = e
|
||
|
|
if (['completed', 'error', 'cancelled'].includes(e.stage)) {
|
||
|
|
if (this.batchTaskIds.includes(e.taskId)) {
|
||
|
|
this.batchTaskIds = this.batchTaskIds.filter(id => id !== e.taskId)
|
||
|
|
if (this.batchTaskIds.length) {
|
||
|
|
this.tasks.__batch_pending__ = { taskId: '__batch_pending__', projectId: 0, stage: 'queued', progress: 100, messageKey: e.messageKey, params: e.params }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
this.showToast({ type: e.stage === 'completed' ? 'success' : 'error', key: e.messageKey, params: e.params })
|
||
|
|
this.refresh()
|
||
|
|
}
|
||
|
|
})
|
||
|
|
},
|
||
|
|
async analyze(id, kind = 'all') {
|
||
|
|
const task = await call('StartAnalysis', id, kind)
|
||
|
|
this.tasks[task] = { taskId: task, projectId: id, stage: 'start', progress: 1, messageKey: 'task.start' }
|
||
|
|
return task
|
||
|
|
},
|
||
|
|
async batchAnalyze(groupId = 0) {
|
||
|
|
const ids = groupId ? await call('StartBatchAnalysisByGroup', groupId) : await call('StartBatchAnalysis')
|
||
|
|
this.batchTaskIds = ids || []
|
||
|
|
if (this.batchTaskIds.length && !Object.values(this.tasks).some(x => !['completed', 'error', 'cancelled'].includes(x.stage))) {
|
||
|
|
this.tasks.__batch_pending__ = { taskId: '__batch_pending__', projectId: 0, stage: 'queued', progress: 1, messageKey: 'task.start' }
|
||
|
|
}
|
||
|
|
return this.batchTaskIds
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|