fix(projects): make freshly-added projects editable

Make workspace-less projects flow through aggregated project fetching and keep the settings screen editable immediately after adding one.
This commit is contained in:
huiliaoning
2026-06-27 12:44:16 +08:00
committed by GitHub
parent a908384e5a
commit 26a8a04651
10 changed files with 1531 additions and 22 deletions
@@ -1,5 +1,4 @@
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import type { WorkspaceDescriptor } from "@/stores/session-store";
import { fetchAllWorkspaceDescriptors } from "@/projects/workspace-fetching";
import { buildProjects, type ProjectHost, type ProjectSummary } from "@/utils/projects";
@@ -58,13 +57,14 @@ export async function fetchAggregatedProjects(
serverName: host.serverName,
isOnline,
workspaces: [],
emptyProjects: [],
},
error: null,
};
}
try {
const workspaces: WorkspaceDescriptor[] = await fetchAllWorkspaceDescriptors({
const { workspaces, emptyProjects } = await fetchAllWorkspaceDescriptors({
client,
sort: [{ key: "name", direction: "asc" }],
});
@@ -74,6 +74,7 @@ export async function fetchAggregatedProjects(
serverName: host.serverName,
isOnline,
workspaces,
emptyProjects,
},
error: null,
};
@@ -84,6 +85,7 @@ export async function fetchAggregatedProjects(
serverName: host.serverName,
isOnline,
workspaces: [],
emptyProjects: [],
},
error: {
serverId: host.serverId,
@@ -1,16 +1,33 @@
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import { normalizeWorkspaceDescriptor, type WorkspaceDescriptor } from "@/stores/session-store";
import {
type EmptyProjectDescriptor,
normalizeEmptyProjectDescriptor,
normalizeWorkspaceDescriptor,
type WorkspaceDescriptor,
} from "@/stores/session-store";
export type FetchWorkspacesClient = Pick<DaemonClient, "fetchWorkspaces">;
export type FetchWorkspacesSort = NonNullable<
Parameters<DaemonClient["fetchWorkspaces"]>[0]
>["sort"];
export interface FetchWorkspaceDescriptorsResult {
workspaces: WorkspaceDescriptor[];
/**
* Project parents with no active workspaces. The daemon only rides these on
* the first page of `fetchWorkspaces`, so a freshly-added project that has no
* workspace yet shows up here and nowhere else — drop it and the project is
* invisible to anything that derives projects from workspaces alone.
*/
emptyProjects: EmptyProjectDescriptor[];
}
export async function fetchAllWorkspaceDescriptors(input: {
client: FetchWorkspacesClient;
sort: FetchWorkspacesSort;
}): Promise<WorkspaceDescriptor[]> {
const entries: WorkspaceDescriptor[] = [];
}): Promise<FetchWorkspaceDescriptorsResult> {
const workspaces: WorkspaceDescriptor[] = [];
const emptyProjects = new Map<string, EmptyProjectDescriptor>();
let cursor: string | null = null;
while (true) {
@@ -18,12 +35,16 @@ export async function fetchAllWorkspaceDescriptors(input: {
sort: input.sort,
page: cursor ? { limit: 200, cursor } : { limit: 200 },
});
entries.push(...payload.entries.map((entry) => normalizeWorkspaceDescriptor(entry)));
workspaces.push(...payload.entries.map((entry) => normalizeWorkspaceDescriptor(entry)));
for (const project of payload.emptyProjects ?? []) {
const descriptor = normalizeEmptyProjectDescriptor(project);
emptyProjects.set(descriptor.projectId, descriptor);
}
if (!payload.pageInfo.hasMore || !payload.pageInfo.nextCursor) {
break;
}
cursor = payload.pageInfo.nextCursor;
}
return entries;
return { workspaces, emptyProjects: Array.from(emptyProjects.values()) };
}