35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import { computed, inject, type InjectionKey, type MaybeRefOrGetter } from 'vue'
|
|
import { usePolling } from '../../composables/usePolling'
|
|
import { projectsApi } from './api'
|
|
import type { ProjectDetail } from './types'
|
|
import type { Checkpoint } from '../workflows/types'
|
|
import type { Ref } from 'vue'
|
|
|
|
/** 同一项目的各个 graph 共用一份查询,避免每个面板重复请求。 */
|
|
export function useProjectData(id: Ref<string>, interval: MaybeRefOrGetter<number | false> = 6000) {
|
|
const query = usePolling(
|
|
id,
|
|
async (projectId, signal) => {
|
|
const [project, checkpoints] = await Promise.all([
|
|
projectsApi.detail(projectId, signal),
|
|
projectsApi.checkpoints(projectId, signal)
|
|
])
|
|
return { project, checkpoints }
|
|
},
|
|
interval
|
|
)
|
|
const project = computed<ProjectDetail | null>(() => query.data.value?.project ?? null)
|
|
const checkpoints = computed<Checkpoint[]>(() => query.data.value?.checkpoints ?? [])
|
|
return { ...query, project, checkpoints }
|
|
}
|
|
|
|
/** 项目布局向子页面提供的类型安全上下文。 */
|
|
export const projectContextKey: InjectionKey<ReturnType<typeof useProjectData>> = Symbol('project-context')
|
|
|
|
/** 读取项目上下文,错误布局在开发阶段立即暴露。 */
|
|
export function useProjectContext() {
|
|
const context = inject(projectContextKey)
|
|
if (!context) throw new Error('项目页面必须位于 ProjectLayout 中')
|
|
return context
|
|
}
|