Skip to content
Source
Sign inSign up

projectClones.ts

54 lines2.3 KB

1import { useAtomValue } from "@effect/atom-react";
2import { parseScopedProjectKey, scopedProjectKey } from "@t3tools/client-runtime/environment";
3import type { EnvironmentId, ProjectCloneSnapshot, ScopedProjectRef } from "@t3tools/contracts";
4import { AsyncResult, Atom } from "effect/reactivity";
5​
6import { environmentServerConfigsAtom } from "./server";
7import { sourceControlEnvironment } from "./sourceControl";
8​
9const EMPTY_CLONES: ReadonlyArray<ProjectCloneSnapshot> = [];
10const EMPTY_CLONE_ATOM = Atom.make<ProjectCloneSnapshot | null>(null).pipe(
11 Atom.withLabel("web-project-clone:empty"),
12);
13​
14export const environmentProjectClonesAtom = Atom.family((environmentId: EnvironmentId) =>
15 Atom.make((get): ReadonlyArray<ProjectCloneSnapshot> => {
16 if (!get(environmentServerConfigsAtom).has(environmentId)) return EMPTY_CLONES;
17 const result = get(sourceControlEnvironment.projectClones({ environmentId, input: {} }));
18 return AsyncResult.getOrElse(result, () => EMPTY_CLONES);
19 }).pipe(Atom.withLabel(`web-project-clones:${environmentId}`)),
20);
21​
22const projectCloneAtom = Atom.family((key: string) => {
23 const ref = parseScopedProjectKey(key);
24 return Atom.make((get): ProjectCloneSnapshot | null => {
25 if (ref === null) return null;
26 const clones = get(environmentProjectClonesAtom(ref.environmentId));
27 return clones.find((clone) => clone.projectId === ref.projectId) ?? null;
28 }).pipe(Atom.withLabel(`web-project-clone:${key}`));
29});
30​
31export function useProjectClone(ref: ScopedProjectRef | null): ProjectCloneSnapshot | null {
32 return useAtomValue(ref === null ? EMPTY_CLONE_ATOM : projectCloneAtom(scopedProjectKey(ref)));
34​
35export function useEnvironmentProjectClones(
36 environmentId: EnvironmentId,
37): ReadonlyArray<ProjectCloneSnapshot> {
38 return useAtomValue(environmentProjectClonesAtom(environmentId));
40​
41const silencedCloneToasts = new Set<string>();
42​
43/**
44 * Keeps a clone's progress out of toasts once the user is looking at its
45 * project, whose composer shows the same progress. Failures still toast
46 * whenever the project is not on screen.
47 */
48export function silenceProjectCloneToasts(ref: ScopedProjectRef) {
49 silencedCloneToasts.add(scopedProjectKey(ref));
51​
52export function isProjectCloneToastSilenced(ref: ScopedProjectRef): boolean {
53 return silencedCloneToasts.has(scopedProjectKey(ref));