@cueloop/client 0.1.0-alpha.70 → 0.1.0-alpha.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cueloop/client",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.71",
|
|
4
4
|
"description": "The cueloop review UI: projection renderer, keyboard grammar, review rail",
|
|
5
5
|
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cueloop/daemon": "0.1.0-alpha.
|
|
31
|
-
"@cueloop/extension-api": "0.1.0-alpha.
|
|
32
|
-
"@cueloop/integration-obsidian": "0.1.0-alpha.
|
|
33
|
-
"@cueloop/schema": "0.1.0-alpha.
|
|
30
|
+
"@cueloop/daemon": "0.1.0-alpha.71",
|
|
31
|
+
"@cueloop/extension-api": "0.1.0-alpha.71",
|
|
32
|
+
"@cueloop/integration-obsidian": "0.1.0-alpha.71",
|
|
33
|
+
"@cueloop/schema": "0.1.0-alpha.71",
|
|
34
34
|
"@opentui/core": "^0.5.8",
|
|
35
35
|
"@opentui/keymap": "0.5.8",
|
|
36
36
|
"@opentui/react": "^0.5.8",
|
package/src/App.tsx
CHANGED
|
@@ -878,6 +878,16 @@ export function App({
|
|
|
878
878
|
dispatch({ type: "openSubmit" });
|
|
879
879
|
};
|
|
880
880
|
|
|
881
|
+
const threadFooter = (
|
|
882
|
+
<ThreadFooter
|
|
883
|
+
repo={projectName(activeSession.workspace)}
|
|
884
|
+
branch={activeSession.workspace.branch}
|
|
885
|
+
onSubmit={onSubmitRequest}
|
|
886
|
+
canSubmit={canSubmitReview(isOwner, resolved, observer)}
|
|
887
|
+
theme={theme}
|
|
888
|
+
/>
|
|
889
|
+
);
|
|
890
|
+
|
|
881
891
|
return (
|
|
882
892
|
<SlashSkillsContext.Provider value={skills}>
|
|
883
893
|
<ThemeProvider theme={theme}>
|
|
@@ -969,13 +979,7 @@ export function App({
|
|
|
969
979
|
/>
|
|
970
980
|
)}
|
|
971
981
|
</box>
|
|
972
|
-
|
|
973
|
-
repo={projectName(activeSession.workspace)}
|
|
974
|
-
branch={activeSession.workspace.branch}
|
|
975
|
-
onSubmit={onSubmitRequest}
|
|
976
|
-
canSubmit={canSubmitReview(isOwner, resolved, observer)}
|
|
977
|
-
theme={theme}
|
|
978
|
-
/>
|
|
982
|
+
{threadFooter}
|
|
979
983
|
</box>
|
|
980
984
|
}
|
|
981
985
|
changesOpen={workbench.changesOpen}
|
|
@@ -985,6 +989,7 @@ export function App({
|
|
|
985
989
|
onToggleRight={workbench.toggleRight}
|
|
986
990
|
projectMode={workbench.projectMode}
|
|
987
991
|
zoomHideThread={workbench.zoomed}
|
|
992
|
+
changesFooter={threadFooter}
|
|
988
993
|
changesPanel={
|
|
989
994
|
<EditorGrid
|
|
990
995
|
tree={workbench.grid}
|
|
@@ -247,6 +247,40 @@ describe("the four-pane workbench", () => {
|
|
|
247
247
|
expect(diffToggleColumn(setup)).toBeGreaterThan(0);
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
+
test("selecting a non-diff thread while zoomed exits zoom and restores the Thread pane", async () => {
|
|
251
|
+
// a second, non-diff thread to navigate to; its sync has no Changes editor to fill a zoom
|
|
252
|
+
server.core.sessionCreate({
|
|
253
|
+
workspace: { repoRoot: repo, branch: "main" },
|
|
254
|
+
artifact: {
|
|
255
|
+
type: "plan",
|
|
256
|
+
content: "# Zoomed Plan\n\nReview this plan.\n",
|
|
257
|
+
meta: { title: "Zoomed Plan" },
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
const setup = await renderApp();
|
|
261
|
+
|
|
262
|
+
// open the collapsed Threads sidebar first (its toggle sits three cells left of the brand); the
|
|
263
|
+
// brand rides the Thread header, which zoom then hides, so it must be reached before zooming
|
|
264
|
+
const brand = locateText(setup, "cueloop");
|
|
265
|
+
await setup.mockMouse.click(brand.column - 3, brand.row);
|
|
266
|
+
await waitForText(setup, "Zoomed Plan");
|
|
267
|
+
|
|
268
|
+
// zoom the diff - the Thread pane hides and the footer rides the Changes pane
|
|
269
|
+
const zoom = locateText(setup, NERD.zoom);
|
|
270
|
+
await setup.mockMouse.click(zoom.column, zoom.row);
|
|
271
|
+
await waitForState(setup, () => !setup.captureCharFrame().includes("review the changes"));
|
|
272
|
+
|
|
273
|
+
// switch to the plan thread: it has no Changes editor, so a stranded zoom would blank the middle
|
|
274
|
+
const planRow = locateText(setup, "Zoomed Plan");
|
|
275
|
+
await setup.mockMouse.click(planRow.column, planRow.row);
|
|
276
|
+
await waitForText(setup, "Review this plan.");
|
|
277
|
+
|
|
278
|
+
const frame = setup.captureCharFrame();
|
|
279
|
+
// the Thread pane is back with the plan, and the diff's Changes editor is gone - never a blank middle
|
|
280
|
+
expect(frame).toContain("Review this plan.");
|
|
281
|
+
expect(frame).not.toContain("store.ts");
|
|
282
|
+
});
|
|
283
|
+
|
|
250
284
|
test("toggling the right sidebar while zoomed exits zoom and restores the Thread pane", async () => {
|
|
251
285
|
const setup = await renderApp();
|
|
252
286
|
|
|
@@ -37,6 +37,8 @@ export interface AppShellProps {
|
|
|
37
37
|
projectMode: ProjectPanelMode;
|
|
38
38
|
/** The Changes editor grid; rendered only when changesOpen. */
|
|
39
39
|
changesPanel?: React.ReactNode;
|
|
40
|
+
/** The thread footer, shown beneath the Changes grid while the Thread pane is zoomed away. */
|
|
41
|
+
changesFooter?: React.ReactNode;
|
|
40
42
|
projectPanel: React.ReactNode;
|
|
41
43
|
/** Hide the Thread pane so Changes fills the middle (zoom); the sidebars stay. */
|
|
42
44
|
zoomHideThread?: boolean;
|
|
@@ -90,6 +92,7 @@ export function AppShell({
|
|
|
90
92
|
onToggleRight,
|
|
91
93
|
projectMode,
|
|
92
94
|
changesPanel,
|
|
95
|
+
changesFooter,
|
|
93
96
|
projectPanel,
|
|
94
97
|
zoomHideThread,
|
|
95
98
|
footer,
|
|
@@ -227,7 +230,8 @@ export function AppShell({
|
|
|
227
230
|
borderColor: tokens.border,
|
|
228
231
|
}}
|
|
229
232
|
>
|
|
230
|
-
{changesPanel}
|
|
233
|
+
<box style={{ flexGrow: 1, minHeight: 0 }}>{changesPanel}</box>
|
|
234
|
+
{zoomHideThread ? changesFooter : null}
|
|
231
235
|
</box>
|
|
232
236
|
) : null}
|
|
233
237
|
{projectOpen ? (
|
|
@@ -80,6 +80,47 @@ describe("zoom icon in the shell", () => {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
test("the footer rides the Changes pane only while the Thread pane is zoomed away", async () => {
|
|
84
|
+
async function footerVisible(zoomed: boolean): Promise<boolean> {
|
|
85
|
+
const setup = await testRender(
|
|
86
|
+
<AppShell
|
|
87
|
+
sidebarOpen={false}
|
|
88
|
+
onToggleSidebar={() => {}}
|
|
89
|
+
onOpenMenu={() => {}}
|
|
90
|
+
threadsPanel={<text>threads</text>}
|
|
91
|
+
threadTitle="thread"
|
|
92
|
+
threadPanel={<text>body</text>}
|
|
93
|
+
changesOpen
|
|
94
|
+
projectOpen
|
|
95
|
+
onToggleChanges={() => {}}
|
|
96
|
+
onToggleProject={() => {}}
|
|
97
|
+
onToggleRight={() => {}}
|
|
98
|
+
projectMode="changes"
|
|
99
|
+
zoomHideThread={zoomed}
|
|
100
|
+
projectPanel={<text>project</text>}
|
|
101
|
+
changesFooter={<text>send message</text>}
|
|
102
|
+
changesPanel={<text>diff</text>}
|
|
103
|
+
/>,
|
|
104
|
+
{ width: 160, height: 8 },
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
allowEventLoopUpdates();
|
|
108
|
+
await setup.waitForVisualIdle();
|
|
109
|
+
const shown = setup.captureCharFrame().includes("send message");
|
|
110
|
+
|
|
111
|
+
setup.renderer.destroy();
|
|
112
|
+
|
|
113
|
+
return shown;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Act
|
|
117
|
+
const [zoomed, unzoomed] = await Promise.all([footerVisible(true), footerVisible(false)]);
|
|
118
|
+
|
|
119
|
+
// Assert - the Thread pane carries the footer normally, so it must not double up in Changes
|
|
120
|
+
expect(zoomed).toBe(true);
|
|
121
|
+
expect(unzoomed).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
|
|
83
124
|
test("the icon clears the Project border by its padding in both states", async () => {
|
|
84
125
|
// Act
|
|
85
126
|
const setupColumns = await Promise.all([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// The thread's bottom band: a header-like bar
|
|
2
|
-
// thread column. It carries the repo/branch
|
|
3
|
-
// clickable "Send message" control on the right.
|
|
1
|
+
// The thread's bottom band: a header-like bar under the thread column, or the
|
|
2
|
+
// Changes column when a zoom drops the thread column. It carries the repo/branch
|
|
3
|
+
// context on the left and a written, clickable "Send message" control on the right.
|
|
4
4
|
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { DARK, type Theme } from "../theme";
|
|
@@ -64,6 +64,8 @@ export function useChangesWorkbench(options?: ChangesWorkbenchOptions): ChangesW
|
|
|
64
64
|
setChangesOpen(isDiff);
|
|
65
65
|
setProjectMode(isDiff ? "changes" : "tree");
|
|
66
66
|
rememberedChanges.current = isDiff;
|
|
67
|
+
// a non-diff thread has no Changes editor; leaving zoom on would strand the hidden Thread pane
|
|
68
|
+
if (!isDiff) setZoomed(false);
|
|
67
69
|
setGrid(makeGroup([changesTab()]));
|
|
68
70
|
setFocusedGroup(null);
|
|
69
71
|
};
|