@kitlangton/ghui 0.2.0 → 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 +233 -19
- 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/DetailsPane.tsx +25 -17
- 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
|
@@ -8,12 +8,12 @@ import { Cause, Effect, Layer, Schedule } from "effect"
|
|
|
8
8
|
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
9
9
|
import * as Atom from "effect/unstable/reactivity/Atom"
|
|
10
10
|
import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry"
|
|
11
|
-
import { useContext, useEffect, useMemo, useRef, useState } from "react"
|
|
11
|
+
import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
|
|
12
12
|
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")
|
|
@@ -603,6 +614,7 @@ export const App = () => {
|
|
|
603
614
|
const [terminalFocused, setTerminalFocused] = useState(true)
|
|
604
615
|
const [startupLoadComplete, setStartupLoadComplete] = useState(false)
|
|
605
616
|
const [loadingMoreKey, setLoadingMoreKey] = useState<string | null>(null)
|
|
617
|
+
const [detailPreviewScrollTop, setDetailPreviewScrollTop] = useState(0)
|
|
606
618
|
const usernameResult = useAtomValue(usernameAtom)
|
|
607
619
|
const loadRepoLabels = useAtomSet(listRepoLabelsAtom, { mode: "promise" })
|
|
608
620
|
const loadPullRequestPage = useAtomSet(listOpenPullRequestPageAtom, { mode: "promise" })
|
|
@@ -615,6 +627,7 @@ export const App = () => {
|
|
|
615
627
|
const mergePullRequest = useAtomSet(mergePullRequestAtom, { mode: "promise" })
|
|
616
628
|
const closePullRequest = useAtomSet(closePullRequestAtom, { mode: "promise" })
|
|
617
629
|
const createPullRequestComment = useAtomSet(createPullRequestCommentAtom, { mode: "promise" })
|
|
630
|
+
const submitPullRequestReview = useAtomSet(submitPullRequestReviewAtom, { mode: "promise" })
|
|
618
631
|
const copyToClipboard = useAtomSet(copyToClipboardAtom, { mode: "promise" })
|
|
619
632
|
const openInBrowser = useAtomSet(openInBrowserAtom, { mode: "promise" })
|
|
620
633
|
const terminalWidth = width ?? 100
|
|
@@ -644,6 +657,7 @@ export const App = () => {
|
|
|
644
657
|
const maybeRefreshPullRequestsRef = useRef<(minimumAgeMs: number) => void>(() => {})
|
|
645
658
|
const detailScrollRef = useRef<ScrollBoxRenderable | null>(null)
|
|
646
659
|
const detailPreviewScrollRef = useRef<ScrollBoxRenderable | null>(null)
|
|
660
|
+
const detailPreviewScrollTopRef = useRef(0)
|
|
647
661
|
const diffScrollRef = useRef<ScrollBoxRenderable | null>(null)
|
|
648
662
|
const prListScrollRef = useRef<ScrollBoxRenderable | null>(null)
|
|
649
663
|
const diffRenderableRefs = useRef(new Map<number, DiffRenderable>())
|
|
@@ -722,6 +736,10 @@ export const App = () => {
|
|
|
722
736
|
: [],
|
|
723
737
|
[selectedDiffState, diffWhitespaceMode],
|
|
724
738
|
)
|
|
739
|
+
const changedFileResults = useMemo(
|
|
740
|
+
() => changedFilesModalActive ? filterChangedFiles(readyDiffFiles, changedFilesModal.query) : [],
|
|
741
|
+
[changedFilesModalActive, readyDiffFiles, changedFilesModal.query],
|
|
742
|
+
)
|
|
725
743
|
const displayedDiffState = useMemo(
|
|
726
744
|
() => selectedDiffState?._tag === "Ready"
|
|
727
745
|
? PullRequestDiffState.Ready({ patch: readyDiffFiles.map((file) => file.patch).join("\n"), files: readyDiffFiles })
|
|
@@ -1071,6 +1089,10 @@ export const App = () => {
|
|
|
1071
1089
|
setDiffPreferredSide(null)
|
|
1072
1090
|
setDiffCommentRangeStartIndex(null)
|
|
1073
1091
|
detailPreviewScrollRef.current?.scrollTo({ x: 0, y: 0 })
|
|
1092
|
+
if (detailPreviewScrollTopRef.current !== 0) {
|
|
1093
|
+
detailPreviewScrollTopRef.current = 0
|
|
1094
|
+
setDetailPreviewScrollTop(0)
|
|
1095
|
+
}
|
|
1074
1096
|
}, [selectedIndex])
|
|
1075
1097
|
|
|
1076
1098
|
useEffect(() => {
|
|
@@ -1148,7 +1170,7 @@ export const App = () => {
|
|
|
1148
1170
|
}, [diffFullView])
|
|
1149
1171
|
const isHydratingPullRequestDetails = pullRequestStatus === "ready" && selectedPullRequest?.state === "open" && !selectedPullRequest.detailLoaded
|
|
1150
1172
|
const isRefreshingPullRequests = pullRequestResult.waiting && pullRequestLoad !== null
|
|
1151
|
-
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"
|
|
1152
1174
|
const loadingIndicator = SPINNER_FRAMES[loadingFrame % SPINNER_FRAMES.length]!
|
|
1153
1175
|
|
|
1154
1176
|
useEffect(() => {
|
|
@@ -1211,8 +1233,6 @@ export const App = () => {
|
|
|
1211
1233
|
title: `${loadingIndicator} Loading pull request details`,
|
|
1212
1234
|
hint: `${selectedPullRequest.repository} #${selectedPullRequest.number}`,
|
|
1213
1235
|
} : detailPlaceholderContent
|
|
1214
|
-
const detailJunctions = isSelectedPullRequestDetailLoading ? [] : getDetailJunctionRows(selectedPullRequest, rightPaneWidth, true, rightContentWidth, selectedConversationItems, selectedConversationStatus)
|
|
1215
|
-
|
|
1216
1236
|
const halfPage = Math.max(1, Math.floor(wideBodyHeight / 2))
|
|
1217
1237
|
|
|
1218
1238
|
const loadPullRequestComments = (pullRequest: PullRequestItem, force = false) => {
|
|
@@ -1334,8 +1354,23 @@ export const App = () => {
|
|
|
1334
1354
|
setDiffFileIndex((current) => current === nextIndex ? current : nextIndex)
|
|
1335
1355
|
}
|
|
1336
1356
|
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1357
|
+
const syncDetailPreviewScrollState = useCallback(() => {
|
|
1358
|
+
const scrollTop = detailPreviewScrollRef.current?.scrollTop
|
|
1359
|
+
if (scrollTop === undefined) return
|
|
1360
|
+
const nextTop = Math.max(0, Math.floor(scrollTop))
|
|
1361
|
+
if (detailPreviewScrollTopRef.current === nextTop) return
|
|
1362
|
+
detailPreviewScrollTopRef.current = nextTop
|
|
1363
|
+
setDetailPreviewScrollTop(nextTop)
|
|
1364
|
+
}, [])
|
|
1365
|
+
|
|
1366
|
+
const scrollDetailPreviewBy = (y: number) => {
|
|
1367
|
+
detailPreviewScrollRef.current?.scrollBy({ x: 0, y })
|
|
1368
|
+
syncDetailPreviewScrollState()
|
|
1369
|
+
}
|
|
1370
|
+
const scrollDetailPreviewTo = (y: number) => {
|
|
1371
|
+
detailPreviewScrollRef.current?.scrollTo({ x: 0, y })
|
|
1372
|
+
syncDetailPreviewScrollState()
|
|
1373
|
+
}
|
|
1339
1374
|
|
|
1340
1375
|
const ensureDiffLineVisible = (line: number) => {
|
|
1341
1376
|
const scroll = diffScrollRef.current
|
|
@@ -1354,9 +1389,19 @@ export const App = () => {
|
|
|
1354
1389
|
return () => globalThis.clearInterval(interval)
|
|
1355
1390
|
}, [diffFullView, stackedDiffFiles])
|
|
1356
1391
|
|
|
1357
|
-
|
|
1392
|
+
useLayoutEffect(() => {
|
|
1393
|
+
if (!isWideLayout || detailFullView || diffFullView) return
|
|
1394
|
+
const scroll = detailPreviewScrollRef.current
|
|
1395
|
+
if (!scroll) return
|
|
1396
|
+
const sync = () => { syncDetailPreviewScrollState() }
|
|
1397
|
+
scroll.verticalScrollBar.on("change", sync)
|
|
1398
|
+
syncDetailPreviewScrollState()
|
|
1399
|
+
return () => { scroll.verticalScrollBar.off("change", sync) }
|
|
1400
|
+
}, [isWideLayout, detailFullView, diffFullView, syncDetailPreviewScrollState])
|
|
1401
|
+
|
|
1402
|
+
const selectDiffFile = (index: number) => {
|
|
1358
1403
|
if (readyDiffFiles.length === 0) return
|
|
1359
|
-
const nextIndex = safeDiffFileIndex(readyDiffFiles,
|
|
1404
|
+
const nextIndex = safeDiffFileIndex(readyDiffFiles, index)
|
|
1360
1405
|
setDiffFileIndex(nextIndex)
|
|
1361
1406
|
setDiffCommentRangeStartIndex(null)
|
|
1362
1407
|
const targetSide = diffPreferredSide ?? selectedDiffCommentAnchor?.side
|
|
@@ -1366,6 +1411,26 @@ export const App = () => {
|
|
|
1366
1411
|
scrollToDiffFile(nextIndex)
|
|
1367
1412
|
}
|
|
1368
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
|
+
|
|
1369
1434
|
const navigableDiffCommentAnchors = () => diffCommentRangeStartAnchor
|
|
1370
1435
|
? diffCommentAnchors.filter((anchor) => sameDiffCommentTarget(anchor, diffCommentRangeStartAnchor))
|
|
1371
1436
|
: diffCommentAnchors
|
|
@@ -1445,6 +1510,27 @@ export const App = () => {
|
|
|
1445
1510
|
})
|
|
1446
1511
|
}
|
|
1447
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
|
+
|
|
1448
1534
|
const openDiffCommentModal = () => {
|
|
1449
1535
|
if (!selectedDiffCommentAnchor || !selectedPullRequest) return
|
|
1450
1536
|
setCommentModal(initialCommentModalState)
|
|
@@ -1554,6 +1640,31 @@ export const App = () => {
|
|
|
1554
1640
|
})
|
|
1555
1641
|
}
|
|
1556
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
|
+
|
|
1557
1668
|
const openSelectedPullRequestInBrowser = (pullRequest: PullRequestItem) => {
|
|
1558
1669
|
void openInBrowser(pullRequest)
|
|
1559
1670
|
.then(() => flashNotice(`Opened #${pullRequest.number} in browser`))
|
|
@@ -1831,10 +1942,18 @@ export const App = () => {
|
|
|
1831
1942
|
editComment((state) => insertText(state, text.replace(/\r\n?/g, "\n")))
|
|
1832
1943
|
return true
|
|
1833
1944
|
}
|
|
1945
|
+
if (submitReviewModalActive) {
|
|
1946
|
+
editSubmitReview((state) => insertText(state, text.replace(/\r\n?/g, "\n")))
|
|
1947
|
+
return true
|
|
1948
|
+
}
|
|
1834
1949
|
if (labelModalActive) {
|
|
1835
1950
|
setLabelModal((current) => ({ ...current, query: current.query + singleLineText(text), selectedIndex: 0 }))
|
|
1836
1951
|
return true
|
|
1837
1952
|
}
|
|
1953
|
+
if (changedFilesModalActive) {
|
|
1954
|
+
setChangedFilesModal((current) => ({ ...current, query: current.query + singleLineText(text), selectedIndex: 0 }))
|
|
1955
|
+
return true
|
|
1956
|
+
}
|
|
1838
1957
|
if (filterMode) {
|
|
1839
1958
|
setFilterDraft((current) => current + singleLineText(text))
|
|
1840
1959
|
return true
|
|
@@ -1854,7 +1973,7 @@ export const App = () => {
|
|
|
1854
1973
|
return () => {
|
|
1855
1974
|
keyInput.off("paste", handlePaste)
|
|
1856
1975
|
}
|
|
1857
|
-
}, [renderer, commandPaletteActive, openRepositoryModalActive, themeModalActive, themeModal.filterMode, commentModalActive, labelModalActive, filterMode])
|
|
1976
|
+
}, [renderer, commandPaletteActive, openRepositoryModalActive, themeModalActive, themeModal.filterMode, commentModalActive, submitReviewModalActive, labelModalActive, changedFilesModalActive, filterMode])
|
|
1858
1977
|
|
|
1859
1978
|
const appCommands: readonly AppCommand[] = buildAppCommands({
|
|
1860
1979
|
pullRequestStatus,
|
|
@@ -1916,11 +2035,13 @@ export const App = () => {
|
|
|
1916
2035
|
toggleDiffRenderView: () => setDiffRenderView((current) => current === "unified" ? "split" : "unified"),
|
|
1917
2036
|
toggleDiffWrapMode: () => setDiffWrapMode((current) => current === "none" ? "word" : "none"),
|
|
1918
2037
|
toggleDiffWhitespaceMode,
|
|
2038
|
+
openChangedFilesModal,
|
|
1919
2039
|
jumpDiffFile,
|
|
1920
2040
|
openSelectedDiffComment,
|
|
1921
2041
|
toggleDiffCommentRange,
|
|
1922
2042
|
moveDiffCommentThread,
|
|
1923
2043
|
openDiffCommentModal,
|
|
2044
|
+
openSubmitReviewModal,
|
|
1924
2045
|
togglePullRequestDraftStatus: toggleSelectedPullRequestDraftStatus,
|
|
1925
2046
|
openLabelModal,
|
|
1926
2047
|
openMergeModal,
|
|
@@ -1986,6 +2107,15 @@ export const App = () => {
|
|
|
1986
2107
|
const max = Math.max(0, filterLabels(labelModal.availableLabels, labelModal.query).length - 1)
|
|
1987
2108
|
return { ...current, selectedIndex: Math.max(0, Math.min(max, current.selectedIndex + delta)) }
|
|
1988
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
|
+
})
|
|
1989
2119
|
const moveCommandPaletteSelection = (delta: -1 | 1) => setCommandPalette((current) => {
|
|
1990
2120
|
const selectedIndex = clampCommandIndex(current.selectedIndex + delta, commandPaletteCommands)
|
|
1991
2121
|
return selectedIndex === current.selectedIndex ? current : { ...current, selectedIndex }
|
|
@@ -2060,6 +2190,8 @@ export const App = () => {
|
|
|
2060
2190
|
closeModalActive,
|
|
2061
2191
|
mergeModalActive,
|
|
2062
2192
|
commentThreadModalActive,
|
|
2193
|
+
changedFilesModalActive,
|
|
2194
|
+
submitReviewModalActive,
|
|
2063
2195
|
labelModalActive,
|
|
2064
2196
|
themeModalActive,
|
|
2065
2197
|
openRepositoryModalActive,
|
|
@@ -2071,6 +2203,8 @@ export const App = () => {
|
|
|
2071
2203
|
textInputActive: commentModalActive
|
|
2072
2204
|
|| commandPaletteActive
|
|
2073
2205
|
|| openRepositoryModalActive
|
|
2206
|
+
|| changedFilesModalActive
|
|
2207
|
+
|| submitReviewModalActive
|
|
2074
2208
|
|| labelModalActive
|
|
2075
2209
|
|| filterMode
|
|
2076
2210
|
|| (themeModalActive && themeModal.filterMode),
|
|
@@ -2090,6 +2224,32 @@ export const App = () => {
|
|
|
2090
2224
|
openInlineComment: openDiffCommentModal,
|
|
2091
2225
|
scrollBy: scrollCommentThread,
|
|
2092
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
|
+
},
|
|
2093
2253
|
labelModal: {
|
|
2094
2254
|
closeModal: closeActiveModal,
|
|
2095
2255
|
toggleSelected: toggleLabelAtIndex,
|
|
@@ -2151,7 +2311,6 @@ export const App = () => {
|
|
|
2151
2311
|
else runCommandById("diff.close")
|
|
2152
2312
|
},
|
|
2153
2313
|
openSelectedComment: openSelectedDiffComment,
|
|
2154
|
-
addComment: () => runCommandById("diff.add-comment"),
|
|
2155
2314
|
toggleRange: () => runCommandById("diff.toggle-range"),
|
|
2156
2315
|
toggleView: () => runCommandById("diff.toggle-view"),
|
|
2157
2316
|
toggleWrap: () => runCommandById("diff.toggle-wrap"),
|
|
@@ -2162,6 +2321,8 @@ export const App = () => {
|
|
|
2162
2321
|
moveAnchorToBoundary: moveDiffCommentToBoundary,
|
|
2163
2322
|
alignAnchor: alignSelectedDiffCommentAnchor,
|
|
2164
2323
|
selectSide: selectDiffCommentSide,
|
|
2324
|
+
openChangedFiles: () => runCommandById("diff.changed-files"),
|
|
2325
|
+
openSubmitReview: () => runCommandById("diff.submit-review"),
|
|
2165
2326
|
nextFile: () => runCommandById("diff.next-file"),
|
|
2166
2327
|
previousFile: () => runCommandById("diff.previous-file"),
|
|
2167
2328
|
openInBrowser: () => runCommandById("pull.open-browser"),
|
|
@@ -2245,9 +2406,21 @@ export const App = () => {
|
|
|
2245
2406
|
return
|
|
2246
2407
|
}
|
|
2247
2408
|
|
|
2409
|
+
if (submitReviewModalActive) {
|
|
2410
|
+
const text = printableKeyText(key)
|
|
2411
|
+
if (text) editSubmitReview((state) => insertText(state, text))
|
|
2412
|
+
return
|
|
2413
|
+
}
|
|
2248
2414
|
|
|
2249
|
-
|
|
2250
|
-
|
|
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
|
+
}
|
|
2251
2424
|
if (labelModalActive) {
|
|
2252
2425
|
if (isSingleLineInputKey(key)) {
|
|
2253
2426
|
setLabelModal((current) => ({
|
|
@@ -2284,6 +2457,16 @@ export const App = () => {
|
|
|
2284
2457
|
const wideDetailBodyViewportHeight = Math.max(1, wideBodyHeight - wideDetailHeaderHeight)
|
|
2285
2458
|
const wideDetailBodyHeight = getScrollableDetailBodyHeight(selectedPullRequest, rightContentWidth, selectedConversationItems, selectedConversationStatus)
|
|
2286
2459
|
const wideDetailBodyScrollable = wideDetailBodyHeight > wideDetailBodyViewportHeight
|
|
2460
|
+
const detailJunctions = isSelectedPullRequestDetailLoading ? [] : getDetailJunctionRows({
|
|
2461
|
+
pullRequest: selectedPullRequest,
|
|
2462
|
+
paneWidth: rightPaneWidth,
|
|
2463
|
+
showChecks: true,
|
|
2464
|
+
contentWidth: rightContentWidth,
|
|
2465
|
+
conversationItems: selectedConversationItems,
|
|
2466
|
+
conversationStatus: selectedConversationStatus,
|
|
2467
|
+
bodyScrollTop: detailPreviewScrollTop,
|
|
2468
|
+
bodyViewportHeight: wideDetailBodyViewportHeight,
|
|
2469
|
+
})
|
|
2287
2470
|
|
|
2288
2471
|
const prListProps = {
|
|
2289
2472
|
groups: visibleGroups,
|
|
@@ -2305,6 +2488,11 @@ export const App = () => {
|
|
|
2305
2488
|
const labelModalHeight = Math.min(20, terminalHeight - 4)
|
|
2306
2489
|
const labelModalLeft = centeredOffset(contentWidth, labelModalWidth)
|
|
2307
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)
|
|
2308
2496
|
const sizedModal = (minW: number, maxW: number, padX: number, maxH: number) => {
|
|
2309
2497
|
const w = Math.min(maxW, Math.max(minW, contentWidth - padX))
|
|
2310
2498
|
const h = Math.min(maxH, terminalHeight - 4)
|
|
@@ -2325,6 +2513,11 @@ export const App = () => {
|
|
|
2325
2513
|
const commentThreadModalHeight = commentThreadLayout.height
|
|
2326
2514
|
const commentThreadModalLeft = commentThreadLayout.left
|
|
2327
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
|
|
2328
2521
|
const commentAnchorLabel = selectedDiffCommentAnchor && selectedDiffCommentLabel
|
|
2329
2522
|
? `${selectedDiffCommentAnchor.path} ${selectedDiffCommentLabel}`
|
|
2330
2523
|
: "No diff line selected"
|
|
@@ -2470,7 +2663,7 @@ export const App = () => {
|
|
|
2470
2663
|
hasSelection={selectedPullRequest !== null}
|
|
2471
2664
|
canCloseSelection={selectedPullRequest?.state === "open"}
|
|
2472
2665
|
hasError={pullRequestStatus === "error"}
|
|
2473
|
-
isLoading={pullRequestStatus === "loading" || isRefreshingPullRequests || isHydratingPullRequestDetails || closeModal.running || mergeModal.running}
|
|
2666
|
+
isLoading={pullRequestStatus === "loading" || isRefreshingPullRequests || isHydratingPullRequestDetails || closeModal.running || mergeModal.running || submitReviewModal.running}
|
|
2474
2667
|
loadingIndicator={loadingIndicator}
|
|
2475
2668
|
retryProgress={retryProgress}
|
|
2476
2669
|
/>
|
|
@@ -2518,6 +2711,27 @@ export const App = () => {
|
|
|
2518
2711
|
offsetTop={commentThreadModalTop}
|
|
2519
2712
|
/>
|
|
2520
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}
|
|
2521
2735
|
{mergeModalActive ? (
|
|
2522
2736
|
<MergeModal
|
|
2523
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*() {
|