Root location folds away once there is nothing left to do
Everything under it is in order most of the time, and a card that is four paragraphs of "fine" pushes the settings that are not fine off the screen. So it shuts, with a check on the right, and opens on a click. "Finished" is three bits reported upward by the parts that own them: the path is saved, the checkout is a repository, and media/ both exists and is current. None of those is knowable in the parent — each child fetches its own status — and lifting all of it up to answer one question would be a far worse trade than three booleans. It is only collapsible while settled. A block you can shut on unfinished setup is a way to hide the thing you came here to fix. And the children are NOT RENDERED while it is shut rather than hidden, because a collapsed block whose children still poll is a settled panel making requests all afternoon about something nobody is looking at. The `null` in `collapsed` is a sentinel for "nobody has decided", which is what lets a deliberate expand survive. Setting it to false while unsettled spent it on the first render — before any status had arrived — so the block could never fold itself away at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+15
-2
@@ -31,7 +31,13 @@ type Status = { path: string; present: boolean; blocked: boolean; children: Chil
|
||||
const count = (entries: number | null) =>
|
||||
entries === null ? '' : entries === 0 ? 'empty' : `${entries} item${entries === 1 ? '' : 's'}`;
|
||||
|
||||
export const MediaFolder = ({ rootPath }: { rootPath: string }) => {
|
||||
export const MediaFolder = ({
|
||||
rootPath,
|
||||
onSettled,
|
||||
}: {
|
||||
rootPath: string;
|
||||
onSettled?: (settled: boolean) => void;
|
||||
}) => {
|
||||
const client = useClient();
|
||||
const clientRef = useRef(client);
|
||||
clientRef.current = client;
|
||||
@@ -39,6 +45,9 @@ export const MediaFolder = ({ rootPath }: { rootPath: string }) => {
|
||||
const [status, setStatus] = useState<Status | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
/* The folders existing is only half of finished; the other half is `derived/` being current, which
|
||||
only `MediaSync` knows. Both have to be true before this reports settled upward. */
|
||||
const [synced, setSynced] = useState(false);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
try {
|
||||
@@ -55,6 +64,10 @@ export const MediaFolder = ({ rootPath }: { rootPath: string }) => {
|
||||
void load();
|
||||
}, [load, rootPath]);
|
||||
|
||||
useEffect(() => {
|
||||
onSettled?.(Boolean(status?.complete) && synced);
|
||||
}, [status?.complete, synced, onSettled]);
|
||||
|
||||
const create = async () => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
@@ -126,7 +139,7 @@ export const MediaFolder = ({ rootPath }: { rootPath: string }) => {
|
||||
|
||||
{/* Only once both folders exist. Until then the button would be asking to write into a directory
|
||||
that is not there, and Create above is the thing to press. */}
|
||||
{status.complete && <MediaSync />}
|
||||
{status.complete && <MediaSync onSettled={setSynced} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user