import { defineStore } from "pinia"; import type { FileTree, ResourceIn, ResourceOut, ResourceVersionIn, ResourceVersionOut, UserRequestAnswer, UserSynchronizationRequestIn, UserSynchronizationRequestOut, } from "@/client/resource"; import { ResourceService, ResourceVersionService, Status, } from "@/client/resource"; import { useAuthStore } from "@/stores/users"; import { useNameStore } from "@/stores/names"; function parseFileTree(parent: string, tree?: FileTree | null): string[] { if (tree == undefined || tree.contents == undefined) { return []; } let files: string[] = []; const currentName = parent.length > 0 ? parent + tree.name + "/" : "/"; for (const dir of tree.contents) { files.push(currentName + dir.name); if (dir.type === "directory") { files = files.concat(parseFileTree(currentName, dir)); } } return files; } export const useResourceStore = defineStore({ id: "resources", state: () => ({ resourceMapping: {}, ownResourceMapping: {}, reviewableResourceMapping: {}, syncRequestMapping: {}, resourceTree: {}, resourceTreeList: {}, __syncRequestsFetched: false, }) as { resourceMapping: Record<string, ResourceOut>; ownResourceMapping: Record<string, ResourceOut>; reviewableResourceMapping: Record<string, ResourceOut>; syncRequestMapping: Record<string, UserSynchronizationRequestOut>; resourceTree: Record<string, FileTree | null>; resourceTreeList: Record<string, string[]>; __syncRequestsFetched: boolean; }, getters: { resources(): ResourceOut[] { return Object.values(this.resourceMapping); }, versionMapping(): Record<string, ResourceVersionOut> { const mapping: Record<string, ResourceVersionOut> = {}; for (const resource of this.resources) { for (const version of resource.versions) { mapping[version.resource_version_id] = version; } } return mapping; }, getLatestVersion(): (resource_id: string) => string { return (resource_id) => { for (const version of this.resourceMapping[resource_id]?.versions ?? []) { if (version.status === Status.LATEST) { return version.resource_version_id; } } return ""; }; }, ownResources(): ResourceOut[] { return Object.values(this.ownResourceMapping); }, reviewableResources(): ResourceOut[] { return Object.values(this.reviewableResourceMapping); }, syncRequests(): UserSynchronizationRequestOut[] { return Object.values(this.syncRequestMapping); }, }, actions: { fetchResource( resource_id: string, versionStatus?: Status[], ): Promise<ResourceOut> { return ResourceService.resourceGetResource( resource_id, versionStatus, ).then((resource) => { const nameStore = useNameStore(); nameStore.addNameToMapping(resource.resource_id, resource.name); for (const version of resource.versions) { nameStore.addNameToMapping( version.resource_version_id, version.release, ); } return resource; }); }, fetchSyncRequests( onFinally?: () => void, ): Promise<UserSynchronizationRequestOut[]> { if (this.__syncRequestsFetched) { onFinally?.(); } return ResourceService.resourceListSyncRequests() .then((requests) => { this.__syncRequestsFetched = true; const newMapping: Record<string, UserSynchronizationRequestOut> = {}; for (const request of requests) { newMapping[request.resource_version_id] = request; } this.syncRequestMapping = newMapping; return requests; }) .finally(onFinally); }, fetchResources( maintainerId?: string, versionStatus?: Status[], searchString?: string, _public?: boolean, ): Promise<ResourceOut[]> { return ResourceService.resourceListResources( maintainerId, versionStatus, searchString, _public, ).then((resources) => { const nameStore = useNameStore(); for (const resource of resources) { nameStore.addNameToMapping(resource.resource_id, resource.name); for (const version of resource.versions) { nameStore.addNameToMapping( version.resource_version_id, version.release, ); } } return resources; }); }, fetchResourceTree( resource_id: string, resource_version_id: string, onFinally?: () => void, ): Promise<FileTree> { if (this.resourceTree[resource_version_id] === null) { onFinally?.(); } return ResourceVersionService.resourceVersionResourceFileTree( resource_version_id, resource_id, ) .then((tree) => { this.resourceTree[resource_version_id] = tree[0]; this.resourceTreeList[resource_version_id] = parseFileTree( "", tree[0], ); return tree; }) .catch((err) => { this.resourceTree[resource_version_id] = null; return err; }) .finally(onFinally); }, fetchReviewableResources(onFinally?: () => void): Promise<ResourceOut[]> { if (Object.keys(this.reviewableResourceMapping).length > 0) { onFinally?.(); } return this.fetchResources(undefined, [Status.WAIT_FOR_REVIEW]) .then((resources) => { const newMapping: Record<string, ResourceOut> = {}; for (const resource of resources) { newMapping[resource.resource_id] = resource; } this.reviewableResourceMapping = newMapping; return resources; }) .finally(onFinally); }, fetchPublicResources(onFinally?: () => void): Promise<ResourceOut[]> { if (this.resources.length > 0) { onFinally?.(); } return this.fetchResources(undefined, [ Status.APPROVED, Status.SYNC_REQUESTED, Status.SYNCHRONIZING, Status.SYNC_ERROR, Status.SYNCHRONIZED, Status.SETTING_LATEST, Status.LATEST, Status.CLUSTER_DELETE_ERROR, ]) .then((resources) => { const newMapping: Record<string, ResourceOut> = {}; for (const resource of resources) { newMapping[resource.resource_id] = resource; } this.resourceMapping = newMapping; return resources; }) .finally(onFinally); }, fetchOwnResource( resource_id: string, onFinally?: () => void, ): Promise<ResourceOut> { if (this.ownResourceMapping[resource_id]) { onFinally?.(); } return this.fetchResource(resource_id) .then((resource) => { this.ownResourceMapping[resource.resource_id] = resource; return resource; }) .finally(onFinally); }, fetchOwnResources(onFinally?: () => void): Promise<ResourceOut[]> { const authStore = useAuthStore(); if (this.ownResources.length > 0) { onFinally?.(); } return this.fetchResources(authStore.currentUID) .then((resources) => { const newMapping: Record<string, ResourceOut> = {}; for (const resource of resources) { newMapping[resource.resource_id] = resource; } this.ownResourceMapping = newMapping; return resources; }) .finally(onFinally); }, async createResource(resource: ResourceIn): Promise<ResourceOut> { const createdResource = await ResourceService.resourceCreateResource(resource); this.ownResourceMapping[createdResource.resource_id] = createdResource; const nameStore = useNameStore(); nameStore.addNameToMapping( createdResource.resource_id, createdResource.name, ); nameStore.addNameToMapping( createdResource.versions[0].resource_version_id, createdResource.versions[0].release, ); return createdResource; }, requestSynchronization( resourceVersion: ResourceVersionOut, request: UserSynchronizationRequestIn, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionRequestResourceVersionSync( resourceVersion.resource_id, resourceVersion.resource_version_id, request, ) .then((changedResourceVersion) => { const versionIndex = this.resourceMapping[ changedResourceVersion.resource_id ]?.versions?.findIndex( (version) => version.resource_version_id == changedResourceVersion.resource_version_id, ); if (versionIndex != undefined && versionIndex > -1) { this.resourceMapping[changedResourceVersion.resource_id].versions[ versionIndex ] = changedResourceVersion; } return changedResourceVersion; }) .then((changedResourceVersion) => { const versionIndex = this.ownResourceMapping[ changedResourceVersion.resource_id ]?.versions?.findIndex( (version) => version.resource_version_id == changedResourceVersion.resource_version_id, ); if (versionIndex != undefined && versionIndex > -1) { this.ownResourceMapping[ changedResourceVersion.resource_id ].versions[versionIndex] = changedResourceVersion; } return changedResourceVersion; }); }, requestReview( resourceVersion: ResourceVersionOut, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionRequestResourceVersionReview( resourceVersion.resource_id, resourceVersion.resource_version_id, ).then((changedResourceVersion) => { if ( this.ownResourceMapping[changedResourceVersion.resource_id] == undefined ) { this.fetchOwnResource(resourceVersion.resource_id); return changedResourceVersion; } const versionIndex = this.ownResourceMapping[ changedResourceVersion.resource_id ].versions.findIndex( (version) => version.resource_version_id == changedResourceVersion.resource_version_id, ); if (versionIndex > -1) { this.ownResourceMapping[changedResourceVersion.resource_id].versions[ versionIndex ] = changedResourceVersion; } else { this.ownResourceMapping[ changedResourceVersion.resource_id ].versions.push(changedResourceVersion); } return changedResourceVersion; }); }, updateResource( resource_id: string, version: ResourceVersionIn, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionRequestResourceVersion( resource_id, version, ).then((versionOut) => { if (this.ownResourceMapping[versionOut.resource_id] == undefined) { this.fetchOwnResource(versionOut.resource_id); return versionOut; } useNameStore().addNameToMapping( versionOut.resource_version_id, versionOut.release, ); this.ownResourceMapping[versionOut.resource_id].versions.push( versionOut, ); return versionOut; }); }, reviewResource( resourceVersion: ResourceVersionOut, requestAnswer: UserRequestAnswer, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionResourceVersionReview( resourceVersion.resource_id, resourceVersion.resource_version_id, requestAnswer, ).then(this._updateReviewableResourceVersion); }, syncResource( resourceVersion: ResourceVersionOut, requestAnswer: UserRequestAnswer, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionResourceVersionSync( resourceVersion.resource_id, resourceVersion.resource_version_id, requestAnswer, ).then((version) => { delete this.syncRequestMapping[version.resource_version_id]; return version; }); }, _updateReviewableResourceVersion( version: ResourceVersionOut, ): ResourceVersionOut { if (this.reviewableResourceMapping[version.resource_id] == undefined) { return version; } const versionIndex = this.reviewableResourceMapping[ version.resource_id ].versions.findIndex( (version) => version.resource_version_id == version.resource_version_id, ); if (versionIndex > -1) { this.reviewableResourceMapping[version.resource_id].versions[ versionIndex ] = version; } else { this.reviewableResourceMapping[version.resource_id].versions.push( version, ); } return version; }, setLatestResource( resourceVersion: ResourceVersionOut, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionResourceVersionLatest( resourceVersion.resource_id, resourceVersion.resource_version_id, ); }, deleteOnCluster( resourceVersion: ResourceVersionOut, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionDeleteResourceVersionCluster( resourceVersion.resource_id, resourceVersion.resource_version_id, ); }, deleteInS3( resourceVersion: ResourceVersionOut, ): Promise<ResourceVersionOut> { return ResourceVersionService.resourceVersionDeleteResourceVersionS3( resourceVersion.resource_id, resourceVersion.resource_version_id, ); }, }, });