@cueloop/client 0.1.0-alpha.76 → 0.1.0-alpha.78
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.autoclose.test.tsx +3 -3
- package/src/App.diff.test.tsx +14 -2
- package/src/App.export.test.tsx +1 -2
- package/src/App.identity.test.tsx +78 -0
- package/src/App.plan-review.test.tsx +16 -0
- package/src/App.share-choice.test.tsx +105 -0
- package/src/App.submit-confirm.test.tsx +34 -5
- package/src/App.test.tsx +2 -2
- package/src/App.toast.test.tsx +3 -1
- package/src/App.tsx +180 -5
- package/src/App.walk.test.tsx +2 -2
- package/src/__snapshots__/view-plan.regression.test.ts.snap +1 -1
- package/src/ansi-screen.test.ts +28 -0
- package/src/ansi-screen.ts +72 -0
- package/src/app-screens.tsx +20 -3
- package/src/app-view-model.ts +4 -0
- package/src/components/AnnotatableFileView.tsx +10 -2
- package/src/components/AnnotationCards.tsx +40 -6
- package/src/components/AnsiScreen.stories.tsx +12 -0
- package/src/components/AnsiScreen.tsx +28 -0
- package/src/components/CompletionOverlay.stories.tsx +15 -1
- package/src/components/CompletionOverlay.tsx +22 -5
- package/src/components/ConfirmCard.stories.tsx +2 -0
- package/src/components/ConfirmCard.tsx +45 -18
- package/src/components/ConfirmDialog.tsx +11 -12
- package/src/components/DiffContentView.tsx +9 -5
- package/src/components/FileContentsView.tsx +1 -1
- package/src/components/GridTabContent.tsx +2 -0
- package/src/components/ManageAccessDialog.stories.tsx +36 -0
- package/src/components/ManageAccessDialog.test.tsx +94 -0
- package/src/components/ManageAccessDialog.tsx +122 -0
- package/src/components/PromptDialog.test.tsx +2 -2
- package/src/components/PromptDialog.tsx +9 -10
- package/src/components/ShareChoiceDialog.stories.tsx +34 -0
- package/src/components/ShareChoiceDialog.test.tsx +103 -0
- package/src/components/ShareChoiceDialog.tsx +80 -0
- package/src/components/SlashComposer.stories.tsx +37 -0
- package/src/components/SlashComposer.tsx +87 -0
- package/src/components/ThreadTree.tsx +11 -6
- package/src/components/ThreadView.selection.test.tsx +88 -1
- package/src/components/ThreadView.slash.test.tsx +0 -1
- package/src/components/ThreadView.tsx +71 -8
- package/src/components/Toast.tsx +0 -5
- package/src/components/WalkWizard.stories.tsx +2 -2
- package/src/components/WalkWizard.tsx +10 -12
- package/src/components/__snapshots__/stories.test.tsx.snap +277 -61
- package/src/components/primitives/Card.tsx +3 -0
- package/src/components/primitives/DialogActions.stories.tsx +20 -0
- package/src/components/primitives/DialogActions.tsx +39 -0
- package/src/components/session-tree.ts +7 -6
- package/src/components/stories-app.tsx +13 -4
- package/src/components/stories.test.tsx +8 -1
- package/src/components/story-tree.test.ts +32 -24
- package/src/components/story.ts +32 -15
- package/src/config-identity.test.ts +78 -0
- package/src/config.ts +44 -1
- package/src/diff-intraline.test.ts +75 -2
- package/src/diff-intraline.ts +95 -26
- package/src/github-identity.test.ts +58 -0
- package/src/github-identity.ts +41 -0
- package/src/intent-dispatch.test.ts +17 -2
- package/src/intent-dispatch.ts +7 -1
- package/src/keymap.test.ts +2 -2
- package/src/keymap.ts +1 -1
- package/src/pasted-image.test.ts +67 -0
- package/src/pasted-image.ts +60 -0
- package/src/run.ts +31 -19
- package/src/serve.ts +1 -1
- package/src/share.ts +11 -3
- package/src/slash-palette.test.ts +17 -0
- package/src/slash-palette.ts +11 -0
- package/src/thread-controller.curate.test.ts +1 -0
- package/src/thread-controller.derivation.test.ts +62 -0
- package/src/thread-controller.live-diff.test.ts +1 -0
- package/src/thread-controller.optimistic.test.ts +69 -0
- package/src/thread-controller.share.test.ts +36 -2
- package/src/thread-controller.switch-cache.test.ts +146 -0
- package/src/thread-controller.tree.test.ts +1 -0
- package/src/thread-controller.ts +171 -24
- package/src/use-annotation-surface.tsx +53 -29
- package/src/use-settings-dialog.tsx +24 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import React, { useContext, useEffect, useRef, useState } from "react";
|
|
16
16
|
import type { KeyEvent, MouseEvent as TerminalMouseEvent, TextRenderable } from "@opentui/core";
|
|
17
17
|
import { useKeyboard } from "@opentui/react";
|
|
18
|
-
import type { Thread } from "@cueloop/schema";
|
|
18
|
+
import type { Annotation, Thread } from "@cueloop/schema";
|
|
19
19
|
import type { Mark } from "./view-plan";
|
|
20
20
|
import type { QuickAction } from "./config";
|
|
21
21
|
import type { Theme } from "./theme";
|
|
@@ -40,6 +40,7 @@ import { printableSequence, type MarkRange, type VisualLine } from "./mark-runs"
|
|
|
40
40
|
import { matchesLeader } from "./thread-chords";
|
|
41
41
|
import {
|
|
42
42
|
activeSlashToken,
|
|
43
|
+
insertSlashItem,
|
|
43
44
|
isStandaloneSlashQuery,
|
|
44
45
|
mergeSlashItems,
|
|
45
46
|
slashFilter,
|
|
@@ -104,6 +105,8 @@ export interface AnnotationSurfaceOptions {
|
|
|
104
105
|
onAnnotate: (span: TextSpan, body: string) => void;
|
|
105
106
|
onReply: (rootAnnotationId: string, body: string) => void;
|
|
106
107
|
onUpdateAnnotation: (id: string, body: string) => void;
|
|
108
|
+
/** The author's display name for a comment's hover tooltip; the rail resolves it against the participant registry. */
|
|
109
|
+
resolveAuthorLabel?: (annotation: Annotation) => string | undefined;
|
|
107
110
|
leaderCombos?: readonly string[];
|
|
108
111
|
onLeaderCommand?: (key: KeyEvent) => void;
|
|
109
112
|
onExit: () => void;
|
|
@@ -179,6 +182,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
179
182
|
onAnnotate,
|
|
180
183
|
onReply,
|
|
181
184
|
onUpdateAnnotation,
|
|
185
|
+
resolveAuthorLabel,
|
|
182
186
|
leaderCombos,
|
|
183
187
|
onLeaderCommand,
|
|
184
188
|
onExit,
|
|
@@ -240,6 +244,11 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
240
244
|
};
|
|
241
245
|
const [folded, setFolded] = useState<Set<string>>(new Set());
|
|
242
246
|
const [composeText, setComposeText] = useState("");
|
|
247
|
+
const composeTextRef = useRef("");
|
|
248
|
+
const setDraft = (text: string): void => {
|
|
249
|
+
composeTextRef.current = text;
|
|
250
|
+
setComposeText(text);
|
|
251
|
+
};
|
|
243
252
|
const [caretOffset, setCaretOffset] = useState(0);
|
|
244
253
|
const [slashIndex, setSlashIndex] = useState(0);
|
|
245
254
|
const composerReady = useRef(false);
|
|
@@ -311,14 +320,14 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
311
320
|
composerReady.current = false;
|
|
312
321
|
composeRef.current = state;
|
|
313
322
|
setCompose(state);
|
|
314
|
-
|
|
323
|
+
setDraft(state.seed);
|
|
315
324
|
setCaretOffset(state.seed.length);
|
|
316
325
|
setSlashIndex(0);
|
|
317
326
|
};
|
|
318
327
|
const closeCompose = (): void => {
|
|
319
328
|
composeRef.current = null;
|
|
320
329
|
setCompose(null);
|
|
321
|
-
|
|
330
|
+
setDraft("");
|
|
322
331
|
setCaretOffset(0);
|
|
323
332
|
};
|
|
324
333
|
const skills = useContext(SlashSkillsContext);
|
|
@@ -448,14 +457,10 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
448
457
|
return true;
|
|
449
458
|
}
|
|
450
459
|
if (key.name === "return" || key.name === "tab") {
|
|
451
|
-
const
|
|
452
|
-
const cut = caretOffset - token.length;
|
|
453
|
-
const insertion = `/${slashItems[selected]!.name} `;
|
|
454
|
-
const seed = composeText.slice(0, cut) + insertion + composeText.slice(caretOffset);
|
|
460
|
+
const inserted = insertSlashItem(composeText, caretOffset, slashItems[selected]!.name);
|
|
455
461
|
|
|
456
|
-
openCompose({ ...activeCompose, seed });
|
|
457
|
-
|
|
458
|
-
setCaretOffset(cut + insertion.length);
|
|
462
|
+
openCompose({ ...activeCompose, seed: inserted.text });
|
|
463
|
+
setCaretOffset(inserted.caret);
|
|
459
464
|
|
|
460
465
|
return true;
|
|
461
466
|
}
|
|
@@ -470,7 +475,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
470
475
|
const grown = { ...activeCompose, seed: `${activeCompose.seed}\n` };
|
|
471
476
|
|
|
472
477
|
composeRef.current = grown;
|
|
473
|
-
|
|
478
|
+
setDraft(grown.seed);
|
|
474
479
|
setCaretOffset(grown.seed.length);
|
|
475
480
|
|
|
476
481
|
return setCompose(grown);
|
|
@@ -481,7 +486,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
481
486
|
const grown = { ...activeCompose, seed: activeCompose.seed + sequence };
|
|
482
487
|
|
|
483
488
|
composeRef.current = grown;
|
|
484
|
-
|
|
489
|
+
setDraft(grown.seed);
|
|
485
490
|
setCaretOffset(grown.seed.length);
|
|
486
491
|
setCompose(grown);
|
|
487
492
|
}
|
|
@@ -500,7 +505,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
500
505
|
// (an edit of an existing comment is never deleted this way)
|
|
501
506
|
if (
|
|
502
507
|
key.name === "backspace" &&
|
|
503
|
-
|
|
508
|
+
composeTextRef.current.length === 0 &&
|
|
504
509
|
activeCompose.editAnnotationId === null
|
|
505
510
|
) {
|
|
506
511
|
return closeCompose();
|
|
@@ -701,7 +706,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
701
706
|
onSave={saveComment}
|
|
702
707
|
onReady={() => (composerReady.current = true)}
|
|
703
708
|
onInput={(text, caret) => {
|
|
704
|
-
|
|
709
|
+
setDraft(text);
|
|
705
710
|
setCaretOffset(caret);
|
|
706
711
|
}}
|
|
707
712
|
/>
|
|
@@ -735,7 +740,12 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
735
740
|
node: editingHere ? (
|
|
736
741
|
composerNode
|
|
737
742
|
) : (
|
|
738
|
-
<CommentRow
|
|
743
|
+
<CommentRow
|
|
744
|
+
key={annotation.id}
|
|
745
|
+
annotation={annotation}
|
|
746
|
+
tokens={tokens}
|
|
747
|
+
authorLabel={resolveAuthorLabel?.(annotation)}
|
|
748
|
+
/>
|
|
739
749
|
),
|
|
740
750
|
};
|
|
741
751
|
});
|
|
@@ -791,9 +801,36 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
791
801
|
const endsInLine = (end: number): boolean => end - 1 >= line.start && end - 1 < line.end;
|
|
792
802
|
const nodes: React.ReactNode[] = [];
|
|
793
803
|
const composeHere = compose && compose.blockIndex === blockIndex;
|
|
804
|
+
const newComposeHere = Boolean(composeHere && compose.discussionKey === null && composerNode);
|
|
805
|
+
const composeAnchoredHere =
|
|
806
|
+
newComposeHere && (compose!.span ? endsInLine(compose!.span.end.char) : isLastLine);
|
|
807
|
+
const composeStart = compose?.span?.start;
|
|
808
|
+
|
|
809
|
+
const pushComposeCard = (): void => {
|
|
810
|
+
nodes.push(
|
|
811
|
+
<DiscussionCard
|
|
812
|
+
key="compose-new"
|
|
813
|
+
tokens={tokens}
|
|
814
|
+
segments={[{ color: palette.cardEdge, node: composerNode }]}
|
|
815
|
+
/>,
|
|
816
|
+
);
|
|
817
|
+
nodes.push(paletteNode);
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
// the draft sorts in by its span start, the same order discussionsFrom lands it on save, so a
|
|
821
|
+
// new comment sits in its final position while typing instead of appending to the stack
|
|
822
|
+
let composePending = composeAnchoredHere;
|
|
794
823
|
|
|
795
824
|
for (const discussion of discussions) {
|
|
796
825
|
if (discussion.blockIndex !== blockIndex || !endsInLine(discussion.span.end.char)) continue;
|
|
826
|
+
if (
|
|
827
|
+
composePending &&
|
|
828
|
+
composeStart &&
|
|
829
|
+
comparePositions(composeStart, discussion.span.start) < 0
|
|
830
|
+
) {
|
|
831
|
+
pushComposeCard();
|
|
832
|
+
composePending = false;
|
|
833
|
+
}
|
|
797
834
|
const composingHere = Boolean(composeHere && compose.discussionKey === discussion.key);
|
|
798
835
|
|
|
799
836
|
if (folded.has(discussion.key) && !composingHere) {
|
|
@@ -803,20 +840,7 @@ export function useAnnotationSurface(options: AnnotationSurfaceOptions): Annotat
|
|
|
803
840
|
nodes.push(discussionCardFor(discussion, composingHere));
|
|
804
841
|
if (composingHere) nodes.push(paletteNode);
|
|
805
842
|
}
|
|
806
|
-
if (
|
|
807
|
-
const anchoredHere = compose.span ? endsInLine(compose.span.end.char) : isLastLine;
|
|
808
|
-
|
|
809
|
-
if (anchoredHere) {
|
|
810
|
-
nodes.push(
|
|
811
|
-
<DiscussionCard
|
|
812
|
-
key="compose-new"
|
|
813
|
-
tokens={tokens}
|
|
814
|
-
segments={[{ color: palette.cardEdge, node: composerNode }]}
|
|
815
|
-
/>,
|
|
816
|
-
);
|
|
817
|
-
nodes.push(paletteNode);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
843
|
+
if (composePending) pushComposeCard();
|
|
820
844
|
|
|
821
845
|
return nodes;
|
|
822
846
|
};
|
|
@@ -83,6 +83,10 @@ export function useSettingsDialog(params: {
|
|
|
83
83
|
quickActions: QuickAction[];
|
|
84
84
|
setQuickActions: Dispatch<SetStateAction<QuickAction[]>>;
|
|
85
85
|
setMenuDialog: Dispatch<SetStateAction<"keybinds" | "settings" | null>>;
|
|
86
|
+
identityName?: string;
|
|
87
|
+
identityProvider: "typed" | "github";
|
|
88
|
+
onSyncGithubIdentity: () => void;
|
|
89
|
+
onRenameDisplayName: () => void;
|
|
86
90
|
}): SettingsDialogModel {
|
|
87
91
|
const {
|
|
88
92
|
theme,
|
|
@@ -98,6 +102,10 @@ export function useSettingsDialog(params: {
|
|
|
98
102
|
quickActions,
|
|
99
103
|
setQuickActions,
|
|
100
104
|
setMenuDialog,
|
|
105
|
+
identityName,
|
|
106
|
+
identityProvider,
|
|
107
|
+
onSyncGithubIdentity,
|
|
108
|
+
onRenameDisplayName,
|
|
101
109
|
} = params;
|
|
102
110
|
|
|
103
111
|
const [settingsNav, setSettingsNav] = useState<SettingsNav>({
|
|
@@ -157,6 +165,15 @@ export function useSettingsDialog(params: {
|
|
|
157
165
|
},
|
|
158
166
|
],
|
|
159
167
|
},
|
|
168
|
+
{
|
|
169
|
+
id: "account",
|
|
170
|
+
name: "Account",
|
|
171
|
+
rows: [
|
|
172
|
+
{ key: "displayName", label: "Display name", kind: "text" },
|
|
173
|
+
{ key: "identitySource", label: "Source", kind: "text" },
|
|
174
|
+
{ key: "syncGithub", label: "Sync from GitHub", kind: "text" },
|
|
175
|
+
],
|
|
176
|
+
},
|
|
160
177
|
{
|
|
161
178
|
id: "appearance",
|
|
162
179
|
name: "Appearance",
|
|
@@ -202,6 +219,9 @@ export function useSettingsDialog(params: {
|
|
|
202
219
|
autoClose: autoClose === "off" ? "off" : `${autoClose}s`,
|
|
203
220
|
diffView: diffView === "split" ? "Split" : "Stacked",
|
|
204
221
|
theme: THEME_LABELS[themeName],
|
|
222
|
+
displayName: identityName ?? "-- not set --",
|
|
223
|
+
identitySource: identityProvider === "github" ? "GitHub" : "typed",
|
|
224
|
+
syncGithub: "enter to sync",
|
|
205
225
|
};
|
|
206
226
|
const cycleSetting = (rowKey: string): void => {
|
|
207
227
|
if (rowKey === "autoClose") {
|
|
@@ -220,6 +240,10 @@ export function useSettingsDialog(params: {
|
|
|
220
240
|
setThemeName(next);
|
|
221
241
|
setTheme(composeTheme(next, themeOverrides, appearance));
|
|
222
242
|
persistTheme(next);
|
|
243
|
+
} else if (rowKey === "syncGithub") {
|
|
244
|
+
onSyncGithubIdentity();
|
|
245
|
+
} else if (rowKey === "displayName") {
|
|
246
|
+
onRenameDisplayName();
|
|
223
247
|
}
|
|
224
248
|
};
|
|
225
249
|
|