@kitlangton/ghui 0.2.1 → 0.3.0
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/README.md +1 -4
- package/package.json +1 -1
- package/src/App.tsx +189 -14
- package/src/appCommands.ts +28 -3
- package/src/config.ts +0 -8
- package/src/domain.ts +13 -3
- package/src/keymap/all.ts +23 -10
- package/src/keymap/changedFilesModal.ts +23 -0
- package/src/keymap/commandPalette.ts +2 -2
- package/src/keymap/commentThreadModal.ts +1 -1
- package/src/keymap/diffView.ts +4 -2
- package/src/keymap/labelModal.ts +2 -2
- package/src/keymap/submitReviewModal.ts +48 -0
- package/src/keymap/themeModal.ts +2 -2
- package/src/pullRequestViews.ts +1 -3
- package/src/services/GitHubService.ts +20 -5
- package/src/services/MockGitHubService.ts +1 -0
- package/src/ui/CommandPalette.tsx +11 -51
- package/src/ui/PullRequestDiffPane.tsx +3 -2
- package/src/ui/PullRequestList.tsx +1 -17
- package/src/ui/colors.ts +7 -0
- package/src/ui/modals.tsx +366 -16
- package/src/ui/primitives.tsx +146 -1
package/README.md
CHANGED
|
@@ -44,15 +44,12 @@ bun run dev
|
|
|
44
44
|
|
|
45
45
|
## Configuration
|
|
46
46
|
|
|
47
|
-
- `GHUI_AUTHOR`: author passed to `gh search prs`, defaults to `@me`
|
|
48
|
-
- `GHUI_REPO`: optional `owner/name` repository queue for browsing all open PRs in a repo
|
|
49
47
|
- `GHUI_PR_FETCH_LIMIT`: max PRs fetched, defaults to `200`
|
|
50
48
|
|
|
51
49
|
Example:
|
|
52
50
|
|
|
53
51
|
```bash
|
|
54
|
-
|
|
55
|
-
GHUI_REPO=basecamp/omarchy ghui
|
|
52
|
+
GHUI_PR_FETCH_LIMIT=100 ghui
|
|
56
53
|
```
|
|
57
54
|
|
|
58
55
|
You can also copy `.env.example` to `.env` and edit the values locally.
|
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -13,7 +13,7 @@ import { buildAppCommands } from "./appCommands.js"
|
|
|
13
13
|
import type { AppCommand } from "./commands.js"
|
|
14
14
|
import { clampCommandIndex, commandEnabled, defineCommand, filterCommands, sortCommandsByScope } from "./commands.js"
|
|
15
15
|
import { config } from "./config.js"
|
|
16
|
-
import { type CreatePullRequestCommentInput, type DiffCommentSide, type ListPullRequestPageInput, type LoadStatus, type PullRequestConversationItem, type PullRequestItem, type PullRequestLabel, type PullRequestMergeAction, type PullRequestReviewComment } from "./domain.js"
|
|
16
|
+
import { type CreatePullRequestCommentInput, type DiffCommentSide, type ListPullRequestPageInput, type LoadStatus, type PullRequestConversationItem, type PullRequestItem, type PullRequestLabel, type PullRequestMergeAction, type PullRequestReviewComment, type SubmitPullRequestReviewInput } from "./domain.js"
|
|
17
17
|
import { formatShortDate, formatTimestamp } from "./date.js"
|
|
18
18
|
import { errorMessage } from "./errors.js"
|
|
19
19
|
import { availableMergeActions, mergeInfoFromPullRequest } from "./mergeActions.js"
|
|
@@ -33,7 +33,7 @@ import { FooterHints, initialRetryProgress, RetryProgress } from "./ui/FooterHin
|
|
|
33
33
|
import { LoadingLogoPane } from "./ui/LoadingLogo.js"
|
|
34
34
|
import { Divider, fitCell, PlainLine, SeparatorColumn } from "./ui/primitives.js"
|
|
35
35
|
import { CommandPalette } from "./ui/CommandPalette.js"
|
|
36
|
-
import { CloseModal, CommentModal, CommentThreadModal, filterLabels, initialCloseModalState, initialCommandPaletteState, initialCommentModalState, initialCommentThreadModalState, initialLabelModalState, initialMergeModalState, initialModal, initialOpenRepositoryModalState, initialThemeModalState, LabelModal, MergeModal, Modal, OpenRepositoryModal, ThemeModal, type CloseModalState, type CommandPaletteState, type CommentModalState, type CommentThreadModalState, type LabelModalState, type MergeModalState, type ModalState, type ModalTag, type OpenRepositoryModalState, type ThemeModalState } from "./ui/modals.js"
|
|
36
|
+
import { ChangedFilesModal, CloseModal, CommentModal, CommentThreadModal, filterChangedFiles, filterLabels, initialChangedFilesModalState, initialCloseModalState, initialCommandPaletteState, initialCommentModalState, initialCommentThreadModalState, initialLabelModalState, initialMergeModalState, initialModal, initialOpenRepositoryModalState, initialSubmitReviewModalState, initialThemeModalState, LabelModal, MergeModal, Modal, OpenRepositoryModal, submitReviewOptions, SubmitReviewModal, ThemeModal, type ChangedFilesModalState, type CloseModalState, type CommandPaletteState, type CommentModalState, type CommentThreadModalState, type LabelModalState, type MergeModalState, type ModalState, type ModalTag, type OpenRepositoryModalState, type SubmitReviewModalState, type ThemeModalState } from "./ui/modals.js"
|
|
37
37
|
import { groupBy, reviewLabel } from "./ui/pullRequests.js"
|
|
38
38
|
import { PullRequestDiffPane } from "./ui/PullRequestDiffPane.js"
|
|
39
39
|
import { buildPullRequestListRows, pullRequestListRowIndex, PullRequestList } from "./ui/PullRequestList.js"
|
|
@@ -132,7 +132,7 @@ const appendPullRequestPage = (existing: readonly PullRequestItem[], incoming: r
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
const retryProgressAtom = Atom.make<RetryProgress>(initialRetryProgress).pipe(Atom.keepAlive)
|
|
135
|
-
const activeViewAtom = Atom.make<PullRequestView>(initialPullRequestView(
|
|
135
|
+
const activeViewAtom = Atom.make<PullRequestView>(initialPullRequestView()).pipe(Atom.keepAlive)
|
|
136
136
|
const queueLoadCacheAtom = Atom.make<Partial<Record<string, PullRequestLoad>>>({}).pipe(Atom.keepAlive)
|
|
137
137
|
const queueSelectionAtom = Atom.make<Partial<Record<string, number>>>({}).pipe(Atom.keepAlive)
|
|
138
138
|
const trimQueueLoadCache = (cache: Partial<Record<string, PullRequestLoad>>) => {
|
|
@@ -212,9 +212,7 @@ const labelCacheAtom = Atom.make<Record<string, readonly PullRequestLabel[]>>({}
|
|
|
212
212
|
const pullRequestOverridesAtom = Atom.make<Record<string, PullRequestItem>>({}).pipe(Atom.keepAlive)
|
|
213
213
|
const recentlyCompletedPullRequestsAtom = Atom.make<Record<string, PullRequestItem>>({}).pipe(Atom.keepAlive)
|
|
214
214
|
const usernameAtom = githubRuntime.atom(
|
|
215
|
-
|
|
216
|
-
? GitHubService.use((github) => github.getAuthenticatedUser())
|
|
217
|
-
: Effect.succeed(config.author.replace(/^@/, "")),
|
|
215
|
+
GitHubService.use((github) => github.getAuthenticatedUser()),
|
|
218
216
|
).pipe(Atom.keepAlive)
|
|
219
217
|
|
|
220
218
|
const pullRequestLoadAtom = Atom.make((get) => {
|
|
@@ -350,6 +348,7 @@ const closePullRequestAtom = githubRuntime.fn<{ readonly repository: string; rea
|
|
|
350
348
|
GitHubService.use((github) => github.closePullRequest(input.repository, input.number))
|
|
351
349
|
)
|
|
352
350
|
const createPullRequestCommentAtom = githubRuntime.fn<CreatePullRequestCommentInput>()((input) => GitHubService.use((github) => github.createPullRequestComment(input)))
|
|
351
|
+
const submitPullRequestReviewAtom = githubRuntime.fn<SubmitPullRequestReviewInput>()((input) => GitHubService.use((github) => github.submitPullRequestReview(input)))
|
|
353
352
|
const copyToClipboardAtom = githubRuntime.fn<string>()((text) => Clipboard.use((clipboard) => clipboard.copy(text)))
|
|
354
353
|
const openInBrowserAtom = githubRuntime.fn<PullRequestItem>()((pullRequest) => BrowserOpener.use((browser) => browser.openPullRequest(pullRequest)))
|
|
355
354
|
|
|
@@ -418,6 +417,12 @@ const groupDiffCommentThreads = (pullRequest: PullRequestItem, comments: readonl
|
|
|
418
417
|
|
|
419
418
|
const isLocalDiffComment = (comment: PullRequestReviewComment) => comment.id.startsWith("local:")
|
|
420
419
|
|
|
420
|
+
const reviewStatusAfterSubmit = {
|
|
421
|
+
COMMENT: null,
|
|
422
|
+
APPROVE: "approved",
|
|
423
|
+
REQUEST_CHANGES: "changes",
|
|
424
|
+
} satisfies Record<SubmitPullRequestReviewInput["event"], PullRequestItem["reviewStatus"] | null>
|
|
425
|
+
|
|
421
426
|
const originalDiffLineColor = (anchor: DiffCommentAnchor): DiffLineColorConfig => {
|
|
422
427
|
if (anchor.kind === "addition") {
|
|
423
428
|
return { gutter: colors.diff.addedLineNumberBg, content: colors.diff.addedBg }
|
|
@@ -559,6 +564,8 @@ export const App = () => {
|
|
|
559
564
|
const mergeModalActive = Modal.$is("Merge")(activeModal)
|
|
560
565
|
const commentModalActive = Modal.$is("Comment")(activeModal)
|
|
561
566
|
const commentThreadModalActive = Modal.$is("CommentThread")(activeModal)
|
|
567
|
+
const changedFilesModalActive = Modal.$is("ChangedFiles")(activeModal)
|
|
568
|
+
const submitReviewModalActive = Modal.$is("SubmitReview")(activeModal)
|
|
562
569
|
const themeModalActive = Modal.$is("Theme")(activeModal)
|
|
563
570
|
const commandPaletteActive = Modal.$is("CommandPalette")(activeModal)
|
|
564
571
|
const openRepositoryModalActive = Modal.$is("OpenRepository")(activeModal)
|
|
@@ -567,6 +574,8 @@ export const App = () => {
|
|
|
567
574
|
const mergeModal: MergeModalState = mergeModalActive ? activeModal : initialMergeModalState
|
|
568
575
|
const commentModal: CommentModalState = commentModalActive ? activeModal : initialCommentModalState
|
|
569
576
|
const commentThreadModal: CommentThreadModalState = commentThreadModalActive ? activeModal : initialCommentThreadModalState
|
|
577
|
+
const changedFilesModal: ChangedFilesModalState = changedFilesModalActive ? activeModal : initialChangedFilesModalState
|
|
578
|
+
const submitReviewModal: SubmitReviewModalState = submitReviewModalActive ? activeModal : initialSubmitReviewModalState
|
|
570
579
|
const themeModal: ThemeModalState = themeModalActive ? activeModal : initialThemeModalState
|
|
571
580
|
const commandPalette: CommandPaletteState = commandPaletteActive ? activeModal : initialCommandPaletteState
|
|
572
581
|
const openRepositoryModal: OpenRepositoryModalState = openRepositoryModalActive ? activeModal : initialOpenRepositoryModalState
|
|
@@ -585,6 +594,8 @@ export const App = () => {
|
|
|
585
594
|
const setMergeModal = makeModalSetter("Merge")
|
|
586
595
|
const setCommentModal = makeModalSetter("Comment")
|
|
587
596
|
const setCommentThreadModal = makeModalSetter("CommentThread")
|
|
597
|
+
const setChangedFilesModal = makeModalSetter("ChangedFiles")
|
|
598
|
+
const setSubmitReviewModal = makeModalSetter("SubmitReview")
|
|
588
599
|
const setThemeModal = makeModalSetter("Theme")
|
|
589
600
|
const setCommandPalette = makeModalSetter("CommandPalette")
|
|
590
601
|
const setOpenRepositoryModal = makeModalSetter("OpenRepository")
|
|
@@ -616,6 +627,7 @@ export const App = () => {
|
|
|
616
627
|
const mergePullRequest = useAtomSet(mergePullRequestAtom, { mode: "promise" })
|
|
617
628
|
const closePullRequest = useAtomSet(closePullRequestAtom, { mode: "promise" })
|
|
618
629
|
const createPullRequestComment = useAtomSet(createPullRequestCommentAtom, { mode: "promise" })
|
|
630
|
+
const submitPullRequestReview = useAtomSet(submitPullRequestReviewAtom, { mode: "promise" })
|
|
619
631
|
const copyToClipboard = useAtomSet(copyToClipboardAtom, { mode: "promise" })
|
|
620
632
|
const openInBrowser = useAtomSet(openInBrowserAtom, { mode: "promise" })
|
|
621
633
|
const terminalWidth = width ?? 100
|
|
@@ -724,6 +736,10 @@ export const App = () => {
|
|
|
724
736
|
: [],
|
|
725
737
|
[selectedDiffState, diffWhitespaceMode],
|
|
726
738
|
)
|
|
739
|
+
const changedFileResults = useMemo(
|
|
740
|
+
() => changedFilesModalActive ? filterChangedFiles(readyDiffFiles, changedFilesModal.query) : [],
|
|
741
|
+
[changedFilesModalActive, readyDiffFiles, changedFilesModal.query],
|
|
742
|
+
)
|
|
727
743
|
const displayedDiffState = useMemo(
|
|
728
744
|
() => selectedDiffState?._tag === "Ready"
|
|
729
745
|
? PullRequestDiffState.Ready({ patch: readyDiffFiles.map((file) => file.patch).join("\n"), files: readyDiffFiles })
|
|
@@ -1154,7 +1170,7 @@ export const App = () => {
|
|
|
1154
1170
|
}, [diffFullView])
|
|
1155
1171
|
const isHydratingPullRequestDetails = pullRequestStatus === "ready" && selectedPullRequest?.state === "open" && !selectedPullRequest.detailLoaded
|
|
1156
1172
|
const isRefreshingPullRequests = pullRequestResult.waiting && pullRequestLoad !== null
|
|
1157
|
-
const hasActiveLoadingIndicator = pullRequestResult.waiting || isHydratingPullRequestDetails || isLoadingMorePullRequests || labelModal.loading || closeModal.running || mergeModal.loading || mergeModal.running || selectedDiffState?._tag === "Loading"
|
|
1173
|
+
const hasActiveLoadingIndicator = pullRequestResult.waiting || isHydratingPullRequestDetails || isLoadingMorePullRequests || labelModal.loading || closeModal.running || mergeModal.loading || mergeModal.running || submitReviewModal.running || selectedDiffState?._tag === "Loading"
|
|
1158
1174
|
const loadingIndicator = SPINNER_FRAMES[loadingFrame % SPINNER_FRAMES.length]!
|
|
1159
1175
|
|
|
1160
1176
|
useEffect(() => {
|
|
@@ -1383,9 +1399,9 @@ export const App = () => {
|
|
|
1383
1399
|
return () => { scroll.verticalScrollBar.off("change", sync) }
|
|
1384
1400
|
}, [isWideLayout, detailFullView, diffFullView, syncDetailPreviewScrollState])
|
|
1385
1401
|
|
|
1386
|
-
const
|
|
1402
|
+
const selectDiffFile = (index: number) => {
|
|
1387
1403
|
if (readyDiffFiles.length === 0) return
|
|
1388
|
-
const nextIndex = safeDiffFileIndex(readyDiffFiles,
|
|
1404
|
+
const nextIndex = safeDiffFileIndex(readyDiffFiles, index)
|
|
1389
1405
|
setDiffFileIndex(nextIndex)
|
|
1390
1406
|
setDiffCommentRangeStartIndex(null)
|
|
1391
1407
|
const targetSide = diffPreferredSide ?? selectedDiffCommentAnchor?.side
|
|
@@ -1395,6 +1411,26 @@ export const App = () => {
|
|
|
1395
1411
|
scrollToDiffFile(nextIndex)
|
|
1396
1412
|
}
|
|
1397
1413
|
|
|
1414
|
+
const jumpDiffFile = (delta: 1 | -1) => {
|
|
1415
|
+
selectDiffFile(diffFileIndex + delta)
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
const openChangedFilesModal = () => {
|
|
1419
|
+
if (readyDiffFiles.length === 0) return
|
|
1420
|
+
setChangedFilesModal({
|
|
1421
|
+
query: "",
|
|
1422
|
+
selectedIndex: safeDiffFileIndex(readyDiffFiles, diffFileIndex),
|
|
1423
|
+
})
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
const selectChangedFile = () => {
|
|
1427
|
+
const selectedIndex = changedFileResults.length === 0 ? 0 : Math.max(0, Math.min(changedFilesModal.selectedIndex, changedFileResults.length - 1))
|
|
1428
|
+
const entry = changedFileResults[selectedIndex]
|
|
1429
|
+
if (!entry) return
|
|
1430
|
+
closeActiveModal()
|
|
1431
|
+
selectDiffFile(entry.index)
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1398
1434
|
const navigableDiffCommentAnchors = () => diffCommentRangeStartAnchor
|
|
1399
1435
|
? diffCommentAnchors.filter((anchor) => sameDiffCommentTarget(anchor, diffCommentRangeStartAnchor))
|
|
1400
1436
|
: diffCommentAnchors
|
|
@@ -1474,6 +1510,27 @@ export const App = () => {
|
|
|
1474
1510
|
})
|
|
1475
1511
|
}
|
|
1476
1512
|
|
|
1513
|
+
const editSubmitReview = (transform: (state: CommentEditorValue) => CommentEditorValue) => {
|
|
1514
|
+
setSubmitReviewModal((current) => {
|
|
1515
|
+
const next = transform({ body: current.body, cursor: current.cursor })
|
|
1516
|
+
if (next.body === current.body && next.cursor === current.cursor && current.error === null) return current
|
|
1517
|
+
return { ...current, body: next.body, cursor: next.cursor, error: null }
|
|
1518
|
+
})
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const openSubmitReviewModal = () => {
|
|
1522
|
+
if (!selectedPullRequest || selectedPullRequest.state !== "open") return
|
|
1523
|
+
setSubmitReviewModal({
|
|
1524
|
+
repository: selectedPullRequest.repository,
|
|
1525
|
+
number: selectedPullRequest.number,
|
|
1526
|
+
selectedIndex: 0,
|
|
1527
|
+
body: "",
|
|
1528
|
+
cursor: 0,
|
|
1529
|
+
running: false,
|
|
1530
|
+
error: null,
|
|
1531
|
+
})
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1477
1534
|
const openDiffCommentModal = () => {
|
|
1478
1535
|
if (!selectedDiffCommentAnchor || !selectedPullRequest) return
|
|
1479
1536
|
setCommentModal(initialCommentModalState)
|
|
@@ -1583,6 +1640,31 @@ export const App = () => {
|
|
|
1583
1640
|
})
|
|
1584
1641
|
}
|
|
1585
1642
|
|
|
1643
|
+
const confirmSubmitReview = () => {
|
|
1644
|
+
if (!submitReviewModal.repository || submitReviewModal.number === null || submitReviewModal.running) return
|
|
1645
|
+
const option = submitReviewOptions[submitReviewModal.selectedIndex]
|
|
1646
|
+
if (!option) return
|
|
1647
|
+
const repository = submitReviewModal.repository
|
|
1648
|
+
const number = submitReviewModal.number
|
|
1649
|
+
const body = submitReviewModal.body.trim()
|
|
1650
|
+
const targetPullRequest = pullRequests.find((pullRequest) => pullRequest.repository === repository && pullRequest.number === number) ?? null
|
|
1651
|
+
const nextReviewStatus = reviewStatusAfterSubmit[option.event]
|
|
1652
|
+
|
|
1653
|
+
setSubmitReviewModal((current) => ({ ...current, running: true, error: null }))
|
|
1654
|
+
void submitPullRequestReview({ repository, number, event: option.event, body })
|
|
1655
|
+
.then(() => {
|
|
1656
|
+
if (targetPullRequest && nextReviewStatus) {
|
|
1657
|
+
updatePullRequest(targetPullRequest.url, (pullRequest) => ({ ...pullRequest, reviewStatus: nextReviewStatus }))
|
|
1658
|
+
}
|
|
1659
|
+
closeActiveModal()
|
|
1660
|
+
flashNotice(`Submitted ${option.title.toLowerCase()} review for #${number}`)
|
|
1661
|
+
})
|
|
1662
|
+
.catch((error) => {
|
|
1663
|
+
setSubmitReviewModal((current) => ({ ...current, running: false, error: errorMessage(error) }))
|
|
1664
|
+
flashNotice(errorMessage(error))
|
|
1665
|
+
})
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1586
1668
|
const openSelectedPullRequestInBrowser = (pullRequest: PullRequestItem) => {
|
|
1587
1669
|
void openInBrowser(pullRequest)
|
|
1588
1670
|
.then(() => flashNotice(`Opened #${pullRequest.number} in browser`))
|
|
@@ -1860,10 +1942,18 @@ export const App = () => {
|
|
|
1860
1942
|
editComment((state) => insertText(state, text.replace(/\r\n?/g, "\n")))
|
|
1861
1943
|
return true
|
|
1862
1944
|
}
|
|
1945
|
+
if (submitReviewModalActive) {
|
|
1946
|
+
editSubmitReview((state) => insertText(state, text.replace(/\r\n?/g, "\n")))
|
|
1947
|
+
return true
|
|
1948
|
+
}
|
|
1863
1949
|
if (labelModalActive) {
|
|
1864
1950
|
setLabelModal((current) => ({ ...current, query: current.query + singleLineText(text), selectedIndex: 0 }))
|
|
1865
1951
|
return true
|
|
1866
1952
|
}
|
|
1953
|
+
if (changedFilesModalActive) {
|
|
1954
|
+
setChangedFilesModal((current) => ({ ...current, query: current.query + singleLineText(text), selectedIndex: 0 }))
|
|
1955
|
+
return true
|
|
1956
|
+
}
|
|
1867
1957
|
if (filterMode) {
|
|
1868
1958
|
setFilterDraft((current) => current + singleLineText(text))
|
|
1869
1959
|
return true
|
|
@@ -1883,7 +1973,7 @@ export const App = () => {
|
|
|
1883
1973
|
return () => {
|
|
1884
1974
|
keyInput.off("paste", handlePaste)
|
|
1885
1975
|
}
|
|
1886
|
-
}, [renderer, commandPaletteActive, openRepositoryModalActive, themeModalActive, themeModal.filterMode, commentModalActive, labelModalActive, filterMode])
|
|
1976
|
+
}, [renderer, commandPaletteActive, openRepositoryModalActive, themeModalActive, themeModal.filterMode, commentModalActive, submitReviewModalActive, labelModalActive, changedFilesModalActive, filterMode])
|
|
1887
1977
|
|
|
1888
1978
|
const appCommands: readonly AppCommand[] = buildAppCommands({
|
|
1889
1979
|
pullRequestStatus,
|
|
@@ -1945,11 +2035,13 @@ export const App = () => {
|
|
|
1945
2035
|
toggleDiffRenderView: () => setDiffRenderView((current) => current === "unified" ? "split" : "unified"),
|
|
1946
2036
|
toggleDiffWrapMode: () => setDiffWrapMode((current) => current === "none" ? "word" : "none"),
|
|
1947
2037
|
toggleDiffWhitespaceMode,
|
|
2038
|
+
openChangedFilesModal,
|
|
1948
2039
|
jumpDiffFile,
|
|
1949
2040
|
openSelectedDiffComment,
|
|
1950
2041
|
toggleDiffCommentRange,
|
|
1951
2042
|
moveDiffCommentThread,
|
|
1952
2043
|
openDiffCommentModal,
|
|
2044
|
+
openSubmitReviewModal,
|
|
1953
2045
|
togglePullRequestDraftStatus: toggleSelectedPullRequestDraftStatus,
|
|
1954
2046
|
openLabelModal,
|
|
1955
2047
|
openMergeModal,
|
|
@@ -2015,6 +2107,15 @@ export const App = () => {
|
|
|
2015
2107
|
const max = Math.max(0, filterLabels(labelModal.availableLabels, labelModal.query).length - 1)
|
|
2016
2108
|
return { ...current, selectedIndex: Math.max(0, Math.min(max, current.selectedIndex + delta)) }
|
|
2017
2109
|
})
|
|
2110
|
+
const moveChangedFileSelection = (delta: -1 | 1) => setChangedFilesModal((current) => {
|
|
2111
|
+
const max = Math.max(0, changedFileResults.length - 1)
|
|
2112
|
+
const selectedIndex = Math.max(0, Math.min(max, current.selectedIndex + delta))
|
|
2113
|
+
return selectedIndex === current.selectedIndex ? current : { ...current, selectedIndex }
|
|
2114
|
+
})
|
|
2115
|
+
const moveSubmitReviewActionSelection = (delta: -1 | 1) => setSubmitReviewModal((current) => {
|
|
2116
|
+
const max = Math.max(0, submitReviewOptions.length - 1)
|
|
2117
|
+
return { ...current, selectedIndex: Math.max(0, Math.min(max, current.selectedIndex + delta)), error: null }
|
|
2118
|
+
})
|
|
2018
2119
|
const moveCommandPaletteSelection = (delta: -1 | 1) => setCommandPalette((current) => {
|
|
2019
2120
|
const selectedIndex = clampCommandIndex(current.selectedIndex + delta, commandPaletteCommands)
|
|
2020
2121
|
return selectedIndex === current.selectedIndex ? current : { ...current, selectedIndex }
|
|
@@ -2089,6 +2190,8 @@ export const App = () => {
|
|
|
2089
2190
|
closeModalActive,
|
|
2090
2191
|
mergeModalActive,
|
|
2091
2192
|
commentThreadModalActive,
|
|
2193
|
+
changedFilesModalActive,
|
|
2194
|
+
submitReviewModalActive,
|
|
2092
2195
|
labelModalActive,
|
|
2093
2196
|
themeModalActive,
|
|
2094
2197
|
openRepositoryModalActive,
|
|
@@ -2100,6 +2203,8 @@ export const App = () => {
|
|
|
2100
2203
|
textInputActive: commentModalActive
|
|
2101
2204
|
|| commandPaletteActive
|
|
2102
2205
|
|| openRepositoryModalActive
|
|
2206
|
+
|| changedFilesModalActive
|
|
2207
|
+
|| submitReviewModalActive
|
|
2103
2208
|
|| labelModalActive
|
|
2104
2209
|
|| filterMode
|
|
2105
2210
|
|| (themeModalActive && themeModal.filterMode),
|
|
@@ -2119,6 +2224,32 @@ export const App = () => {
|
|
|
2119
2224
|
openInlineComment: openDiffCommentModal,
|
|
2120
2225
|
scrollBy: scrollCommentThread,
|
|
2121
2226
|
},
|
|
2227
|
+
changedFilesModal: {
|
|
2228
|
+
hasResults: changedFileResults.length > 0,
|
|
2229
|
+
closeModal: closeActiveModal,
|
|
2230
|
+
selectFile: selectChangedFile,
|
|
2231
|
+
moveSelection: moveChangedFileSelection,
|
|
2232
|
+
},
|
|
2233
|
+
submitReviewModal: {
|
|
2234
|
+
closeModal: closeActiveModal,
|
|
2235
|
+
submit: confirmSubmitReview,
|
|
2236
|
+
insertNewline: () => editSubmitReview((state) => insertText(state, "\n")),
|
|
2237
|
+
moveActionSelection: moveSubmitReviewActionSelection,
|
|
2238
|
+
moveLeft: () => editSubmitReview(editorMoveLeft),
|
|
2239
|
+
moveRight: () => editSubmitReview(editorMoveRight),
|
|
2240
|
+
moveUp: () => editSubmitReview((state) => moveVertically(state, -1)),
|
|
2241
|
+
moveDown: () => editSubmitReview((state) => moveVertically(state, 1)),
|
|
2242
|
+
moveLineStart: () => editSubmitReview(moveLineStart),
|
|
2243
|
+
moveLineEnd: () => editSubmitReview(moveLineEnd),
|
|
2244
|
+
moveWordBackward: () => editSubmitReview(moveWordBackward),
|
|
2245
|
+
moveWordForward: () => editSubmitReview(moveWordForward),
|
|
2246
|
+
backspace: () => editSubmitReview(editorBackspace),
|
|
2247
|
+
deleteForward: () => editSubmitReview(editorDeleteForward),
|
|
2248
|
+
deleteWordBackward: () => editSubmitReview(deleteWordBackward),
|
|
2249
|
+
deleteWordForward: () => editSubmitReview(deleteWordForward),
|
|
2250
|
+
deleteToLineStart: () => editSubmitReview(deleteToLineStart),
|
|
2251
|
+
deleteToLineEnd: () => editSubmitReview(deleteToLineEnd),
|
|
2252
|
+
},
|
|
2122
2253
|
labelModal: {
|
|
2123
2254
|
closeModal: closeActiveModal,
|
|
2124
2255
|
toggleSelected: toggleLabelAtIndex,
|
|
@@ -2180,7 +2311,6 @@ export const App = () => {
|
|
|
2180
2311
|
else runCommandById("diff.close")
|
|
2181
2312
|
},
|
|
2182
2313
|
openSelectedComment: openSelectedDiffComment,
|
|
2183
|
-
addComment: () => runCommandById("diff.add-comment"),
|
|
2184
2314
|
toggleRange: () => runCommandById("diff.toggle-range"),
|
|
2185
2315
|
toggleView: () => runCommandById("diff.toggle-view"),
|
|
2186
2316
|
toggleWrap: () => runCommandById("diff.toggle-wrap"),
|
|
@@ -2191,6 +2321,8 @@ export const App = () => {
|
|
|
2191
2321
|
moveAnchorToBoundary: moveDiffCommentToBoundary,
|
|
2192
2322
|
alignAnchor: alignSelectedDiffCommentAnchor,
|
|
2193
2323
|
selectSide: selectDiffCommentSide,
|
|
2324
|
+
openChangedFiles: () => runCommandById("diff.changed-files"),
|
|
2325
|
+
openSubmitReview: () => runCommandById("diff.submit-review"),
|
|
2194
2326
|
nextFile: () => runCommandById("diff.next-file"),
|
|
2195
2327
|
previousFile: () => runCommandById("diff.previous-file"),
|
|
2196
2328
|
openInBrowser: () => runCommandById("pull.open-browser"),
|
|
@@ -2274,9 +2406,21 @@ export const App = () => {
|
|
|
2274
2406
|
return
|
|
2275
2407
|
}
|
|
2276
2408
|
|
|
2409
|
+
if (submitReviewModalActive) {
|
|
2410
|
+
const text = printableKeyText(key)
|
|
2411
|
+
if (text) editSubmitReview((state) => insertText(state, text))
|
|
2412
|
+
return
|
|
2413
|
+
}
|
|
2277
2414
|
|
|
2278
|
-
|
|
2279
|
-
|
|
2415
|
+
if (changedFilesModalActive) {
|
|
2416
|
+
if (isSingleLineInputKey(key)) {
|
|
2417
|
+
setChangedFilesModal((current) => {
|
|
2418
|
+
const query = editSingleLineInput(current.query, key) ?? current.query
|
|
2419
|
+
return query === current.query ? current : { ...current, query, selectedIndex: 0 }
|
|
2420
|
+
})
|
|
2421
|
+
}
|
|
2422
|
+
return
|
|
2423
|
+
}
|
|
2280
2424
|
if (labelModalActive) {
|
|
2281
2425
|
if (isSingleLineInputKey(key)) {
|
|
2282
2426
|
setLabelModal((current) => ({
|
|
@@ -2344,6 +2488,11 @@ export const App = () => {
|
|
|
2344
2488
|
const labelModalHeight = Math.min(20, terminalHeight - 4)
|
|
2345
2489
|
const labelModalLeft = centeredOffset(contentWidth, labelModalWidth)
|
|
2346
2490
|
const labelModalTop = centeredOffset(terminalHeight, labelModalHeight)
|
|
2491
|
+
const longestDiffFileName = changedFilesModalActive ? readyDiffFiles.reduce((max, file) => Math.max(max, file.name.length), 0) : 0
|
|
2492
|
+
const changedFilesModalWidth = changedFilesModalActive ? Math.min(Math.max(46, longestDiffFileName + 16), 88, contentWidth - 4) : 46
|
|
2493
|
+
const changedFilesModalHeight = Math.min(22, terminalHeight - 4)
|
|
2494
|
+
const changedFilesModalLeft = centeredOffset(contentWidth, changedFilesModalWidth)
|
|
2495
|
+
const changedFilesModalTop = centeredOffset(terminalHeight, changedFilesModalHeight)
|
|
2347
2496
|
const sizedModal = (minW: number, maxW: number, padX: number, maxH: number) => {
|
|
2348
2497
|
const w = Math.min(maxW, Math.max(minW, contentWidth - padX))
|
|
2349
2498
|
const h = Math.min(maxH, terminalHeight - 4)
|
|
@@ -2364,6 +2513,11 @@ export const App = () => {
|
|
|
2364
2513
|
const commentThreadModalHeight = commentThreadLayout.height
|
|
2365
2514
|
const commentThreadModalLeft = commentThreadLayout.left
|
|
2366
2515
|
const commentThreadModalTop = commentThreadLayout.top
|
|
2516
|
+
const submitReviewLayout = sizedModal(54, 84, 8, 18)
|
|
2517
|
+
const submitReviewModalWidth = submitReviewLayout.width
|
|
2518
|
+
const submitReviewModalHeight = submitReviewLayout.height
|
|
2519
|
+
const submitReviewModalLeft = submitReviewLayout.left
|
|
2520
|
+
const submitReviewModalTop = submitReviewLayout.top
|
|
2367
2521
|
const commentAnchorLabel = selectedDiffCommentAnchor && selectedDiffCommentLabel
|
|
2368
2522
|
? `${selectedDiffCommentAnchor.path} ${selectedDiffCommentLabel}`
|
|
2369
2523
|
: "No diff line selected"
|
|
@@ -2509,7 +2663,7 @@ export const App = () => {
|
|
|
2509
2663
|
hasSelection={selectedPullRequest !== null}
|
|
2510
2664
|
canCloseSelection={selectedPullRequest?.state === "open"}
|
|
2511
2665
|
hasError={pullRequestStatus === "error"}
|
|
2512
|
-
isLoading={pullRequestStatus === "loading" || isRefreshingPullRequests || isHydratingPullRequestDetails || closeModal.running || mergeModal.running}
|
|
2666
|
+
isLoading={pullRequestStatus === "loading" || isRefreshingPullRequests || isHydratingPullRequestDetails || closeModal.running || mergeModal.running || submitReviewModal.running}
|
|
2513
2667
|
loadingIndicator={loadingIndicator}
|
|
2514
2668
|
retryProgress={retryProgress}
|
|
2515
2669
|
/>
|
|
@@ -2557,6 +2711,27 @@ export const App = () => {
|
|
|
2557
2711
|
offsetTop={commentThreadModalTop}
|
|
2558
2712
|
/>
|
|
2559
2713
|
) : null}
|
|
2714
|
+
{changedFilesModalActive ? (
|
|
2715
|
+
<ChangedFilesModal
|
|
2716
|
+
state={changedFilesModal}
|
|
2717
|
+
results={changedFileResults}
|
|
2718
|
+
totalCount={readyDiffFiles.length}
|
|
2719
|
+
modalWidth={changedFilesModalWidth}
|
|
2720
|
+
modalHeight={changedFilesModalHeight}
|
|
2721
|
+
offsetLeft={changedFilesModalLeft}
|
|
2722
|
+
offsetTop={changedFilesModalTop}
|
|
2723
|
+
/>
|
|
2724
|
+
) : null}
|
|
2725
|
+
{submitReviewModalActive ? (
|
|
2726
|
+
<SubmitReviewModal
|
|
2727
|
+
state={submitReviewModal}
|
|
2728
|
+
modalWidth={submitReviewModalWidth}
|
|
2729
|
+
modalHeight={submitReviewModalHeight}
|
|
2730
|
+
offsetLeft={submitReviewModalLeft}
|
|
2731
|
+
offsetTop={submitReviewModalTop}
|
|
2732
|
+
loadingIndicator={loadingIndicator}
|
|
2733
|
+
/>
|
|
2734
|
+
) : null}
|
|
2560
2735
|
{mergeModalActive ? (
|
|
2561
2736
|
<MergeModal
|
|
2562
2737
|
state={mergeModal}
|
package/src/appCommands.ts
CHANGED
|
@@ -21,11 +21,13 @@ interface AppCommandActions {
|
|
|
21
21
|
readonly toggleDiffRenderView: () => void
|
|
22
22
|
readonly toggleDiffWrapMode: () => void
|
|
23
23
|
readonly toggleDiffWhitespaceMode: () => void
|
|
24
|
+
readonly openChangedFilesModal: () => void
|
|
24
25
|
readonly jumpDiffFile: (delta: 1 | -1) => void
|
|
25
26
|
readonly openSelectedDiffComment: () => void
|
|
26
27
|
readonly toggleDiffCommentRange: () => void
|
|
27
28
|
readonly moveDiffCommentThread: (delta: 1 | -1) => void
|
|
28
29
|
readonly openDiffCommentModal: () => void
|
|
30
|
+
readonly openSubmitReviewModal: () => void
|
|
29
31
|
readonly togglePullRequestDraftStatus: () => void
|
|
30
32
|
readonly openLabelModal: () => void
|
|
31
33
|
readonly openMergeModal: () => void
|
|
@@ -99,6 +101,10 @@ export const buildAppCommands = ({
|
|
|
99
101
|
const diffThreadReason = diffFullView && diffReady
|
|
100
102
|
? hasDiffCommentThreads ? null : "No diff comments loaded."
|
|
101
103
|
: diffOpenReadyReason
|
|
104
|
+
const changedFilesReason = diffFullView && diffReady
|
|
105
|
+
? readyDiffFileCount > 0 ? null : "No changed files loaded."
|
|
106
|
+
: diffOpenReadyReason
|
|
107
|
+
const submitReviewReason = diffFullView && diffReady ? noOpenPullRequestReason : diffOpenReadyReason
|
|
102
108
|
const loadMoreDisabledReason = isLoadingMorePullRequests
|
|
103
109
|
? "Already loading more pull requests."
|
|
104
110
|
: hasMorePullRequests ? null : "No more pull requests loaded by this view."
|
|
@@ -256,13 +262,23 @@ export const buildAppCommands = ({
|
|
|
256
262
|
keywords: ["whitespace", "spacing", "ignore", "show"],
|
|
257
263
|
run: actions.toggleDiffWhitespaceMode,
|
|
258
264
|
}),
|
|
265
|
+
defineCommand({
|
|
266
|
+
id: "diff.changed-files",
|
|
267
|
+
title: "Open changed files navigator",
|
|
268
|
+
scope: "Diff",
|
|
269
|
+
subtitle: readyDiffFileCount > 0 ? `${readyDiffFileCount} changed files` : "No diff files loaded",
|
|
270
|
+
shortcut: "f",
|
|
271
|
+
disabledReason: changedFilesReason,
|
|
272
|
+
keywords: ["files", "navigator", "search"],
|
|
273
|
+
run: actions.openChangedFilesModal,
|
|
274
|
+
}),
|
|
259
275
|
defineCommand({
|
|
260
276
|
id: "diff.next-file",
|
|
261
277
|
title: "Next diff file",
|
|
262
278
|
scope: "Diff",
|
|
263
279
|
subtitle: readyDiffFileCount > 0 ? `${diffFileIndex + 1}/${readyDiffFileCount}` : "No diff files loaded",
|
|
264
280
|
shortcut: "]",
|
|
265
|
-
disabledReason:
|
|
281
|
+
disabledReason: changedFilesReason,
|
|
266
282
|
run: () => actions.jumpDiffFile(1),
|
|
267
283
|
}),
|
|
268
284
|
defineCommand({
|
|
@@ -271,7 +287,7 @@ export const buildAppCommands = ({
|
|
|
271
287
|
scope: "Diff",
|
|
272
288
|
subtitle: readyDiffFileCount > 0 ? `${diffFileIndex + 1}/${readyDiffFileCount}` : "No diff files loaded",
|
|
273
289
|
shortcut: "[",
|
|
274
|
-
disabledReason:
|
|
290
|
+
disabledReason: changedFilesReason,
|
|
275
291
|
run: () => actions.jumpDiffFile(-1),
|
|
276
292
|
}),
|
|
277
293
|
defineCommand({
|
|
@@ -319,11 +335,20 @@ export const buildAppCommands = ({
|
|
|
319
335
|
title: "Add comment on selected diff line",
|
|
320
336
|
scope: "Diff",
|
|
321
337
|
subtitle: selectedDiffCommentAnchorLabel ?? "No diff line selected",
|
|
322
|
-
shortcut: "a",
|
|
323
338
|
disabledReason: selectedDiffLineReason,
|
|
324
339
|
keywords: ["review", "reply"],
|
|
325
340
|
run: actions.openDiffCommentModal,
|
|
326
341
|
}),
|
|
342
|
+
defineCommand({
|
|
343
|
+
id: "diff.submit-review",
|
|
344
|
+
title: "Submit pull request review",
|
|
345
|
+
scope: "Diff",
|
|
346
|
+
subtitle: selectedPullRequestLabel,
|
|
347
|
+
shortcut: "R",
|
|
348
|
+
disabledReason: submitReviewReason,
|
|
349
|
+
keywords: ["review", "approve", "request changes"],
|
|
350
|
+
run: actions.openSubmitReviewModal,
|
|
351
|
+
}),
|
|
327
352
|
forSelected({
|
|
328
353
|
id: "pull.toggle-draft",
|
|
329
354
|
title: selectedPullRequest?.reviewStatus === "draft" ? "Mark ready for review" : "Mark as draft",
|
package/src/config.ts
CHANGED
|
@@ -5,10 +5,6 @@ const positiveIntOr = (fallback: number) => (value: number) => Number.isFinite(v
|
|
|
5
5
|
const pageSizeOr = (fallback: number) => (value: number) => Math.min(100, positiveIntOr(fallback)(value))
|
|
6
6
|
|
|
7
7
|
const appConfig = Config.all({
|
|
8
|
-
author: Config.string("GHUI_AUTHOR").pipe(
|
|
9
|
-
Config.withDefault("@me"),
|
|
10
|
-
Config.map((value) => value.trim() || "@me"),
|
|
11
|
-
),
|
|
12
8
|
prFetchLimit: Config.int("GHUI_PR_FETCH_LIMIT").pipe(
|
|
13
9
|
Config.withDefault(200),
|
|
14
10
|
Config.map(positiveIntOr(200)),
|
|
@@ -17,10 +13,6 @@ const appConfig = Config.all({
|
|
|
17
13
|
Config.withDefault(50),
|
|
18
14
|
Config.map(pageSizeOr(50)),
|
|
19
15
|
),
|
|
20
|
-
repository: Config.string("GHUI_REPO").pipe(
|
|
21
|
-
Config.withDefault(""),
|
|
22
|
-
Config.map((value) => value.trim() || null),
|
|
23
|
-
),
|
|
24
16
|
})
|
|
25
17
|
|
|
26
18
|
export const config = Effect.runSync(Effect.gen(function*() {
|
package/src/domain.ts
CHANGED
|
@@ -16,10 +16,10 @@ export const pullRequestQueueLabels = {
|
|
|
16
16
|
mentioned: "mentioned",
|
|
17
17
|
} as const satisfies Record<PullRequestQueueMode, string>
|
|
18
18
|
|
|
19
|
-
export const pullRequestQueueSearchQualifier = (mode: PullRequestQueueMode,
|
|
19
|
+
export const pullRequestQueueSearchQualifier = (mode: PullRequestQueueMode, repository: string | null) => {
|
|
20
20
|
const qualifiers = {
|
|
21
|
-
repository: repository ? `repo:${repository}` :
|
|
22
|
-
authored:
|
|
21
|
+
repository: repository ? `repo:${repository}` : "author:@me",
|
|
22
|
+
authored: "author:@me",
|
|
23
23
|
review: "review-requested:@me",
|
|
24
24
|
assigned: "assignee:@me",
|
|
25
25
|
mentioned: "mentions:@me",
|
|
@@ -44,6 +44,9 @@ export type DiffCommentSide = Schema.Schema.Type<typeof DiffCommentSide>
|
|
|
44
44
|
|
|
45
45
|
export type PullRequestMergeAction = "squash" | "auto" | "admin" | "disable-auto"
|
|
46
46
|
|
|
47
|
+
export const pullRequestReviewEvents = ["COMMENT", "APPROVE", "REQUEST_CHANGES"] as const
|
|
48
|
+
export type PullRequestReviewEvent = (typeof pullRequestReviewEvents)[number]
|
|
49
|
+
|
|
47
50
|
export interface CheckItem {
|
|
48
51
|
readonly name: string
|
|
49
52
|
readonly status: CheckRunStatus
|
|
@@ -67,6 +70,13 @@ export interface CreatePullRequestCommentInput {
|
|
|
67
70
|
readonly body: string
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
export interface SubmitPullRequestReviewInput {
|
|
74
|
+
readonly repository: string
|
|
75
|
+
readonly number: number
|
|
76
|
+
readonly event: PullRequestReviewEvent
|
|
77
|
+
readonly body: string
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
export interface PullRequestReviewComment {
|
|
71
81
|
readonly id: string
|
|
72
82
|
readonly path: string
|
package/src/keymap/all.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { context } from "@ghui/keymap"
|
|
2
|
+
import { changedFilesModalKeymap, type ChangedFilesModalCtx } from "./changedFilesModal.ts"
|
|
2
3
|
import { closeModalKeymap, type CloseModalCtx } from "./closeModal.ts"
|
|
3
4
|
import { commandPaletteKeymap, type CommandPaletteCtx } from "./commandPalette.ts"
|
|
4
5
|
import { commentModalKeymap, type CommentModalCtx } from "./commentModal.ts"
|
|
@@ -10,6 +11,7 @@ import { labelModalKeymap, type LabelModalCtx } from "./labelModal.ts"
|
|
|
10
11
|
import { listNavKeymap, type ListNavCtx } from "./listNav.ts"
|
|
11
12
|
import { mergeModalKeymap, type MergeModalCtx } from "./mergeModal.ts"
|
|
12
13
|
import { openRepositoryModalKeymap, type OpenRepositoryModalCtx } from "./openRepositoryModal.ts"
|
|
14
|
+
import { submitReviewModalKeymap, type SubmitReviewModalCtx } from "./submitReviewModal.ts"
|
|
13
15
|
import { themeModalKeymap, type ThemeModalCtx } from "./themeModal.ts"
|
|
14
16
|
|
|
15
17
|
export interface AppCtx {
|
|
@@ -17,6 +19,8 @@ export interface AppCtx {
|
|
|
17
19
|
readonly closeModalActive: boolean
|
|
18
20
|
readonly mergeModalActive: boolean
|
|
19
21
|
readonly commentThreadModalActive: boolean
|
|
22
|
+
readonly changedFilesModalActive: boolean
|
|
23
|
+
readonly submitReviewModalActive: boolean
|
|
20
24
|
readonly labelModalActive: boolean
|
|
21
25
|
readonly themeModalActive: boolean
|
|
22
26
|
readonly openRepositoryModalActive: boolean
|
|
@@ -34,6 +38,8 @@ export interface AppCtx {
|
|
|
34
38
|
readonly closeModal: CloseModalCtx
|
|
35
39
|
readonly mergeModal: MergeModalCtx
|
|
36
40
|
readonly commentThreadModal: CommentThreadModalCtx
|
|
41
|
+
readonly changedFilesModal: ChangedFilesModalCtx
|
|
42
|
+
readonly submitReviewModal: SubmitReviewModalCtx
|
|
37
43
|
readonly labelModal: LabelModalCtx
|
|
38
44
|
readonly themeModal: ThemeModalCtx
|
|
39
45
|
readonly openRepositoryModal: OpenRepositoryModalCtx
|
|
@@ -51,15 +57,20 @@ export interface AppCtx {
|
|
|
51
57
|
|
|
52
58
|
const App = context<AppCtx>()
|
|
53
59
|
|
|
60
|
+
const modalActive = (a: AppCtx): boolean =>
|
|
61
|
+
a.closeModalActive
|
|
62
|
+
|| a.mergeModalActive
|
|
63
|
+
|| a.commentThreadModalActive
|
|
64
|
+
|| a.changedFilesModalActive
|
|
65
|
+
|| a.submitReviewModalActive
|
|
66
|
+
|| a.labelModalActive
|
|
67
|
+
|| a.themeModalActive
|
|
68
|
+
|| a.openRepositoryModalActive
|
|
69
|
+
|| a.commentModalActive
|
|
70
|
+
|| a.commandPaletteActive
|
|
71
|
+
|
|
54
72
|
const inListMode = (a: AppCtx): boolean =>
|
|
55
|
-
!a
|
|
56
|
-
&& !a.mergeModalActive
|
|
57
|
-
&& !a.commentThreadModalActive
|
|
58
|
-
&& !a.labelModalActive
|
|
59
|
-
&& !a.themeModalActive
|
|
60
|
-
&& !a.openRepositoryModalActive
|
|
61
|
-
&& !a.commentModalActive
|
|
62
|
-
&& !a.commandPaletteActive
|
|
73
|
+
!modalActive(a)
|
|
63
74
|
&& !a.filterMode
|
|
64
75
|
&& !a.diffFullView
|
|
65
76
|
&& !a.detailFullView
|
|
@@ -87,6 +98,8 @@ export const appKeymap = App(
|
|
|
87
98
|
closeModalKeymap.scope((a) => a.closeModalActive && a.closeModal),
|
|
88
99
|
mergeModalKeymap.scope((a) => a.mergeModalActive && a.mergeModal),
|
|
89
100
|
commentThreadModalKeymap.scope((a) => a.commentThreadModalActive && a.commentThreadModal),
|
|
101
|
+
changedFilesModalKeymap.scope((a) => a.changedFilesModalActive && a.changedFilesModal),
|
|
102
|
+
submitReviewModalKeymap.scope((a) => a.submitReviewModalActive && a.submitReviewModal),
|
|
90
103
|
labelModalKeymap.scope((a) => a.labelModalActive && a.labelModal),
|
|
91
104
|
themeModalKeymap.scope((a) => a.themeModalActive && a.themeModal),
|
|
92
105
|
openRepositoryModalKeymap.scope((a) => a.openRepositoryModalActive && a.openRepositoryModal),
|
|
@@ -95,8 +108,8 @@ export const appKeymap = App(
|
|
|
95
108
|
filterModeKeymap.scope((a) => a.filterMode && a.filterModeCtx),
|
|
96
109
|
|
|
97
110
|
// Full-view layers (only when no modal is on top)
|
|
98
|
-
diffViewKeymap.scope((a) => a.diffFullView && !a
|
|
99
|
-
detailViewKeymap.scope((a) => a.detailFullView && !a
|
|
111
|
+
diffViewKeymap.scope((a) => a.diffFullView && !modalActive(a) && a.diff),
|
|
112
|
+
detailViewKeymap.scope((a) => a.detailFullView && !modalActive(a) && a.detail),
|
|
100
113
|
|
|
101
114
|
// PR list nav
|
|
102
115
|
listNavKeymap.scope((a) => inListMode(a) && a.listNav),
|