import { CheckIcon, LoaderIcon, SearchIcon } from "@chopin/icons"; import { useEffect, useRef, useState } from "react"; import * as Api from "./api"; import { NavigationDialog } from "./navigation-dialog"; import { PaletteListbox } from "./navigation-palette"; import { installedRepositoryGroups, loadRepositorySnapshot, readRepositoryCache, repositoryCacheIsStale, writeRepositoryCache, } from "./repository-snapshot"; import { TerminalAlert } from "./terminal-alert"; import type { RepositorySnapshot } from "./repository-snapshot"; import type { NavigationDialogMotion } from "./navigation-dialog"; function message(error: unknown): string { return error instanceof Error ? error.message : "Could not load repositories."; } export function AddProjectDialog( { added, motion, onAdded, onDismiss, userId, }: { added: Api.NavigationProject[]; motion: NavigationDialogMotion; onAdded: (project: Api.NavigationProject) => void; onDismiss: () => void; userId: string; }, ) { let input = useRef(null); let [snapshot, setSnapshot] = useState(() => readRepositoryCache(userId) ); let [error, setError] = useState(); let [query, setQuery] = useState(""); let [retry, setRetry] = useState(0); let [adding, setAdding] = useState(); useEffect(() => { let active = true; let cached = readRepositoryCache(userId); if (cached) setSnapshot(cached); setError(undefined); if (retry === 0 && cached && !repositoryCacheIsStale(cached)) return; loadRepositorySnapshot(userId, cached, value => { if (active) setSnapshot(value); }).then(value => { if (active) { writeRepositoryCache(value); setSnapshot(value); } }, reason => { if (active) setError(reason); }); return () => { active = false; }; }, [retry, userId]); let normalized = query.trim().toLocaleLowerCase(); let repositories = snapshot ? installedRepositoryGroups(snapshot).flatMap(group => group.repositories) : []; let addedIds = new Set(added.map(project => project.repositoryId)); let visible = repositories.filter(repository => !normalized || `${repository.owner}/${repository.name}`.toLocaleLowerCase().includes(normalized) ); async function select(repository: Api.Repository) { if (adding || addedIds.has(repository.id)) return; setAdding(repository.id); setError(undefined); try { onAdded(await Api.addProject(repository.owner, repository.name)); onDismiss(); } catch (reason) { setError(reason); setAdding(undefined); } } return (
{!snapshot && error === undefined && (

)} {error !== undefined && (
{message(error)}
)} {snapshot && visible.length === 0 && error === undefined && ( normalized || repositories.length > 0 ? (

No matching repositories

) : (

No repositories to add yet

Install the GitHub App for Chopin on the repositories you want to write about.

Install the GitHub App for Chopin
) )} {visible.length > 0 && ( !addedIds.has(repository.id)} input={input} itemKey={repository => repository.id} itemLabel={repository => `${repository.owner}/${repository.name}${ addedIds.has(repository.id) ? ", added" : "" }`} items={visible} label="Repositories" onChoose={repository => void select(repository)} query={query} renderItem={repository => { let alreadyAdded = addedIds.has(repository.id); let busy = adding === repository.id; return ( <> {repository.owner}/ {repository.name} {alreadyAdded ? ( ) : ( {busy ? "Adding…" : "Add"} )} ); }} /> )}
); }