@cueloop/client 0.1.0-alpha.70 → 0.1.0-alpha.72
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 +5 -5
- package/src/App.tsx +245 -230
- package/src/App.workbench.test.tsx +34 -0
- package/src/components/AnnotationCards.stories.tsx +0 -1
- package/src/components/AnnotationCards.tsx +34 -30
- package/src/components/AppShell.tsx +5 -1
- package/src/components/AppShell.zoom.test.tsx +41 -0
- package/src/components/ThreadFooter.tsx +3 -3
- package/src/components/ThreadView.slash.test.tsx +86 -98
- package/src/components/ThreadView.tsx +0 -1
- package/src/components/syntax-highlight.ts +23 -0
- package/src/mark-runs.ts +5 -4
- package/src/skills.ts +7 -0
- package/src/slash-palette.test.ts +37 -5
- package/src/slash-palette.ts +33 -19
- package/src/use-annotation-surface.tsx +34 -25
- package/src/use-changes-workbench.ts +2 -0
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.72",
|
|
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.72",
|
|
31
|
+
"@cueloop/extension-api": "0.1.0-alpha.72",
|
|
32
|
+
"@cueloop/integration-obsidian": "0.1.0-alpha.72",
|
|
33
|
+
"@cueloop/schema": "0.1.0-alpha.72",
|
|
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
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
type DiffViewMode,
|
|
22
22
|
type QuickAction,
|
|
23
23
|
} from "./config";
|
|
24
|
-
import { loadSkills, SlashSkillsContext } from "./skills";
|
|
25
|
-
import type
|
|
24
|
+
import { loadSkills, PaletteNamesContext, SlashSkillsContext } from "./skills";
|
|
25
|
+
import { mergeSlashItems, slashItemsFrom, type SlashItem } from "./slash-palette";
|
|
26
26
|
import {
|
|
27
27
|
composeTheme,
|
|
28
28
|
DEFAULT_THEME_NAME,
|
|
@@ -490,6 +490,10 @@ export function App({
|
|
|
490
490
|
const [authorNames, setAuthorNames] = useState<Record<string, string>>({});
|
|
491
491
|
const [quickActions, setQuickActions] = useState<QuickAction[]>(DEFAULT_QUICK_ACTIONS);
|
|
492
492
|
const [skills, setSkills] = useState<SlashItem[]>([]);
|
|
493
|
+
const paletteNames = useMemo(
|
|
494
|
+
() => new Set(mergeSlashItems(slashItemsFrom(quickActions), skills).map((item) => item.name)),
|
|
495
|
+
[quickActions, skills],
|
|
496
|
+
);
|
|
493
497
|
// opt-in: render a prototype as a kitty pixel mockup instead of the markdown doc
|
|
494
498
|
const [prototypePixels, setPrototypePixels] = useState(false);
|
|
495
499
|
|
|
@@ -792,23 +796,25 @@ export function App({
|
|
|
792
796
|
if (!session)
|
|
793
797
|
return inbox ? (
|
|
794
798
|
<SlashSkillsContext.Provider value={skills}>
|
|
795
|
-
<
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
799
|
+
<PaletteNamesContext.Provider value={paletteNames}>
|
|
800
|
+
<NoThreadShell
|
|
801
|
+
rows={grouped.rows}
|
|
802
|
+
inboxCursor={inboxCursor}
|
|
803
|
+
mode={mode}
|
|
804
|
+
theme={theme}
|
|
805
|
+
controller={controller}
|
|
806
|
+
setMode={setMode}
|
|
807
|
+
menuChrome={menuChrome}
|
|
808
|
+
onOpenMenu={() => setMenuDialog("settings")}
|
|
809
|
+
sidebarOpen={sidebarOpen}
|
|
810
|
+
onToggleSidebar={() => setSidebarOpen((open) => !open)}
|
|
811
|
+
pinnedIds={pinnedIds}
|
|
812
|
+
onPin={togglePin}
|
|
813
|
+
onRename={(id, title) => setMode({ type: "renameThread", sessionId: id, text: title })}
|
|
814
|
+
quickActions={quickActions}
|
|
815
|
+
onWelcomeComposingChange={setWelcomeComposing}
|
|
816
|
+
/>
|
|
817
|
+
</PaletteNamesContext.Provider>
|
|
812
818
|
</SlashSkillsContext.Provider>
|
|
813
819
|
) : (
|
|
814
820
|
<ConnectingScreen theme={theme} />
|
|
@@ -878,228 +884,237 @@ export function App({
|
|
|
878
884
|
dispatch({ type: "openSubmit" });
|
|
879
885
|
};
|
|
880
886
|
|
|
887
|
+
const threadFooter = (
|
|
888
|
+
<ThreadFooter
|
|
889
|
+
repo={projectName(activeSession.workspace)}
|
|
890
|
+
branch={activeSession.workspace.branch}
|
|
891
|
+
onSubmit={onSubmitRequest}
|
|
892
|
+
canSubmit={canSubmitReview(isOwner, resolved, observer)}
|
|
893
|
+
theme={theme}
|
|
894
|
+
/>
|
|
895
|
+
);
|
|
896
|
+
|
|
881
897
|
return (
|
|
882
898
|
<SlashSkillsContext.Provider value={skills}>
|
|
883
|
-
<
|
|
884
|
-
<
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
<
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
<
|
|
910
|
-
{
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
{
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
<box style={{ flexGrow: 1, flexDirection: "
|
|
921
|
-
{
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
<
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
899
|
+
<PaletteNamesContext.Provider value={paletteNames}>
|
|
900
|
+
<ThemeProvider theme={theme}>
|
|
901
|
+
<AppShell
|
|
902
|
+
sidebarOpen={sidebarOpen}
|
|
903
|
+
onToggleSidebar={() => setSidebarOpen((open) => !open)}
|
|
904
|
+
onOpenMenu={() => setMenuDialog("settings")}
|
|
905
|
+
threadsPanel={
|
|
906
|
+
<scrollbox style={{ flexGrow: 1 }} focused={false}>
|
|
907
|
+
<ThreadTree
|
|
908
|
+
rows={grouped.rows}
|
|
909
|
+
cursor={inboxCursor}
|
|
910
|
+
activeId={activeSession.id}
|
|
911
|
+
pinnedIds={pinnedIds}
|
|
912
|
+
width={30}
|
|
913
|
+
onSelect={(id) => controller.open(id)}
|
|
914
|
+
onPin={togglePin}
|
|
915
|
+
onRename={(id, title) =>
|
|
916
|
+
setMode({ type: "renameThread", sessionId: id, text: title })
|
|
917
|
+
}
|
|
918
|
+
theme={theme}
|
|
919
|
+
/>
|
|
920
|
+
</scrollbox>
|
|
921
|
+
}
|
|
922
|
+
threadTitle={threadTitle(activeSession)}
|
|
923
|
+
threadActions={
|
|
924
|
+
showOwnerActions ? (
|
|
925
|
+
<Toolbar>
|
|
926
|
+
<Button onPress={onEditRequest} theme={theme}>
|
|
927
|
+
{" edit "}
|
|
928
|
+
</Button>
|
|
929
|
+
<Button onPress={onShareRequest} theme={theme}>
|
|
930
|
+
{" share "}
|
|
931
|
+
</Button>
|
|
932
|
+
</Toolbar>
|
|
933
|
+
) : undefined
|
|
934
|
+
}
|
|
935
|
+
threadPanel={
|
|
936
|
+
<box style={{ flexGrow: 1, flexDirection: "column" }}>
|
|
937
|
+
<box style={{ flexGrow: 1, flexDirection: "row" }}>
|
|
938
|
+
{isPixelPrototype ? (
|
|
939
|
+
<PrototypePixels
|
|
940
|
+
prototypePath={prototypePath}
|
|
941
|
+
canComment={prototypeCanComment}
|
|
942
|
+
onCommentElement={onCommentPrototype}
|
|
943
|
+
onComposingChange={setPrototypeComposing}
|
|
944
|
+
hidden={chromeHidden}
|
|
945
|
+
/>
|
|
946
|
+
) : isDiff ? (
|
|
947
|
+
<box style={{ flexGrow: 1, paddingLeft: 2, paddingTop: 1 }}>
|
|
948
|
+
<text fg={theme.textDim}>review the changes on the right</text>
|
|
949
|
+
</box>
|
|
950
|
+
) : (
|
|
951
|
+
<ThreadView
|
|
952
|
+
session={activeSession}
|
|
953
|
+
suspended={threadViewSuspended}
|
|
954
|
+
editOrphanCount={editOrphanCount}
|
|
955
|
+
onComposingChange={setThreadComposing}
|
|
956
|
+
resolved={resolved}
|
|
957
|
+
onObserverBlocked={(reason) =>
|
|
958
|
+
controller.setStatus(
|
|
959
|
+
reason === "observer"
|
|
960
|
+
? "observer - read-only"
|
|
961
|
+
: "review submitted - read-only",
|
|
962
|
+
)
|
|
963
|
+
}
|
|
964
|
+
onCursorChange={setCursor}
|
|
965
|
+
focusedAnnotationId={focusedAnnotationId}
|
|
966
|
+
onFocusAnnotation={setFocusedAnnotationId}
|
|
967
|
+
display={display}
|
|
968
|
+
marks={marks}
|
|
969
|
+
quickActions={quickActions}
|
|
970
|
+
observer={observer}
|
|
971
|
+
onAnnotate={(span, body) =>
|
|
972
|
+
void controller.annotate(
|
|
973
|
+
"comment",
|
|
974
|
+
span.start.blockIndex,
|
|
975
|
+
span.start.char,
|
|
976
|
+
span.end.char,
|
|
977
|
+
body,
|
|
978
|
+
span.end.blockIndex,
|
|
979
|
+
)
|
|
980
|
+
}
|
|
981
|
+
onReply={(rootAnnotationId, body) =>
|
|
982
|
+
void controller.reply(rootAnnotationId, body)
|
|
983
|
+
}
|
|
984
|
+
onUpdateAnnotation={(id, body) => controller.updateAnnotation(id, body)}
|
|
985
|
+
onExit={() => onExit?.(0)}
|
|
986
|
+
/>
|
|
987
|
+
)}
|
|
988
|
+
</box>
|
|
989
|
+
{threadFooter}
|
|
990
|
+
</box>
|
|
991
|
+
}
|
|
992
|
+
changesOpen={workbench.changesOpen}
|
|
993
|
+
projectOpen={workbench.projectOpen}
|
|
994
|
+
onToggleChanges={workbench.toggleChanges}
|
|
995
|
+
onToggleProject={workbench.toggleProject}
|
|
996
|
+
onToggleRight={workbench.toggleRight}
|
|
997
|
+
projectMode={workbench.projectMode}
|
|
998
|
+
zoomHideThread={workbench.zoomed}
|
|
999
|
+
changesFooter={threadFooter}
|
|
1000
|
+
changesPanel={
|
|
1001
|
+
<EditorGrid
|
|
1002
|
+
tree={workbench.grid}
|
|
1003
|
+
focusedGroupId={workbench.activeGroup}
|
|
1004
|
+
commentCounts={diffCommentCounts}
|
|
1005
|
+
onFocusGroup={workbench.focusGroup}
|
|
1006
|
+
onActivateTab={workbench.activate}
|
|
1007
|
+
onCloseTab={workbench.close}
|
|
1008
|
+
onSplit={workbench.split}
|
|
1009
|
+
onZoom={workbench.toggleZoom}
|
|
1010
|
+
zoomed={workbench.zoomed}
|
|
1011
|
+
renderTab={(tab, groupFocused) => (
|
|
1012
|
+
<GridTabContent
|
|
1013
|
+
tab={tab}
|
|
1014
|
+
rows={rows}
|
|
1015
|
+
surface={{
|
|
1016
|
+
session: activeSession,
|
|
1017
|
+
quickActions,
|
|
1018
|
+
observer,
|
|
1019
|
+
commentsEnabled: true,
|
|
1020
|
+
resolved,
|
|
1021
|
+
suspended: threadViewSuspended || !groupFocused,
|
|
1022
|
+
onComposingChange: setThreadComposing,
|
|
1023
|
+
onObserverBlocked: (reason) =>
|
|
1024
|
+
controller.setStatus(
|
|
1025
|
+
reason === "observer"
|
|
1026
|
+
? "observer - read-only"
|
|
1027
|
+
: "review submitted - read-only",
|
|
1028
|
+
),
|
|
1029
|
+
onCursorChange: setCursor,
|
|
1030
|
+
focusedAnnotationId,
|
|
1031
|
+
onFocusAnnotation: setFocusedAnnotationId,
|
|
1032
|
+
// a diff thread's Changes view is the artifact itself; any other thread's is the
|
|
1033
|
+
// live working-tree diff, so its notes carry a file target and anchor there
|
|
1034
|
+
onAnnotate: (span, body) =>
|
|
1035
|
+
void controller.annotate(
|
|
1036
|
+
"comment",
|
|
1037
|
+
span.start.blockIndex,
|
|
1038
|
+
span.start.char,
|
|
1039
|
+
span.end.char,
|
|
1040
|
+
body,
|
|
1041
|
+
span.end.blockIndex,
|
|
1042
|
+
isDiff
|
|
1043
|
+
? { kind: "artifact" }
|
|
1044
|
+
: { kind: "file", path: "", rev: "worktree" },
|
|
1045
|
+
),
|
|
1046
|
+
onReply: (rootAnnotationId, body) =>
|
|
1047
|
+
void controller.reply(rootAnnotationId, body),
|
|
1048
|
+
onUpdateAnnotation: (id, body) => controller.updateAnnotation(id, body),
|
|
1049
|
+
onExit: () => onExit?.(0),
|
|
1050
|
+
}}
|
|
1051
|
+
rejectedRows={rejectedRows}
|
|
1052
|
+
fold={diffFold}
|
|
1053
|
+
fileStats={controller.fileStats()}
|
|
1054
|
+
split={diffView === "split" && workbench.zoomed}
|
|
1055
|
+
dimmed={walking}
|
|
1056
|
+
readFile={(path) => controller.repoReadFile(path)}
|
|
1057
|
+
onAddFileComment={(path, anchor, body) =>
|
|
1058
|
+
void controller.addComment(
|
|
1059
|
+
anchor,
|
|
1060
|
+
{ kind: "file", path, rev: "worktree" },
|
|
960
1061
|
body,
|
|
961
|
-
span.end.blockIndex,
|
|
962
1062
|
)
|
|
963
1063
|
}
|
|
964
|
-
|
|
965
|
-
void controller.reply(rootAnnotationId, body)
|
|
966
|
-
}
|
|
967
|
-
onUpdateAnnotation={(id, body) => controller.updateAnnotation(id, body)}
|
|
968
|
-
onExit={() => onExit?.(0)}
|
|
1064
|
+
theme={theme}
|
|
969
1065
|
/>
|
|
970
1066
|
)}
|
|
971
|
-
</box>
|
|
972
|
-
<ThreadFooter
|
|
973
|
-
repo={projectName(activeSession.workspace)}
|
|
974
|
-
branch={activeSession.workspace.branch}
|
|
975
|
-
onSubmit={onSubmitRequest}
|
|
976
|
-
canSubmit={canSubmitReview(isOwner, resolved, observer)}
|
|
977
1067
|
theme={theme}
|
|
978
1068
|
/>
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
surface={{
|
|
1004
|
-
session: activeSession,
|
|
1005
|
-
quickActions,
|
|
1006
|
-
observer,
|
|
1007
|
-
commentsEnabled: true,
|
|
1008
|
-
resolved,
|
|
1009
|
-
suspended: threadViewSuspended || !groupFocused,
|
|
1010
|
-
onComposingChange: setThreadComposing,
|
|
1011
|
-
onObserverBlocked: (reason) =>
|
|
1012
|
-
controller.setStatus(
|
|
1013
|
-
reason === "observer"
|
|
1014
|
-
? "observer - read-only"
|
|
1015
|
-
: "review submitted - read-only",
|
|
1016
|
-
),
|
|
1017
|
-
onCursorChange: setCursor,
|
|
1018
|
-
focusedAnnotationId,
|
|
1019
|
-
onFocusAnnotation: setFocusedAnnotationId,
|
|
1020
|
-
// a diff thread's Changes view is the artifact itself; any other thread's is the
|
|
1021
|
-
// live working-tree diff, so its notes carry a file target and anchor there
|
|
1022
|
-
onAnnotate: (span, body) =>
|
|
1023
|
-
void controller.annotate(
|
|
1024
|
-
"comment",
|
|
1025
|
-
span.start.blockIndex,
|
|
1026
|
-
span.start.char,
|
|
1027
|
-
span.end.char,
|
|
1028
|
-
body,
|
|
1029
|
-
span.end.blockIndex,
|
|
1030
|
-
isDiff ? { kind: "artifact" } : { kind: "file", path: "", rev: "worktree" },
|
|
1031
|
-
),
|
|
1032
|
-
onReply: (rootAnnotationId, body) =>
|
|
1033
|
-
void controller.reply(rootAnnotationId, body),
|
|
1034
|
-
onUpdateAnnotation: (id, body) => controller.updateAnnotation(id, body),
|
|
1035
|
-
onExit: () => onExit?.(0),
|
|
1036
|
-
}}
|
|
1037
|
-
rejectedRows={rejectedRows}
|
|
1038
|
-
fold={diffFold}
|
|
1039
|
-
fileStats={controller.fileStats()}
|
|
1040
|
-
split={diffView === "split" && workbench.zoomed}
|
|
1041
|
-
dimmed={walking}
|
|
1042
|
-
readFile={(path) => controller.repoReadFile(path)}
|
|
1043
|
-
onAddFileComment={(path, anchor, body) =>
|
|
1044
|
-
void controller.addComment(
|
|
1045
|
-
anchor,
|
|
1046
|
-
{ kind: "file", path, rev: "worktree" },
|
|
1047
|
-
body,
|
|
1048
|
-
)
|
|
1049
|
-
}
|
|
1050
|
-
theme={theme}
|
|
1051
|
-
/>
|
|
1052
|
-
)}
|
|
1053
|
-
theme={theme}
|
|
1054
|
-
/>
|
|
1055
|
-
}
|
|
1056
|
-
projectPanel={
|
|
1057
|
-
<ProjectPanelBody
|
|
1058
|
-
mode={workbench.projectMode}
|
|
1059
|
-
loadChanges={() => controller.repoChanges()}
|
|
1060
|
-
loadProjectFiles={() => controller.repoFiles()}
|
|
1061
|
-
reloadKey={activeSession.id}
|
|
1062
|
-
// the Changes navigator always opens a changed file as a diff - a diff review shows its
|
|
1063
|
-
// captured snapshot, every other thread the live working-tree diff
|
|
1064
|
-
onOpenChangedFile={(path) => workbench.openFile(path, "diff")}
|
|
1065
|
-
onOpenProjectFile={(path) => workbench.openFile(path, "contents")}
|
|
1066
|
-
commentCounts={diffCommentCounts}
|
|
1069
|
+
}
|
|
1070
|
+
projectPanel={
|
|
1071
|
+
<ProjectPanelBody
|
|
1072
|
+
mode={workbench.projectMode}
|
|
1073
|
+
loadChanges={() => controller.repoChanges()}
|
|
1074
|
+
loadProjectFiles={() => controller.repoFiles()}
|
|
1075
|
+
reloadKey={activeSession.id}
|
|
1076
|
+
// the Changes navigator always opens a changed file as a diff - a diff review shows its
|
|
1077
|
+
// captured snapshot, every other thread the live working-tree diff
|
|
1078
|
+
onOpenChangedFile={(path) => workbench.openFile(path, "diff")}
|
|
1079
|
+
onOpenProjectFile={(path) => workbench.openFile(path, "contents")}
|
|
1080
|
+
commentCounts={diffCommentCounts}
|
|
1081
|
+
theme={theme}
|
|
1082
|
+
/>
|
|
1083
|
+
}
|
|
1084
|
+
theme={theme}
|
|
1085
|
+
>
|
|
1086
|
+
<TrailingOverlays
|
|
1087
|
+
walking={walking}
|
|
1088
|
+
walk={walk}
|
|
1089
|
+
walkFileList={walkFileList}
|
|
1090
|
+
viewedPaths={viewedPaths}
|
|
1091
|
+
session={activeSession}
|
|
1092
|
+
terminalWidth={terminalWidth}
|
|
1067
1093
|
theme={theme}
|
|
1094
|
+
mode={mode}
|
|
1095
|
+
toast={toast}
|
|
1096
|
+
setMode={setMode}
|
|
1097
|
+
dispatch={dispatch}
|
|
1068
1098
|
/>
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
position: "absolute",
|
|
1089
|
-
left: 0,
|
|
1090
|
-
top: 0,
|
|
1091
|
-
width: "100%",
|
|
1092
|
-
height: "100%",
|
|
1093
|
-
justifyContent: "center",
|
|
1094
|
-
alignItems: "center",
|
|
1095
|
-
}}
|
|
1096
|
-
>
|
|
1097
|
-
<ConfirmCard {...submitConfirmState} theme={theme} />
|
|
1098
|
-
</box>
|
|
1099
|
-
) : null}
|
|
1100
|
-
{menuChrome}
|
|
1101
|
-
</AppShell>
|
|
1102
|
-
</ThemeProvider>
|
|
1099
|
+
{submitConfirmState !== null ? (
|
|
1100
|
+
<box
|
|
1101
|
+
style={{
|
|
1102
|
+
position: "absolute",
|
|
1103
|
+
left: 0,
|
|
1104
|
+
top: 0,
|
|
1105
|
+
width: "100%",
|
|
1106
|
+
height: "100%",
|
|
1107
|
+
justifyContent: "center",
|
|
1108
|
+
alignItems: "center",
|
|
1109
|
+
}}
|
|
1110
|
+
>
|
|
1111
|
+
<ConfirmCard {...submitConfirmState} theme={theme} />
|
|
1112
|
+
</box>
|
|
1113
|
+
) : null}
|
|
1114
|
+
{menuChrome}
|
|
1115
|
+
</AppShell>
|
|
1116
|
+
</ThemeProvider>
|
|
1117
|
+
</PaletteNamesContext.Provider>
|
|
1103
1118
|
</SlashSkillsContext.Provider>
|
|
1104
1119
|
);
|
|
1105
1120
|
}
|
|
@@ -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
|
|