Merge branch 'investigate/portless' into dev
# Conflicts: # packages/app/e2e/helpers/workspace-setup.ts # packages/app/src/components/sidebar-workspace-list.tsx # packages/app/src/contexts/session-context.tsx # packages/app/src/hooks/use-sidebar-workspaces-list.test.ts # packages/app/src/screens/workspace/workspace-tab-menu.ts # packages/app/src/stores/workspace-setup-store.ts # packages/app/src/stores/workspace-tabs-store.ts # packages/app/src/utils/sidebar-project-row-model.test.ts # packages/app/src/utils/sidebar-shortcuts.test.ts # packages/app/src/utils/workspace-tab-identity.ts # packages/server/src/server/bootstrap.ts # packages/server/src/server/worktree-session.ts
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { WorkspaceServicePayload } from "@server/shared/messages";
|
||||
import {
|
||||
appendMissingOrderKeys,
|
||||
applyStoredOrdering,
|
||||
@@ -24,6 +25,7 @@ function workspace(
|
||||
| "workspaceDirectory"
|
||||
| "projectKind"
|
||||
| "workspaceKind"
|
||||
| "services"
|
||||
>
|
||||
>,
|
||||
): WorkspaceDescriptor {
|
||||
@@ -39,9 +41,26 @@ function workspace(
|
||||
status: input.status,
|
||||
activityAt: input.activityAt,
|
||||
diffStat: null,
|
||||
services: input.services ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
const runningService: WorkspaceServicePayload = {
|
||||
serviceName: "web",
|
||||
hostname: "main.web.localhost",
|
||||
port: 3000,
|
||||
url: "http://main.web.localhost:6767",
|
||||
status: "running",
|
||||
};
|
||||
|
||||
const stoppedService: WorkspaceServicePayload = {
|
||||
serviceName: "api",
|
||||
hostname: "main.api.localhost",
|
||||
port: 3001,
|
||||
url: "http://main.api.localhost:6767",
|
||||
status: "stopped",
|
||||
};
|
||||
|
||||
describe("applyStoredOrdering", () => {
|
||||
it("keeps unknown items on the baseline while applying stored order", () => {
|
||||
const result = applyStoredOrdering({
|
||||
@@ -122,6 +141,27 @@ describe("buildSidebarProjectsFromWorkspaces", () => {
|
||||
expect(projects[0]?.workspaces[0]?.statusBucket).toBe("failed");
|
||||
});
|
||||
|
||||
it("threads services into workspace rows and derives hasRunningServices", () => {
|
||||
const projects = buildSidebarProjectsFromWorkspaces({
|
||||
serverId: "srv",
|
||||
workspaces: [
|
||||
workspace({
|
||||
id: "/repo/main",
|
||||
projectId: "project-1",
|
||||
name: "main",
|
||||
status: "running",
|
||||
activityAt: new Date("2026-01-01T00:00:00.000Z"),
|
||||
services: [runningService, stoppedService],
|
||||
}),
|
||||
],
|
||||
projectOrder: [],
|
||||
workspaceOrderByScope: {},
|
||||
});
|
||||
|
||||
expect(projects[0]?.workspaces[0]?.services).toEqual([runningService, stoppedService]);
|
||||
expect(projects[0]?.workspaces[0]?.hasRunningServices).toBe(true);
|
||||
});
|
||||
|
||||
it("preserves stored project order even when activity changes", () => {
|
||||
const initialWorkspaces: WorkspaceDescriptor[] = [
|
||||
workspace({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useSyncExternalStore } from "react";
|
||||
import type { WorkspaceDescriptorPayload } from "@server/shared/messages";
|
||||
import { normalizeWorkspaceDescriptor, useSessionStore } from "@/stores/session-store";
|
||||
import { getHostRuntimeStore } from "@/runtime/host-runtime";
|
||||
import { useSidebarOrderStore } from "@/stores/sidebar-order-store";
|
||||
@@ -23,6 +24,8 @@ export interface SidebarWorkspaceEntry {
|
||||
activityAt: Date | null;
|
||||
statusBucket: SidebarStateBucket;
|
||||
diffStat: { additions: number; deletions: number } | null;
|
||||
services: WorkspaceDescriptor["services"];
|
||||
hasRunningServices: boolean;
|
||||
}
|
||||
|
||||
export interface SidebarProjectEntry {
|
||||
@@ -141,6 +144,8 @@ export function buildSidebarProjectsFromWorkspaces(input: {
|
||||
activityAt: workspace.activityAt,
|
||||
statusBucket: workspace.status,
|
||||
diffStat: workspace.diffStat,
|
||||
services: workspace.services,
|
||||
hasRunningServices: workspace.services.some((service) => service.status === "running"),
|
||||
};
|
||||
|
||||
project.workspaces.push(row);
|
||||
@@ -264,8 +269,12 @@ function toWorkspaceDescriptor(payload: {
|
||||
name: string;
|
||||
status: WorkspaceDescriptor["status"];
|
||||
activityAt: string | null;
|
||||
services?: WorkspaceDescriptorPayload["services"];
|
||||
}): WorkspaceDescriptor {
|
||||
return normalizeWorkspaceDescriptor(payload);
|
||||
return normalizeWorkspaceDescriptor({
|
||||
...payload,
|
||||
services: payload.services ?? [],
|
||||
});
|
||||
}
|
||||
|
||||
export function useSidebarWorkspacesList(options?: {
|
||||
|
||||
Reference in New Issue
Block a user