From 0da4dfff2e5c309c4252dd4f50f287a36a80df78 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 8 Oct 2025 16:40:42 -0400 Subject: [PATCH 01/83] Fixes component imports for home banner --- src/webviews/apps/home/home.ts | 1 - src/webviews/apps/plus/shared/components/home-header.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index fad7c519c54e5..bef74b1937f62 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -29,7 +29,6 @@ import './components/ama-banner'; import './components/integration-banner'; import './components/preview-banner'; import '../shared/components/mcp-banner'; -import './components/promo-banner'; import './components/repo-alerts'; import '../shared/components/banner/banner'; diff --git a/src/webviews/apps/plus/shared/components/home-header.ts b/src/webviews/apps/plus/shared/components/home-header.ts index ef6710d07abcc..d78d2e5c78f4a 100644 --- a/src/webviews/apps/plus/shared/components/home-header.ts +++ b/src/webviews/apps/plus/shared/components/home-header.ts @@ -6,11 +6,11 @@ import type { GlAccountChip } from './account-chip'; import './account-chip'; import './integrations-chip'; import '../../../home/components/onboarding'; +import '../../../home/components/promo-banner'; import '../../../shared/components/button'; import '../../../shared/components/button-container'; import '../../../shared/components/code-icon'; import '../../../shared/components/overlays/popover'; -import '../../../shared/components/promo'; // import '../../../shared/components/snow'; @customElement('gl-home-header') From 022b2211a59e6b3f90071ad2e1d46acdd9207612 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 8 Oct 2025 16:41:49 -0400 Subject: [PATCH 02/83] Fixes wrong next paid plan --- src/plus/gk/utils/subscription.utils.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plus/gk/utils/subscription.utils.ts b/src/plus/gk/utils/subscription.utils.ts index dd3595cfe8897..82a75beecf339 100644 --- a/src/plus/gk/utils/subscription.utils.ts +++ b/src/plus/gk/utils/subscription.utils.ts @@ -83,7 +83,12 @@ export function computeSubscriptionState(subscription: Optional): PaidSubscriptionPlanIds { - const next = orderedPaidPlans.indexOf(subscription.plan.actual.id as PaidSubscriptionPlanIds) + 1; + let next = orderedPaidPlans.indexOf(subscription.plan.actual.id as PaidSubscriptionPlanIds) + 1; + // Skip the student plan since we cannot determine if the user is student-eligible or not + if (next === 0) { + next++; + } + if (next >= orderedPaidPlans.length) return 'enterprise'; // Not sure what to do here return orderedPaidPlans[next] ?? 'pro'; From d92613e5b789d7977b3117950652eb6df765346d Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 8 Oct 2025 17:20:46 -0400 Subject: [PATCH 03/83] Updates CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94d4e62101491..8a163eebd93d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Fixed + +- Fixes eyebrow banner not appearing for GitLens Community on Home ([#4670](https://github.com/gitkraken/vscode-gitlens/issues/4670)) + ## [17.6.0] - 2025-10-07 ### Added From 0fe50347ac726dd43fe0ae5b73cdbd162d40d3cb Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 8 Oct 2025 20:14:50 -0400 Subject: [PATCH 04/83] Adds more logging --- src/env/node/git/sub-providers/commits.ts | 9 ++++++++- src/views/nodes/branchNode.ts | 11 +++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/env/node/git/sub-providers/commits.ts b/src/env/node/git/sub-providers/commits.ts index e1fac471ce675..b569965d8eb21 100644 --- a/src/env/node/git/sub-providers/commits.ts +++ b/src/env/node/git/sub-providers/commits.ts @@ -49,11 +49,12 @@ import { isRevisionRange, isSha, isUncommitted, isUncommittedStaged } from '../. import { isUserMatch } from '../../../../git/utils/user.utils'; import { configuration } from '../../../../system/-webview/configuration'; import { splitPath } from '../../../../system/-webview/path'; -import { log } from '../../../../system/decorators/log'; +import { debug, log } from '../../../../system/decorators/log'; import { filterMap, first, join, last, some } from '../../../../system/iterable'; import { Logger } from '../../../../system/logger'; import { getLogScope } from '../../../../system/logger.scope'; import { isFolderGlob, stripFolderGlob } from '../../../../system/path'; +import { maybeStopWatch } from '../../../../system/stopwatch'; import type { CachedLog, TrackedGitDocument } from '../../../../trackers/trackedDocument'; import { GitDocumentState } from '../../../../trackers/trackedDocument'; import type { Git, GitResult } from '../git'; @@ -380,6 +381,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider { return this.getLogCore(repoPath, rev, options, cancellation); } + @debug({ args: { 2: false, 3: false, 4: false }, exit: true }) private async getLogCore( repoPath: string, rev?: string | undefined, @@ -1326,6 +1328,9 @@ async function parseCommits( if (resultOrStream instanceof Promise) { const result = await resultOrStream; + const scope = getLogScope(); + using sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); + if (stashes?.size) { const allowFilteredFiles = searchFilters?.files ?? false; const stashesOnly = searchFilters?.type === 'stash'; @@ -1367,6 +1372,8 @@ async function parseCommits( } } + sw?.stop({ suffix: ` created ${count} commits` }); + return { commits: commits, count: count, countStashChildCommits: countStashChildCommits }; } diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index 676662d49dc70..ea3e63b880fc4 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -13,7 +13,7 @@ import { isStash } from '../../git/models/commit'; import type { GitLog } from '../../git/models/log'; import type { PullRequest, PullRequestState } from '../../git/models/pullRequest'; import type { GitBranchReference } from '../../git/models/reference'; -import type { Repository } from '../../git/models/repository'; +import type { Repository, RepositoryChangeEvent } from '../../git/models/repository'; import type { GitUser } from '../../git/models/user'; import type { GitWorktree } from '../../git/models/worktree'; import { getBranchAheadRange, getBranchMergeTargetName } from '../../git/utils/-webview/branch.utils'; @@ -780,9 +780,7 @@ export class CommitsCurrentBranchNode extends SubscribeableViewNode<'commits-cur const interval = getLastFetchedUpdateInterval(lastFetched); if (lastFetched !== 0 && interval > 0) { return Disposable.from( - this.repo != null - ? weakEvent(this.repo.onDidChange, () => this.view.triggerNodeChange(this), this) - : emptyDisposable, + this.repo != null ? weakEvent(this.repo.onDidChange, this.onRepositoryChanged, this) : emptyDisposable, disposableInterval(() => { // Check if the interval should change, and if so, reset it if (interval !== getLastFetchedUpdateInterval(lastFetched)) { @@ -796,4 +794,9 @@ export class CommitsCurrentBranchNode extends SubscribeableViewNode<'commits-cur return undefined; } + + @debug({ args: { 0: e => e.toString() } }) + private onRepositoryChanged(_e: RepositoryChangeEvent) { + this.view.triggerNodeChange(this); + } } From 130e49565c63a50ed551a8c5d5bb07d3a976a92f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 8 Oct 2025 20:15:21 -0400 Subject: [PATCH 05/83] Reduces view refresh freq for fetch time --- src/git/utils/fetch.utils.ts | 44 +++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/git/utils/fetch.utils.ts b/src/git/utils/fetch.utils.ts index 999410f8290c5..1960564d8b5d3 100644 --- a/src/git/utils/fetch.utils.ts +++ b/src/git/utils/fetch.utils.ts @@ -2,9 +2,47 @@ const millisecondsPerMinute = 60 * 1000; const millisecondsPerHour = 60 * 60 * 1000; export const millisecondsPerDay = 24 * 60 * 60 * 1000; +/** + * Calculates the update interval for fetch status based on how long ago the last fetch occurred. + * Uses stepped intervals to prevent thrashing from frequent recalculations. + * + * @param lastFetched - Timestamp (in milliseconds) of the last fetch + * @returns Update interval in milliseconds + * + * Interval schedule: + * - < 15 minutes ago: refresh every 5 minutes + * - < 30 minutes ago: refresh every 10 minutes + * - < 1 hour ago: refresh every 20 minutes + * - < 3 hours ago: refresh every 1 hour + * - < 6 hours ago: refresh every 2 hours + * - < 12 hours ago: refresh every 4 hours + * - < 2 days ago: refresh every 8 hours + * - ≥ 2 days ago: refresh every 1 day + */ export function getLastFetchedUpdateInterval(lastFetched: number): number { const timeDiff = Date.now() - lastFetched; - return timeDiff < millisecondsPerDay - ? (timeDiff < millisecondsPerHour ? millisecondsPerMinute : millisecondsPerHour) / 2 - : 0; + + // Stepped intervals to prevent thrashing + if (timeDiff < 15 * millisecondsPerMinute) { + return 5 * millisecondsPerMinute; + } + if (timeDiff < 30 * millisecondsPerMinute) { + return 10 * millisecondsPerMinute; + } + if (timeDiff < millisecondsPerHour) { + return 20 * millisecondsPerMinute; + } + if (timeDiff < 3 * millisecondsPerHour) { + return millisecondsPerHour; + } + if (timeDiff < 6 * millisecondsPerHour) { + return 2 * millisecondsPerHour; + } + if (timeDiff < 12 * millisecondsPerHour) { + return 4 * millisecondsPerHour; + } + if (timeDiff < 2 * millisecondsPerDay) { + return 8 * millisecondsPerHour; + } + return millisecondsPerDay; } From 0ae041c163f0b8bbfdf685d3540ec54c004d98d0 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 15 Oct 2025 15:30:05 -0400 Subject: [PATCH 06/83] Updates auto-compose instructions setting text to a link --- .../plus/composer/components/commits-panel.ts | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/webviews/apps/plus/composer/components/commits-panel.ts b/src/webviews/apps/plus/composer/components/commits-panel.ts index 3adc1ea07dce8..965610755e85e 100644 --- a/src/webviews/apps/plus/composer/components/commits-panel.ts +++ b/src/webviews/apps/plus/composer/components/commits-panel.ts @@ -18,6 +18,7 @@ import { ruleStyles } from '../../shared/components/vscode.css'; import { composerItemCommitStyles, composerItemContentStyles, composerItemStyles } from './composer.css'; import '../../../shared/components/button'; import '../../../shared/components/button-container'; +import '../../../shared/components/overlays/popover'; import './commit-item'; @customElement('gl-commits-panel') @@ -285,7 +286,15 @@ export class CommitsPanel extends LitElement { } .auto-compose__instructions-info { - --gl-tooltip-max-width: 37rem; + --max-width: 37rem; + + a:has(.inline-code) { + text-decoration: none; + white-space: nowrap; + } + .inline-code code-icon { + vertical-align: middle; + } } .auto-compose__instructions-input { width: 100%; @@ -1059,9 +1068,11 @@ export class CommitsPanel extends LitElement { @input=${this.handleCustomInstructionsChange} ?disabled=${disabled} > - - -
+ + + + +
Providing additional instructions can help steer the AI composition for this session.

Potential instructions include: @@ -1073,9 +1084,15 @@ export class CommitsPanel extends LitElement {
You can also specify custom instructions that apply to all composer sessions with the following setting: - gitlens.ai.generateCommits.customInstructions + + gitlens.ai.generateCommits.customInstructions
- +
From 1d6a52fa529207798da523a8133e955642415707 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 15 Oct 2025 15:41:25 -0400 Subject: [PATCH 07/83] Updates CHANGELOG (post 17.6.1) --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a163eebd93d1..b8a8b91feb981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +## [17.6.1] - 2025-10-08 + ### Fixed - Fixes eyebrow banner not appearing for GitLens Community on Home ([#4670](https://github.com/gitkraken/vscode-gitlens/issues/4670)) @@ -6387,7 +6389,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Initial release but still heavily a work in progress. -[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.0...HEAD +[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.1...HEAD +[17.6.1]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.0...gitkraken:v17.6.1 [17.6.0]: https://github.com/gitkraken/vscode-gitlens/compare/v17.5.1...gitkraken:v17.6.0 [17.5.1]: https://github.com/gitkraken/vscode-gitlens/compare/v17.5.0...gitkraken:v17.5.1 [17.5.0]: https://github.com/gitkraken/vscode-gitlens/compare/v17.4.1...gitkraken:v17.5.0 From 2c3a366287d414a1302ba37fc2479aa8280d88fb Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 15 Oct 2025 15:43:43 -0400 Subject: [PATCH 08/83] Fixes #4691 Kiro mcp extension registration doesn't work --- CHANGELOG.md | 4 ++++ src/plus/gk/utils/-webview/mcp.utils.ts | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8a8b91feb981..25830b45f352c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Fixed + +- Fixes MCP extension registration not working on Kiro ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) + ## [17.6.1] - 2025-10-08 ### Fixed diff --git a/src/plus/gk/utils/-webview/mcp.utils.ts b/src/plus/gk/utils/-webview/mcp.utils.ts index 303d1e68b68f7..06924e2ebc38f 100644 --- a/src/plus/gk/utils/-webview/mcp.utils.ts +++ b/src/plus/gk/utils/-webview/mcp.utils.ts @@ -1,4 +1,4 @@ -import { lm, version } from 'vscode'; +import { env, lm, version } from 'vscode'; import { isWeb } from '@env/platform'; import type { Container } from '../../../../container'; import { configuration } from '../../../../system/-webview/configuration'; @@ -13,8 +13,9 @@ export function isMcpBannerEnabled(container: Container, showAutoRegistration = return !container.storage.get('mcp:banner:dismissed', false); } +const supportedApps = ['Visual Studio Code', 'Visual Studio Code - Insiders', 'Visual Studio Code - Exploration']; export function supportsMcpExtensionRegistration(): boolean { - if (isWeb) { + if (isWeb || !supportedApps.includes(env.appName)) { return false; } From a50e763e4b1e365b4d2c8501cc7090fa29f94cc0 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:26:50 -0700 Subject: [PATCH 09/83] Stores hunks and safety state on webview host, uses for ai operations and safety checks (#4583) --- .../apps/plus/composer/components/app.ts | 18 +---- .../apps/plus/composer/stateProvider.ts | 2 - src/webviews/plus/composer/composerWebview.ts | 77 +++++++++++++------ src/webviews/plus/composer/mockData.ts | 16 +--- src/webviews/plus/composer/protocol.ts | 43 ++--------- src/webviews/plus/composer/utils.ts | 45 ++++------- 6 files changed, 81 insertions(+), 120 deletions(-) diff --git a/src/webviews/apps/plus/composer/components/app.ts b/src/webviews/apps/plus/composer/components/app.ts index 26dd71ed431f8..2ea6289ede40a 100644 --- a/src/webviews/apps/plus/composer/components/app.ts +++ b/src/webviews/apps/plus/composer/components/app.ts @@ -27,7 +27,7 @@ import { OpenOnboardingCommand, ReloadComposerCommand, } from '../../../../plus/composer/protocol'; -import { createCombinedDiffForCommit, updateHunkAssignments } from '../../../../plus/composer/utils'; +import { updateHunkAssignments } from '../../../../plus/composer/utils'; import type { RepoButtonGroupClickEvent } from '../../../shared/components/repo-button-group'; import { focusableBaseStyles } from '../../../shared/components/styles/lit/a11y.css'; import { boxSizingBase } from '../../../shared/components/styles/lit/base.css'; @@ -1271,9 +1271,7 @@ export class ComposerApp extends LitElement { private finishAndCommit() { this._ipc.sendCommand(FinishAndCommitCommand, { commits: this.state.commits, - hunks: this.hunksWithAssignments, baseCommit: this.state.baseCommit, - safetyState: this.state.safetyState, }); } @@ -1288,7 +1286,6 @@ export class ComposerApp extends LitElement { private handleReloadComposer() { this.resetHistory(); this._ipc.sendCommand(ReloadComposerCommand, { - repoPath: this.state.safetyState.repoPath, mode: this.state.mode, }); } @@ -1480,11 +1477,8 @@ export class ComposerApp extends LitElement { this.saveToHistory(); this._ipc.sendCommand(GenerateCommitsCommand, { - hunks: hunksToGenerate, - // In preview mode, send empty commits array to overwrite existing commits - // In interactive mode, send existing commits to preserve them + hunkIndices: hunksToGenerate.map(hunk => hunk.index), commits: this.isPreviewMode ? [] : this.state.commits, - hunkMap: this.state.hunkMap, baseCommit: this.state.baseCommit, customInstructions: customInstructions || undefined, }); @@ -1499,15 +1493,9 @@ export class ComposerApp extends LitElement { return; } - // Create combined diff for the commit - const { patch } = createCombinedDiffForCommit(commit, this.hunksWithAssignments); - if (!patch) { - return; - } - this._ipc.sendCommand(GenerateCommitMessageCommand, { commitId: commitId, - diff: patch, + commitHunkIndices: commit.hunkIndices, overwriteExistingMessage: commit.message.trim() !== '', }); } diff --git a/src/webviews/apps/plus/composer/stateProvider.ts b/src/webviews/apps/plus/composer/stateProvider.ts index 6e45c2d34a55a..6f37a2b8d6f8a 100644 --- a/src/webviews/apps/plus/composer/stateProvider.ts +++ b/src/webviews/apps/plus/composer/stateProvider.ts @@ -136,9 +136,7 @@ export class ComposerStateProvider implements StateProvider { ...this._state, hunks: msg.params.hunks, commits: msg.params.commits, - hunkMap: msg.params.hunkMap, baseCommit: msg.params.baseCommit, - safetyState: msg.params.safetyState, loadingError: msg.params.loadingError, hasChanges: msg.params.hasChanges, safetyError: null, // Clear any existing safety errors diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index 00a89ad1f4d60..dd8c486181660 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -25,7 +25,9 @@ import type { ComposerContext, ComposerGenerateCommitMessageEventData, ComposerGenerateCommitsEventData, + ComposerHunk, ComposerLoadedErrorData, + ComposerSafetyState, ComposerTelemetryEvent, FinishAndCommitParams, GenerateCommitMessageParams, @@ -78,6 +80,7 @@ import { import type { ComposerWebviewShowingArgs } from './registration'; import { convertToComposerDiffInfo, + createCombinedDiffForCommit, createHunksFromDiffs, createSafetyState, getWorkingTreeDiffs, @@ -98,6 +101,10 @@ export class ComposerWebviewProvider implements WebviewProvider ({ - index: hunk.index, - fileName: hunk.fileName, - diffHeader: hunk.diffHeader || `diff --git a/${hunk.fileName} b/${hunk.fileName}`, - hunkHeader: hunk.hunkHeader, - content: hunk.content, - source: hunk.source, - })); + const hunks = []; + for (const index of params.hunkIndices) { + hunks.push({ ...this._hunks.find(m => m.index === index)!, assigned: true }); + } const existingCommits = params.commits.map(commit => ({ id: commit.id, @@ -808,7 +818,7 @@ export class ComposerWebviewProvider implements WebviewProvider ({ index: m.index, hunkHeader: m.hunkHeader })), { source: 'composer', correlationId: this.host.instanceId }, { cancellation: this._generateCommitsCancellation.token, @@ -942,9 +952,28 @@ export class ComposerWebviewProvider implements WebviewProvider params.commitHunkIndices.includes(h.index)), + ); + if (!patch) { + this._context.operations.generateCommitMessage.errorCount++; + this._context.errors.operation.count++; + // Send error notification for failure (not cancellation) + this.sendTelemetryEvent('composer/action/generateCommitMessage/failed', { + ...eventData, + 'failure.reason': 'error', + 'failure.error.message': 'Failed to create diff for commit', + }); + await this.host.notify(DidErrorAIOperationNotification, { + operation: 'generate commit message', + error: 'Failed to create diff for commit', + }); + } + // Call the AI service to generate commit message const result = await this.container.ai.generateCommitMessage( - params.diff, + patch, { source: 'composer', correlationId: this.host.instanceId }, { cancellation: this._generateCommitMessageCancellation.token, @@ -1032,7 +1061,7 @@ export class ComposerWebviewProvider implements WebviewProvider + const commitHunkIndices = params.commits.flatMap(c => c.hunkIndices); + const hunks: ComposerHunk[] = []; + for (const hunk of commitHunkIndices) { + hunks.push({ ...this._hunks.find(m => m.index === hunk)!, assigned: true }); + } + + const hunksBeingCommitted = hunks.filter(hunk => params.commits.some(c => c.hunkIndices.includes(hunk.index)), ); // Validate repository safety state before proceeding - const validation = await validateSafetyState(repo, params.safetyState, hunksBeingCommitted); + const validation = await validateSafetyState(repo, this._safetyState, hunksBeingCommitted); if (!validation.isValid) { // Clear loading state and show safety error await this.host.notify(DidFinishCommittingNotification, undefined); @@ -1073,8 +1107,7 @@ export class ComposerWebviewProvider implements WebviewProvider = { hunks: [], commits: [], - hunkMap: [], baseCommit: { sha: '', message: '', repoName: '', branchName: '', }, - safetyState: { - repoPath: '', - headSha: '', - hashes: { - staged: null, - unstaged: null, - unified: null, - }, - }, selectedCommitId: null, selectedCommitIds: new Set(), selectedUnassignedSection: null, @@ -404,7 +390,6 @@ export const OnRedoCommand = new IpcCommand(ipcScope, 'onRedo'); export const OnResetCommand = new IpcCommand(ipcScope, 'onReset'); // Notifications sent from host to webview -export const DidChangeNotification = new IpcNotification(ipcScope, 'didChange'); export const DidStartGeneratingNotification = new IpcNotification(ipcScope, 'didStartGenerating'); export const DidStartGeneratingCommitMessageNotification = new IpcNotification<{ commitId: string }>( ipcScope, @@ -450,9 +435,8 @@ export const DidChangeAiModelNotification = new IpcNotification commit.hunkIndices.includes(hunk.index)); @@ -82,22 +82,17 @@ export function getFileChanges(hunks: ComposerHunk[]): { additions: number; dele ); } -export function createCombinedDiffForCommit( - commit: ComposerCommit, - hunks: ComposerHunk[], -): { patch: string; filePatches: Map } { - // Get hunks for this commit - const commitHunks = commit.hunkIndices - .map(index => hunks.find(hunk => hunk.index === index)) - .filter((hunk): hunk is ComposerHunk => hunk !== undefined); - - if (commitHunks.length === 0) { +export function createCombinedDiffForCommit(hunks: ComposerHunk[]): { + patch: string; + filePatches: Map; +} { + if (hunks.length === 0) { return { patch: '', filePatches: new Map() }; } // Group hunks by file (diffHeader) const filePatches = new Map(); - for (const hunk of commitHunks) { + for (const hunk of hunks) { const diffHeader = hunk.diffHeader || `diff --git a/${hunk.fileName} b/${hunk.fileName}`; let array = filePatches.get(diffHeader); @@ -137,7 +132,7 @@ export function convertToComposerDiffInfo( hunks: ComposerHunk[], ): Array<{ message: string; explanation?: string; filePatches: Map; patch: string }> { return commits.map(commit => { - const { patch, filePatches } = createCombinedDiffForCommit(commit, hunks); + const { patch, filePatches } = createCombinedDiffForCommit(getHunksForCommit(commit, hunks)); return { message: commit.message, @@ -174,34 +169,27 @@ export function generateComposerMarkdown( return markdown; } -export function createHunksFromDiffs( - stagedDiffContent?: string, - unstagedDiffContent?: string, -): { hunkMap: ComposerHunkMap[]; hunks: ComposerHunk[] } { - const allHunkMaps: ComposerHunkMap[] = []; +export function createHunksFromDiffs(stagedDiffContent?: string, unstagedDiffContent?: string): ComposerHunk[] { const allHunks: ComposerHunk[] = []; let count = 0; - let hunkMap: ComposerHunkMap[] = []; let hunks: ComposerHunk[] = []; if (stagedDiffContent) { const stagedDiff = parseGitDiff(stagedDiffContent); - ({ hunkMap, hunks, count } = convertDiffToComposerHunks(stagedDiff, 'staged', count)); + ({ hunks, count } = convertDiffToComposerHunks(stagedDiff, 'staged', count)); - allHunkMaps.push(...hunkMap); allHunks.push(...hunks); } if (unstagedDiffContent) { const unstagedDiff = parseGitDiff(unstagedDiffContent); - ({ hunkMap, hunks, count } = convertDiffToComposerHunks(unstagedDiff, 'unstaged', count)); + ({ hunks, count } = convertDiffToComposerHunks(unstagedDiff, 'unstaged', count)); - allHunkMaps.push(...hunkMap); allHunks.push(...hunks); } - return { hunkMap: allHunkMaps, hunks: allHunks }; + return allHunks; } /** Converts @type {ParsedGitDiff} output to @type {ComposerHunk}'s */ @@ -209,8 +197,7 @@ function convertDiffToComposerHunks( diff: ParsedGitDiff, source: 'staged' | 'unstaged', startingCount: number, -): { hunkMap: ComposerHunkMap[]; hunks: ComposerHunk[]; count: number } { - const hunkMap: ComposerHunkMap[] = []; +): { hunks: ComposerHunk[]; count: number } { const hunks: ComposerHunk[] = []; let counter = startingCount; @@ -238,8 +225,6 @@ function convertDiffToComposerHunks( content = file.header.split('\n').slice(1).join('\n'); // Skip the diff --git line } - hunkMap.push({ index: hunkIndex, hunkHeader: hunkHeader }); - const composerHunk: ComposerHunk = { index: hunkIndex, fileName: file.path, @@ -260,8 +245,6 @@ function convertDiffToComposerHunks( for (const hunk of file.hunks) { const hunkIndex = ++counter; - hunkMap.push({ index: hunkIndex, hunkHeader: hunk.header }); - // Calculate additions and deletions from the hunk content const { additions, deletions } = calculateHunkStats(hunk.content); @@ -284,7 +267,7 @@ function convertDiffToComposerHunks( } } - return { hunkMap: hunkMap, hunks: hunks, count: counter }; + return { hunks: hunks, count: counter }; } function calculateHunkStats(content: string): { additions: number; deletions: number } { From e0c8a9c92ffedeb6cbbfbbaeca406c50f12665fc Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:41:15 -0700 Subject: [PATCH 10/83] Improves MCP checks and adds offline check (#4687) --- src/container.ts | 6 +++ src/env/browser/platform.ts | 1 + src/env/node/gk/cli/integration.ts | 51 ++++++++++++++++++------- src/env/node/platform.ts | 3 +- src/extension.ts | 1 + src/plus/gk/utils/-webview/mcp.utils.ts | 4 +- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/container.ts b/src/container.ts index 9df704e5d432d..2d0a6560682b8 100644 --- a/src/container.ts +++ b/src/container.ts @@ -190,6 +190,7 @@ export class Container { this._context = context; this._prerelease = prerelease; this._version = version; + this._previousVersion = previousVersion; this.ensureModeApplied(); this._disposables = [ @@ -747,6 +748,11 @@ export class Container { return this._version; } + private readonly _previousVersion: string | undefined; + get previousVersion(): string | undefined { + return this._previousVersion; + } + private readonly _views: Views; get views(): Views { return this._views; diff --git a/src/env/browser/platform.ts b/src/env/browser/platform.ts index 0e5d8294f9596..ee5eecf0e520a 100644 --- a/src/env/browser/platform.ts +++ b/src/env/browser/platform.ts @@ -1,6 +1,7 @@ import type { Platform } from '../node/platform'; export const isWeb = true; +export const isOffline = false; const _platform = (navigator as any)?.userAgentData?.platform; const _userAgent = navigator.userAgent; diff --git a/src/env/node/gk/cli/integration.ts b/src/env/node/gk/cli/integration.ts index e67af6ceb770f..3b649c661614f 100644 --- a/src/env/node/gk/cli/integration.ts +++ b/src/env/node/gk/cli/integration.ts @@ -16,8 +16,8 @@ import { gate } from '../../../../system/decorators/gate'; import { debug, log } from '../../../../system/decorators/log'; import { Logger } from '../../../../system/logger'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; -import { compare } from '../../../../system/version'; -import { getPlatform, isWeb } from '../../platform'; +import { compare, fromString, satisfies } from '../../../../system/version'; +import { getPlatform, isOffline, isWeb } from '../../platform'; import { CliCommandHandlers } from './commands'; import type { IpcServer } from './ipcServer'; import { createIpcServer } from './ipcServer'; @@ -32,6 +32,7 @@ const enum CLIInstallErrorReason { ProxyFetch, GlobalStorageDirectory, CoreInstall, + Offline, } const enum McpSetupErrorReason { @@ -44,6 +45,7 @@ const enum McpSetupErrorReason { UnsupportedHost, UnsupportedClient, UnexpectedOutput, + Offline, } export interface CliCommandRequest { @@ -118,6 +120,15 @@ export class GkCliIntegrationProvider implements Disposable { return; } + // Reset the attempts count if GitLens extension version has changed + if ( + reachedMaxAttempts(cliInstall) && + this.container.version !== this.container.previousVersion && + satisfies(fromString(this.container.version), '>= 17.6') + ) { + void this.container.storage.store('gk:cli:install', undefined); + } + if (!mcpExtensionRegistrationAllowed() || reachedMaxAttempts(cliInstall)) { return; } @@ -164,6 +175,7 @@ export class GkCliIntegrationProvider implements Disposable { switch (ex.reason) { case McpSetupErrorReason.WebUnsupported: case McpSetupErrorReason.VSCodeVersionUnsupported: + case McpSetupErrorReason.Offline: void window.showWarningMessage(ex.message); break; case McpSetupErrorReason.InstallationFailed: @@ -383,6 +395,12 @@ export class GkCliIntegrationProvider implements Disposable { message = 'Unable to locally install the GitKraken MCP server. Please try again.'; telemetryReason = 'local installation failed'; break; + case CLIInstallErrorReason.Offline: + reason = McpSetupErrorReason.Offline; + message = + 'Unable to setup the GitKraken MCP server when offline. Please try again when you are online.'; + telemetryReason = 'offline'; + break; default: reason = McpSetupErrorReason.CLIUnknownError; message = 'Unable to setup the GitKraken MCP: Unknown error.'; @@ -446,6 +464,21 @@ export class GkCliIntegrationProvider implements Disposable { } try { + if (isWeb) { + void this.container.storage + .store('gk:cli:install', { + status: 'unsupported', + attempts: cliInstallAttempts, + }) + .catch(); + + throw new CLIInstallError(CLIInstallErrorReason.UnsupportedPlatform, undefined, 'web'); + } + + if (isOffline) { + throw new CLIInstallError(CLIInstallErrorReason.Offline); + } + cliInstallAttempts += 1; if (this.container.telemetry.enabled) { this.container.telemetry.sendEvent('cli/install/started', { @@ -461,17 +494,6 @@ export class GkCliIntegrationProvider implements Disposable { }) .catch(); - if (isWeb) { - void this.container.storage - .store('gk:cli:install', { - status: 'unsupported', - attempts: cliInstallAttempts, - }) - .catch(); - - throw new CLIInstallError(CLIInstallErrorReason.UnsupportedPlatform, undefined, 'web'); - } - // Map platform names for the API and get architecture let platformName: string; let architecture: string; @@ -797,6 +819,9 @@ class CLIInstallError extends Error { case CLIInstallErrorReason.GlobalStorageDirectory: message = 'Failed to create global storage directory'; break; + case CLIInstallErrorReason.Offline: + message = 'Offline'; + break; default: message = 'An unknown error occurred'; break; diff --git a/src/env/node/platform.ts b/src/env/node/platform.ts index a052589c3fb08..c6cde90778bb6 100644 --- a/src/env/node/platform.ts +++ b/src/env/node/platform.ts @@ -1,9 +1,10 @@ -import { tmpdir } from 'os'; +import { networkInterfaces, tmpdir } from 'os'; import { join } from 'path'; import { platform } from 'process'; import { env, UIKind } from 'vscode'; export const isWeb = env.uiKind === UIKind.Web; +export const isOffline = Object.values(networkInterfaces()).every(iface => iface?.every(addr => addr.internal)); export const isLinux = platform === 'linux'; export const isMac = platform === 'darwin'; diff --git a/src/extension.ts b/src/extension.ts index 06d3f1f03597c..862657333c9ce 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -395,6 +395,7 @@ async function showWhatsNew( function showMcp(version: string, previousVersion: string | undefined): void { if ( + isWeb || previousVersion == null || version === previousVersion || compare(version, previousVersion) !== 1 || diff --git a/src/plus/gk/utils/-webview/mcp.utils.ts b/src/plus/gk/utils/-webview/mcp.utils.ts index 06924e2ebc38f..24ec3cea441fc 100644 --- a/src/plus/gk/utils/-webview/mcp.utils.ts +++ b/src/plus/gk/utils/-webview/mcp.utils.ts @@ -1,5 +1,5 @@ import { env, lm, version } from 'vscode'; -import { isWeb } from '@env/platform'; +import { isOffline, isWeb } from '@env/platform'; import type { Container } from '../../../../container'; import { configuration } from '../../../../system/-webview/configuration'; import { satisfies } from '../../../../system/version'; @@ -15,7 +15,7 @@ export function isMcpBannerEnabled(container: Container, showAutoRegistration = const supportedApps = ['Visual Studio Code', 'Visual Studio Code - Insiders', 'Visual Studio Code - Exploration']; export function supportsMcpExtensionRegistration(): boolean { - if (isWeb || !supportedApps.includes(env.appName)) { + if (isWeb || isOffline || !supportedApps.includes(env.appName)) { return false; } From 181a393148d5f83705e33f088859e9981e458d84 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 15 Oct 2025 14:58:05 -0700 Subject: [PATCH 11/83] Removes unnecessary version check --- src/env/node/gk/cli/integration.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/env/node/gk/cli/integration.ts b/src/env/node/gk/cli/integration.ts index 3b649c661614f..c6da7054baf94 100644 --- a/src/env/node/gk/cli/integration.ts +++ b/src/env/node/gk/cli/integration.ts @@ -121,11 +121,7 @@ export class GkCliIntegrationProvider implements Disposable { } // Reset the attempts count if GitLens extension version has changed - if ( - reachedMaxAttempts(cliInstall) && - this.container.version !== this.container.previousVersion && - satisfies(fromString(this.container.version), '>= 17.6') - ) { + if (reachedMaxAttempts(cliInstall) && this.container.version !== this.container.previousVersion) { void this.container.storage.store('gk:cli:install', undefined); } From 64fa29bccf2179b77ce6b8ba3ba9c72a3be35c8c Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Wed, 15 Oct 2025 15:02:20 -0700 Subject: [PATCH 12/83] Allows commit reordering after composing (#4668) --- .../apps/plus/composer/components/app.ts | 36 ------------------- .../plus/composer/components/commits-panel.ts | 5 --- 2 files changed, 41 deletions(-) diff --git a/src/webviews/apps/plus/composer/components/app.ts b/src/webviews/apps/plus/composer/components/app.ts index 2ea6289ede40a..278a84a545c21 100644 --- a/src/webviews/apps/plus/composer/components/app.ts +++ b/src/webviews/apps/plus/composer/components/app.ts @@ -402,7 +402,6 @@ export class ComposerApp extends LitElement { @state() private onboardingStepNumber: number = 0; - private commitsSortable?: Sortable; private hunksSortable?: Sortable; private isDragging = false; private lastMouseEvent?: MouseEvent; @@ -460,7 +459,6 @@ export class ComposerApp extends LitElement { override disconnectedCallback() { super.disconnectedCallback?.(); - this.commitsSortable?.destroy(); this.hunksSortable?.destroy(); if (this.commitMessageDebounceTimer) { clearTimeout(this.commitMessageDebounceTimer); @@ -470,33 +468,6 @@ export class ComposerApp extends LitElement { } private initializeSortable() { - // Initialize commits sortable - const commitsContainer = this.shadowRoot?.querySelector('.commits-list'); - if (commitsContainer) { - this.commitsSortable = Sortable.create(commitsContainer as HTMLElement, { - animation: 150, - ghostClass: 'sortable-ghost', - chosenClass: 'sortable-chosen', - dragClass: 'sortable-drag', - handle: '.drag-handle', // Only allow dragging by the handle - filter: '.new-commit-drop-zone', - onMove: evt => { - // Only allow moving within the commits list, not into drop zones - const target = evt.related; - return ( - target.tagName.toLowerCase() === 'gl-commit-item' && - !target.closest('.drop-zone') && - !target.closest('.new-commit-drop-zone') - ); - }, - onEnd: evt => { - if (evt.oldIndex !== undefined && evt.newIndex !== undefined && evt.oldIndex !== evt.newIndex) { - this.reorderCommits(evt.oldIndex, evt.newIndex); - } - }, - }); - } - // Initialize hunks sortable (will be re-initialized when commit is selected) this.initializeHunksSortable(); @@ -742,8 +713,6 @@ export class ComposerApp extends LitElement { } private reorderCommits(oldIndex: number, newIndex: number) { - if (!this.canReorderCommits) return; - this.saveToHistory(); const newCommits = [...this.state.commits]; @@ -1214,10 +1183,6 @@ export class ComposerApp extends LitElement { return this.state?.mode === 'preview'; } - private get canReorderCommits(): boolean { - return !this.isPreviewMode; - } - private get canCombineCommits(): boolean { return !this.isPreviewMode; } @@ -1612,7 +1577,6 @@ export class ComposerApp extends LitElement { .committing=${this.state.committing} .aiEnabled=${this.aiEnabled} .aiDisabledReason=${this.aiDisabledReason} - .canReorderCommits=${this.canReorderCommits} .canCombineCommits=${this.canCombineCommits} .canMoveHunks=${this.canMoveHunks} .canGenerateCommitsWithAI=${this.canGenerateCommitsWithAI} diff --git a/src/webviews/apps/plus/composer/components/commits-panel.ts b/src/webviews/apps/plus/composer/components/commits-panel.ts index 965610755e85e..0a24f305dd683 100644 --- a/src/webviews/apps/plus/composer/components/commits-panel.ts +++ b/src/webviews/apps/plus/composer/components/commits-panel.ts @@ -435,11 +435,6 @@ export class CommitsPanel extends LitElement { } private initializeSortable() { - // Don't initialize sortable in AI preview mode - if (this.isPreviewMode) { - return; - } - const commitsContainer = this.shadowRoot?.querySelector('.commits-only'); if (commitsContainer) { this.commitsSortable = Sortable.create(commitsContainer as HTMLElement, { From dc55ccf8d83ed1c47e9e70095862d6db769d37f6 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 15 Oct 2025 15:22:08 -0700 Subject: [PATCH 13/83] Removes unused imports --- src/env/node/gk/cli/integration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env/node/gk/cli/integration.ts b/src/env/node/gk/cli/integration.ts index c6da7054baf94..1b71a867b8d1c 100644 --- a/src/env/node/gk/cli/integration.ts +++ b/src/env/node/gk/cli/integration.ts @@ -16,7 +16,7 @@ import { gate } from '../../../../system/decorators/gate'; import { debug, log } from '../../../../system/decorators/log'; import { Logger } from '../../../../system/logger'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; -import { compare, fromString, satisfies } from '../../../../system/version'; +import { compare } from '../../../../system/version'; import { getPlatform, isOffline, isWeb } from '../../platform'; import { CliCommandHandlers } from './commands'; import type { IpcServer } from './ipcServer'; From 7e56eef7c58df681d440cc75aae6344693d35e12 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 15 Oct 2025 18:26:05 -0400 Subject: [PATCH 14/83] Updates VS Code to 1.95 Resolves #4690 --- CHANGELOG.md | 4 ++++ package.json | 6 +++--- pnpm-lock.yaml | 12 ++++++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25830b45f352c..c58b539bd70af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Changed + +- Changes the minimum VS Code version to 1.95.0 ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) + ### Fixed - Fixes MCP extension registration not working on Kiro ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) diff --git a/package.json b/package.json index f4d883efcff20..687527d010883 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "engines": { "node": ">= 22.12.0", "pnpm": ">= 10.0.0", - "vscode": "^1.92.0" + "vscode": "^1.95.0" }, "license": "SEE LICENSE IN LICENSE", "publisher": "eamodio", @@ -25099,7 +25099,7 @@ "@types/sinon": "17.0.4", "@types/slug": "5.0.9", "@types/sortablejs": "1.15.8", - "@types/vscode": "1.92.0", + "@types/vscode": "1.95.0", "@typescript-eslint/parser": "8.45.0", "@vscode/test-cli": "0.0.11", "@vscode/test-electron": "2.5.2", @@ -25154,7 +25154,7 @@ "webpack-require-from": "1.8.6" }, "resolutions": { - "@types/vscode": "1.92.0", + "@types/vscode": "1.95.0", "esbuild": "0.25.10", "https-proxy-agent": "5.0.1", "iconv-lite": "0.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86c22d1c365a1..cd76efd3ba387 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@types/vscode': 1.92.0 + '@types/vscode': 1.95.0 esbuild: 0.25.10 https-proxy-agent: 5.0.1 iconv-lite: 0.6.3 @@ -170,8 +170,8 @@ importers: specifier: 1.15.8 version: 1.15.8 '@types/vscode': - specifier: 1.92.0 - version: 1.92.0 + specifier: 1.95.0 + version: 1.95.0 '@typescript-eslint/parser': specifier: 8.45.0 version: 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) @@ -1637,8 +1637,8 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/vscode@1.92.0': - resolution: {integrity: sha512-DcZoCj17RXlzB4XJ7IfKdPTcTGDLYvTOcTNkvtjXWF+K2TlKzHHkBEXNWQRpBIXixNEUgx39cQeTFunY0E2msw==} + '@types/vscode@1.95.0': + resolution: {integrity: sha512-0LBD8TEiNbet3NvWsmn59zLzOFu/txSlGxnv5yAFHCrhG9WvAnR3IvfHzMOs2aeWqgvNjq9pO99IUw8d3n+unw==} '@types/warning@3.0.3': resolution: {integrity: sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==} @@ -7515,7 +7515,7 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@types/vscode@1.92.0': {} + '@types/vscode@1.95.0': {} '@types/warning@3.0.3': {} From dc45bd86faca64f01a370f39d23d0f415d18a98a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Oct 2025 18:34:49 -0400 Subject: [PATCH 15/83] Fixes #4692 differs cache keys for autolink refs - Ensures that filtered autolink refs aren't cached --- src/autolinks/autolinksProvider.ts | 52 ++++++++++++------------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/autolinks/autolinksProvider.ts b/src/autolinks/autolinksProvider.ts index 547a03bb5c84d..1222ed2cb56ab 100644 --- a/src/autolinks/autolinksProvider.ts +++ b/src/autolinks/autolinksProvider.ts @@ -120,7 +120,7 @@ export class AutolinksProvider implements Disposable { } } - if (promises.length === 0) return; + if (!promises.length) return; await Promise.allSettled(promises); } @@ -144,7 +144,7 @@ export class AutolinksProvider implements Disposable { } private async getRefSets(remote?: GitRemote, forBranch?: boolean) { - return this._refsetCache.get(remote?.remoteKey, async () => { + return this._refsetCache.get(`${remote?.remoteKey}${forBranch ? ':branch' : ''}`, async () => { const refsets: RefSet[] = []; await this.collectIntegrationAutolinks(forBranch ? undefined : remote, refsets); @@ -158,29 +158,21 @@ export class AutolinksProvider implements Disposable { /** @returns A sorted list of autolinks. the first match is the most relevant */ async getBranchAutolinks(branchName: string, remote?: GitRemote): Promise> { const refsets = await this.getRefSets(remote, true); - if (refsets.length === 0) return emptyAutolinkMap; + if (!refsets.length) return emptyAutolinkMap; return getBranchAutolinks(branchName, refsets); } - @debug({ - args: { - 0: '', - 1: false, - }, - }) + @debug({ args: { 0: '', 1: false } }) async getAutolinks(message: string, remote?: GitRemote): Promise> { const refsets = await this.getRefSets(remote); - if (refsets.length === 0) return emptyAutolinkMap; + if (!refsets.length) return emptyAutolinkMap; return getAutolinks(message, refsets); } getAutolinkEnrichableId(autolink: Autolink): { id: string; key: string } { - return { - id: autolink.id, - key: `${autolink.prefix}${autolink.id}`, - }; + return { id: autolink.id, key: `${autolink.prefix}${autolink.id}` }; } async getEnrichedAutolinks( @@ -205,7 +197,7 @@ export class AutolinksProvider implements Disposable { if (typeof messageOrAutolinks === 'string') { messageOrAutolinks = await this.getAutolinks(messageOrAutolinks, remote); } - if (messageOrAutolinks.size === 0) return undefined; + if (!messageOrAutolinks.size) return undefined; let integration = await remote?.getIntegration(); if (integration != null) { @@ -339,7 +331,7 @@ export class AutolinksProvider implements Disposable { } } - if (tokenMapping.size !== 0) { + if (tokenMapping.size) { // eslint-disable-next-line no-control-regex text = text.replace(/(\x00\d+\x00)/g, (_, t: string) => tokenMapping.get(t) ?? t); } @@ -388,10 +380,9 @@ export class AutolinksProvider implements Disposable { if (issueResult?.value != null) { if (issueResult.paused) { if (footnotes != null && !prs?.has(num)) { - let name = ref.description?.replace(numRegex, num); - if (name == null) { - name = `Custom Autolink ${ref.prefix}${num}`; - } + const name = + ref.description?.replace(numRegex, num) ?? + `Custom Autolink ${ref.prefix}${num}`; footnoteIndex = footnotes.size + 1; footnotes.set( footnoteIndex, @@ -426,10 +417,9 @@ export class AutolinksProvider implements Disposable { )}`; } } else if (footnotes != null && !prs?.has(num)) { - let name = ref.description?.replace(numRegex, num); - if (name == null) { - name = `Custom Autolink ${ref.prefix}${num}`; - } + const name = + ref.description?.replace(numRegex, num) ?? + `Custom Autolink ${ref.prefix}${num}`; footnoteIndex = footnotes.size + 1; footnotes.set( footnoteIndex, @@ -460,10 +450,9 @@ export class AutolinksProvider implements Disposable { if (issueResult?.value != null) { if (issueResult.paused) { if (footnotes != null && !prs?.has(num)) { - let name = ref.description?.replace(numRegex, num); - if (name == null) { - name = `Custom Autolink ${ref.prefix}${num}`; - } + const name = + ref.description?.replace(numRegex, num) ?? + `Custom Autolink ${ref.prefix}${num}`; footnoteIndex = footnotes.size + 1; footnotes.set( footnoteIndex, @@ -498,10 +487,9 @@ export class AutolinksProvider implements Disposable { )}`; } } else if (footnotes != null && !prs?.has(num)) { - let name = ref.description?.replace(numRegex, num); - if (name == null) { - name = `Custom Autolink ${ref.prefix}${num}`; - } + const name = + ref.description?.replace(numRegex, num) ?? + `Custom Autolink ${ref.prefix}${num}`; footnoteIndex = footnotes.size + 1; footnotes.set( footnoteIndex, From 0631ff0e424fb0f1d4aed69abd9dae8bfefd489c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Oct 2025 18:44:36 -0400 Subject: [PATCH 16/83] Fixes missing file from webview lint config --- eslint.config.mjs | 2 ++ src/webviews/apps/tsconfig.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index cf6fa2f1dfb82..25c64bc949b90 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -30,6 +30,7 @@ const filePatterns = { webviewsApps: ['src/webviews/apps/**/*'], webviewsShared: [ // Keep in sync with `src/webviews/apps/tsconfig.json` + 'src/webviews/plus/composer/utils.ts', 'src/webviews/**/protocol.ts', 'src/**/models/**/*.ts', 'src/**/utils/**/*.ts', @@ -39,6 +40,7 @@ const filePatterns = { 'src/constants.*.ts', 'src/env/browser/**/*', 'src/features.ts', + 'src/git/parsers/diffParser.ts', 'src/system/**/*.ts', '**/webview/**/*', ], diff --git a/src/webviews/apps/tsconfig.json b/src/webviews/apps/tsconfig.json index 3844c9cad6bba..44a5622dd6347 100644 --- a/src/webviews/apps/tsconfig.json +++ b/src/webviews/apps/tsconfig.json @@ -12,6 +12,7 @@ // Keep in sync with `src/eslint.config.mjs` "include": [ "**/*", + "../plus/composer/utils.ts", "../**/protocol.ts", "../../**/models/**/*.ts", "../../**/utils/**/*.ts", @@ -23,8 +24,7 @@ "../../features.ts", "../../git/parsers/diffParser.ts", "../../system/**/*.ts", - "../../**/webview/**/*", - "../plus/composer/utils.ts" + "../../**/webview/**/*" ], "exclude": ["src/**/__tests__/**/*", "src/**/-webview/**/*"] } From 4e8e600e4236129a5b435753363ac829ce4afb62 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 14 Oct 2025 22:56:57 -0400 Subject: [PATCH 17/83] Adds better logging to webview IPC - Extracts `IpcPromise` into dedicated IPC module - Nests `IpcPromise` props under a `value` property (future-proofing) - Renames `IpcCall` `packed` to `compressed` (future-proofing) - Moves `UriComponents` to shared system module for future use --- eslint.config.mjs | 1 + src/git/gitUri.ts | 11 +---- src/system/logger.scope.ts | 13 +++++- src/system/serialize.ts | 2 +- src/system/uri.ts | 8 ++++ src/webviews/apps/shared/appHost.ts | 3 ++ src/webviews/apps/shared/ipc.ts | 31 +++++++++----- src/webviews/apps/tsconfig.json | 1 + src/webviews/ipc.ts | 19 +++++++++ src/webviews/plus/graph/protocol.ts | 4 +- src/webviews/protocol.ts | 40 +++++++----------- src/webviews/rebase/rebaseEditor.ts | 2 + src/webviews/webviewController.ts | 64 +++++++++++++++++------------ 13 files changed, 122 insertions(+), 77 deletions(-) create mode 100644 src/webviews/ipc.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 25c64bc949b90..ab189f29a1752 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -30,6 +30,7 @@ const filePatterns = { webviewsApps: ['src/webviews/apps/**/*'], webviewsShared: [ // Keep in sync with `src/webviews/apps/tsconfig.json` + 'src/webviews/ipc.ts', 'src/webviews/plus/composer/utils.ts', 'src/webviews/**/protocol.ts', 'src/**/models/**/*.ts', diff --git a/src/git/gitUri.ts b/src/git/gitUri.ts index ff1eb30022017..5ba97bfb56081 100644 --- a/src/git/gitUri.ts +++ b/src/git/gitUri.ts @@ -9,6 +9,7 @@ import { isVirtualUri } from '../system/-webview/vscode/uris'; import { debug } from '../system/decorators/log'; import { memoize } from '../system/decorators/memoize'; import { basename, normalizePath } from '../system/path'; +import type { UriComponents } from '../system/uri'; import { areUrisEqual } from '../system/uri'; import type { RevisionUriData } from './gitProvider'; import { decodeGitLensRevisionUriAuthority, decodeRemoteHubAuthority } from './gitUri.authority'; @@ -24,20 +25,12 @@ export interface GitCommitish { sha?: string; } -interface UriComponents { - scheme?: string; - authority?: string; - path?: string; - query?: string; - fragment?: string; -} - interface UriEx { new (): Uri; new (scheme: string, authority: string, path: string, query: string, fragment: string): Uri; // Use this ctor, because vscode doesn't validate it // eslint-disable-next-line @typescript-eslint/unified-signatures - new (components: UriComponents): Uri; + new (components: Partial): Uri; } export class GitUri extends (Uri as any as UriEx) { diff --git a/src/system/logger.scope.ts b/src/system/logger.scope.ts index c4a13e958332f..986eb3dffc45f 100644 --- a/src/system/logger.scope.ts +++ b/src/system/logger.scope.ts @@ -68,8 +68,17 @@ export function setLogScope(scopeId: number, scope: LogScope): LogScope { export function setLogScopeExit(scope: LogScope | undefined, details: string | undefined, failed?: string): void { if (scope == null) return; - scope.exitDetails = details; + if (scope.exitDetails != null && details != null) { + scope.exitDetails += details; + } else { + scope.exitDetails = details; + } + if (failed != null) { - scope.exitFailed = failed; + if (scope.exitFailed != null) { + scope.exitFailed += failed; + } else { + scope.exitFailed = failed; + } } } diff --git a/src/system/serialize.ts b/src/system/serialize.ts index 7697d2a4cba58..334d11a0e329c 100644 --- a/src/system/serialize.ts +++ b/src/system/serialize.ts @@ -6,7 +6,7 @@ import type { Branded } from './brand'; // prettier-ignore export type Serialized = // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - T extends Function | Error | Container + T extends Error |Function | Container ? never : T extends Date ? TDate diff --git a/src/system/uri.ts b/src/system/uri.ts index 4de5693c4897c..2b6ed785d9e94 100644 --- a/src/system/uri.ts +++ b/src/system/uri.ts @@ -1,5 +1,13 @@ import type { Uri } from 'vscode'; +export interface UriComponents { + scheme: string; + authority: string; + path: string; + query: string; + fragment: string; +} + export function areUrisEqual(a: Uri | undefined, b: Uri | undefined): boolean { if (a === b) return true; if (a == null || b == null) return false; diff --git a/src/webviews/apps/shared/appHost.ts b/src/webviews/apps/shared/appHost.ts index 07e3121be0d1c..67afba8676ab9 100644 --- a/src/webviews/apps/shared/appHost.ts +++ b/src/webviews/apps/shared/appHost.ts @@ -87,6 +87,9 @@ export abstract class GlAppHost< const state: State = JSON.parse(fromBase64ToString(this.bootstrap)); this.bootstrap = undefined!; this._ipc.replaceIpcPromisesWithPromises(state); + + this._logger.log(`bootstrap duration=${Date.now() - state.timestamp}ms`); + this.onPersistState?.(state); const themeEvent = computeThemeColors(); diff --git a/src/webviews/apps/shared/ipc.ts b/src/webviews/apps/shared/ipc.ts index 93cf1051086cd..bf88e0157e394 100644 --- a/src/webviews/apps/shared/ipc.ts +++ b/src/webviews/apps/shared/ipc.ts @@ -2,11 +2,12 @@ import { getScopedCounter } from '../../../system/counter'; import { debug, logName } from '../../../system/decorators/log'; import { Logger } from '../../../system/logger'; -import { getLogScope, getNewLogScope } from '../../../system/logger.scope'; +import { getLogScope, getNewLogScope, setLogScopeExit } from '../../../system/logger.scope'; import type { Serialized } from '../../../system/serialize'; import { maybeStopWatch } from '../../../system/stopwatch'; +import { isIpcPromise } from '../../ipc'; import type { IpcCallParamsType, IpcCallResponseParamsType, IpcCommand, IpcMessage, IpcRequest } from '../../protocol'; -import { ipcPromiseSettled, isIpcPromise } from '../../protocol'; +import { IpcPromiseSettled } from '../../protocol'; import { DOM } from './dom'; import type { Disposable, Event } from './events'; import { Emitter } from './events'; @@ -52,22 +53,26 @@ export class HostIpc implements Disposable { this._disposable.dispose(); } - @debug({ args: { 0: e => `${e.data.id}, method=${e.data.method}` } }) + @debug({ args: { 0: e => `${e.data.id}|${e.data.method}` } }) private onMessageReceived(e: MessageEvent) { const scope = getLogScope(); const msg = e.data as IpcMessage; - if (msg.packed && msg.params instanceof Uint8Array) { - const sw = maybeStopWatch(getNewLogScope(` deserializing msg=${e.data.method}`, scope), { - log: false, - logLevel: 'debug', - }); + const sw = maybeStopWatch(getNewLogScope(`(e=${msg.id}|${msg.method})`, scope), { + log: false, + logLevel: 'debug', + }); + + if (msg.compressed && msg.params instanceof Uint8Array) { this._textDecoder ??= new TextDecoder(); msg.params = JSON.parse(this._textDecoder.decode(msg.params)); - sw?.stop(); + sw?.restart({ message: `\u2022 decoded (${msg.compressed}) serialized params` }); } this.replaceIpcPromisesWithPromises(msg.params); + sw?.stop({ message: `\u2022 replaced ipc tagged types with params` }); + + setLogScopeExit(scope, ` \u2022 ipc (host -> webview) duration=${Date.now() - msg.timestamp}ms`); // If we have a completionId, then this is a response to a request and it should be handled directly if (msg.completionId != null) { @@ -86,7 +91,7 @@ export class HostIpc implements Disposable { for (const key in data) { const value = (data as Record)[key]; if (isIpcPromise(value)) { - (data as Record)[key] = this.getResponsePromise(value.method, value.id); + (data as Record)[key] = this.getResponsePromise(value.value.method, value.value.id); } else { this.replaceIpcPromisesWithPromises(value); } @@ -105,6 +110,8 @@ export class HostIpc implements Disposable { scope: commandType.scope, method: commandType.method, params: params, + compressed: false, + timestamp: Date.now(), } satisfies IpcMessage>); } @@ -122,6 +129,8 @@ export class HostIpc implements Disposable { scope: requestType.scope, method: requestType.method, params: params, + compressed: false, + timestamp: Date.now(), completionId: id, } satisfies IpcMessage>); return promise; @@ -150,7 +159,7 @@ export class HostIpc implements Disposable { this._pendingHandlers.set(queueKey, msg => { dispose.call(this); - if (msg.method === ipcPromiseSettled.method) { + if (msg.method === IpcPromiseSettled.method) { const params = msg.params as PromiseSettledResult; if (params.status === 'rejected') { queueMicrotask(() => reject(new Error(params.reason))); diff --git a/src/webviews/apps/tsconfig.json b/src/webviews/apps/tsconfig.json index 44a5622dd6347..70032ab64d9e9 100644 --- a/src/webviews/apps/tsconfig.json +++ b/src/webviews/apps/tsconfig.json @@ -12,6 +12,7 @@ // Keep in sync with `src/eslint.config.mjs` "include": [ "**/*", + "../ipc.ts", "../plus/composer/utils.ts", "../**/protocol.ts", "../../**/models/**/*.ts", diff --git a/src/webviews/ipc.ts b/src/webviews/ipc.ts new file mode 100644 index 0000000000000..52c69e61dac79 --- /dev/null +++ b/src/webviews/ipc.ts @@ -0,0 +1,19 @@ +/** Tagged type for Promises that get resolved asynchronously over IPC */ +export interface IpcPromise { + __ipc: 'promise'; + value: { + id: string; + method: string; + }; + __promise: Promise; +} + +export function isIpcPromise(value: unknown): value is IpcPromise { + return ( + typeof value === 'object' && + value != null && + (value as IpcPromise).__ipc === 'promise' && + typeof (value as IpcPromise).value.id === 'string' && + typeof (value as IpcPromise).value.method === 'string' + ); +} diff --git a/src/webviews/plus/graph/protocol.ts b/src/webviews/plus/graph/protocol.ts index 75841fa5d14da..1ced0b0d3ecff 100644 --- a/src/webviews/plus/graph/protocol.ts +++ b/src/webviews/plus/graph/protocol.ts @@ -383,7 +383,7 @@ export const DidChangeRepoConnectionNotification = new IpcNotification(scope, 'didChange', true, true); +export const DidChangeNotification = new IpcNotification(scope, 'didChange', true, 'utf8'); export interface DidChangeGraphConfigurationParams { config: GraphComponentConfig; @@ -471,7 +471,7 @@ export const DidChangeRowsNotification = new IpcNotification { id: string; scope: IpcScope; method: string; - packed?: boolean; params: T; + compressed: IpcCompression; + timestamp: number; + completionId?: string; } @@ -31,7 +34,7 @@ abstract class IpcCall { public readonly scope: IpcScope, method: string, public readonly reset: boolean = false, - public readonly pack: boolean = false, + public readonly compressed: IpcCompression = false, ) { this.method = `${scope}/${method}`; } @@ -58,10 +61,15 @@ export class IpcCommand extends IpcCall {} export class IpcRequest extends IpcCall { public readonly response: IpcNotification; - constructor(scope: IpcScope, method: string, reset?: boolean, pack?: boolean) { - super(scope, method, reset, pack); + constructor(scope: IpcScope, method: string, reset?: boolean, compressed?: IpcCompression) { + super(scope, method, reset, compressed); - this.response = new IpcNotification(this.scope, `${method}/completion`, this.reset, this.pack); + this.response = new IpcNotification( + this.scope, + `${method}/completion`, + this.reset, + this.compressed, + ); } } @@ -119,27 +127,7 @@ export const TelemetrySendEventCommand = new IpcCommand; - id: string; - method: string; -} - -export function isIpcPromise(value: unknown): value is IpcPromise { - return ( - value != null && - typeof value === 'object' && - '__ipc' in value && - value.__ipc === 'promise' && - 'id' in value && - typeof value.id === 'string' && - 'method' in value && - typeof value.method === 'string' - ); -} - -export const ipcPromiseSettled = new IpcNotification>('core', 'ipc/promise/settled'); +export const IpcPromiseSettled = new IpcNotification>('core', 'ipc/promise/settled'); export interface DidChangeHostWindowFocusParams { focused: boolean; diff --git a/src/webviews/rebase/rebaseEditor.ts b/src/webviews/rebase/rebaseEditor.ts index 56c9e12c1747c..3768ab35b0c32 100644 --- a/src/webviews/rebase/rebaseEditor.ts +++ b/src/webviews/rebase/rebaseEditor.ts @@ -513,6 +513,8 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl scope: DidChangeNotification.scope, method: DidChangeNotification.method, params: { state: state }, + compressed: false, + timestamp: Date.now(), }); } diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index d0cba656ebb8f..3b4a6ba991d61 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -19,13 +19,14 @@ import { getLogScope, getNewLogScope, setLogScopeExit } from '../system/logger.s import { pauseOnCancelOrTimeout } from '../system/promise'; import { maybeStopWatch, Stopwatch } from '../system/stopwatch'; import type { WebviewContext } from '../system/webview'; +import type { IpcPromise } from './ipc'; +import { isIpcPromise } from './ipc'; import type { IpcCallMessageType, IpcCallParamsType, IpcCallResponseParamsType, IpcMessage, IpcNotification, - IpcPromise, IpcRequest, WebviewFocusChangedParams, WebviewState, @@ -36,8 +37,7 @@ import { DidChangeWebviewFocusNotification, DidChangeWebviewVisibilityNotification, ExecuteCommand, - ipcPromiseSettled, - isIpcPromise, + IpcPromiseSettled, TelemetrySendEventCommand, WebviewFocusChangedCommand, WebviewReadyCommand, @@ -479,6 +479,9 @@ export class WebviewController< private async onMessageReceivedCore(e: IpcMessage) { if (e == null) return; + const scope = getLogScope(); + setLogScopeExit(scope, ` \u2022 ipc (webview -> host) duration=${Date.now() - e.timestamp}ms`); + switch (true) { case WebviewReadyCommand.is(e): this._ready = true; @@ -606,7 +609,10 @@ export class WebviewController< return this._webRootUri; } + @debug({ args: false }) private async getHtml(webview: Webview): Promise { + const scope = getLogScope(); + const webRootUri = this.getWebRootUri(); const uri = Uri.joinPath(webRootUri, this.descriptor.fileName); @@ -618,7 +624,9 @@ export class WebviewController< this.provider.includeEndOfBody?.(), ]); + const sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); this.replacePromisesWithIpcPromises(bootstrap); + sw?.stop({ message: `\u2022 replaced tagged ipc types in bootstrap` }); const html = replaceWebviewHtmlTokens( utf8TextDecoder.decode(bytes), @@ -646,34 +654,37 @@ export class WebviewController< params: IpcCallParamsType, completionId?: string, ): Promise { + const id = this.nextIpcId(); + const timestamp = Date.now(); + + const scope = getNewLogScope(`${getLoggableName(this)}.notify(${id}|${notificationType.method})`, true); + const sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); + this.replacePromisesWithIpcPromises(params); - let packed; - if (notificationType.pack && params != null) { - const sw = maybeStopWatch( - getNewLogScope(`${getLoggableName(this)}.notify serializing msg=${notificationType.method}`, true), - { - log: false, - logLevel: 'debug', - }, - ); - packed = utf8TextEncoder.encode(JSON.stringify(params)); - sw?.stop(); + sw?.restart({ message: `\u2022 replaced tagged ipc types in params` }); + + let bytes: Uint8Array | undefined; + let compression: IpcMessage['compressed'] = false; + if (notificationType.compressed && params != null) { + bytes = utf8TextEncoder.encode(JSON.stringify(params)); + compression = 'utf8'; } const msg: IpcMessage | Uint8Array> = { - id: this.nextIpcId(), + id: id, scope: notificationType.scope, method: notificationType.method, - params: packed ?? params, - packed: packed != null, + params: bytes ?? params, + compressed: compression, + timestamp: timestamp, completionId: completionId, }; const success = await this.postMessage(msg); if (success) { this._pendingIpcNotifications.clear(); - } else if (notificationType === ipcPromiseSettled) { + } else if (notificationType === IpcPromiseSettled) { this._pendingIpcPromiseNotifications.add({ msg: msg, timestamp: Date.now() }); } else { this.addPendingIpcNotificationCore(notificationType, msg); @@ -703,14 +714,14 @@ export class WebviewController< debugger; return; } - return this.notify(ipcPromiseSettled, { status: 'fulfilled', value: r }, ipcPromise.id); + return this.notify(IpcPromiseSettled, { status: 'fulfilled', value: r }, ipcPromise.value.id); }, (ex: unknown) => { if (cancellation?.isCancellationRequested) { debugger; return; } - return this.notify(ipcPromiseSettled, { status: 'rejected', reason: ex }, ipcPromise.id); + return this.notify(IpcPromiseSettled, { status: 'rejected', reason: ex }, ipcPromise.value.id); }, ); } @@ -728,13 +739,15 @@ export class WebviewController< const ipcPromise: IpcPromise = { __ipc: 'promise', __promise: value, - id: this.nextIpcId(), - method: ipcPromiseSettled.method, + value: { + id: this.nextIpcId(), + method: IpcPromiseSettled.method, + }, }; (data as Record)[key] = ipcPromise; pendingPromises.push(ipcPromise); } else if (isIpcPromise(value)) { - value.id = this.nextIpcId(); + value.value.id = this.nextIpcId(); pendingPromises.push(value); } else { this.replacePromisesWithIpcPromisesCore(value, pendingPromises); @@ -744,8 +757,7 @@ export class WebviewController< @sequentialize() @debug['postMessage']>({ - args: false, - enter: m => `(${m.id}|${m.method}${m.completionId ? `+${m.completionId}` : ''})`, + args: { 0: m => `${m.id}|${m.method}${m.completionId ? `+${m.completionId}` : ''}` }, }) private async postMessage(message: IpcMessage): Promise { if (!this._ready) return Promise.resolve(false); @@ -859,7 +871,7 @@ export function replaceWebviewHtmlTokens( root: string, webRoot: string, placement: 'editor' | 'view', - bootstrap?: SerializedState, + bootstrap?: SerializedState | string, head?: string, body?: string, endOfBody?: string, From 297b6559a238e74836e73b52490a967aad969587 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Oct 2025 20:42:45 -0400 Subject: [PATCH 18/83] Adds Claude 4.5 Haiku, hides older Claude models --- src/plus/ai/anthropicProvider.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/plus/ai/anthropicProvider.ts b/src/plus/ai/anthropicProvider.ts index 88a638509398a..1a13bdf78c7bc 100644 --- a/src/plus/ai/anthropicProvider.ts +++ b/src/plus/ai/anthropicProvider.ts @@ -7,6 +7,20 @@ import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase'; type AnthropicModel = AIModel; const models: AnthropicModel[] = [ + { + id: 'claude-haiku-4-5', + name: 'Claude 4.5 Haiku', + maxTokens: { input: 204800, output: 32000 }, + provider: provider, + default: true, + }, + { + id: 'claude-haiku-4-5-20251001', + name: 'Claude 4.5 Haiku', + maxTokens: { input: 204800, output: 32000 }, + provider: provider, + hidden: true, + }, { id: 'claude-sonnet-4-5', name: 'Claude 4.5 Sonnet', @@ -25,19 +39,20 @@ const models: AnthropicModel[] = [ name: 'Claude 4.1 Opus', maxTokens: { input: 204800, output: 32000 }, provider: provider, - hidden: true, }, { id: 'claude-opus-4-1-20250805', name: 'Claude 4.1 Opus', maxTokens: { input: 204800, output: 32000 }, provider: provider, + hidden: true, }, { id: 'claude-opus-4-0', name: 'Claude 4 Opus', maxTokens: { input: 204800, output: 32000 }, provider: provider, + hidden: true, }, { id: 'claude-opus-4-20250514', @@ -64,6 +79,7 @@ const models: AnthropicModel[] = [ name: 'Claude 3.7 Sonnet', maxTokens: { input: 204800, output: 64000 }, provider: provider, + hidden: true, }, { id: 'claude-3-7-sonnet-20250219', @@ -77,6 +93,7 @@ const models: AnthropicModel[] = [ name: 'Claude 3.5 Sonnet', maxTokens: { input: 204800, output: 8192 }, provider: provider, + hidden: true, }, { id: 'claude-3-5-sonnet-20241022', @@ -97,7 +114,7 @@ const models: AnthropicModel[] = [ name: 'Claude 3.5 Haiku', maxTokens: { input: 204800, output: 8192 }, provider: provider, - default: true, + hidden: true, }, { id: 'claude-3-5-haiku-20241022', @@ -111,6 +128,7 @@ const models: AnthropicModel[] = [ name: 'Claude 3 Opus', maxTokens: { input: 204800, output: 4096 }, provider: provider, + hidden: true, }, { id: 'claude-3-opus-20240229', @@ -138,6 +156,7 @@ const models: AnthropicModel[] = [ name: 'Claude 3 Haiku', maxTokens: { input: 204800, output: 4096 }, provider: provider, + hidden: true, }, { id: 'claude-3-haiku-20240307', From bdccdc48dd2a2716a698ce589a6a4b3cd3acc8b0 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 16 Oct 2025 18:10:52 -0400 Subject: [PATCH 19/83] Fixes #4701 guards against missing config props --- src/env/node/gk/mcp/integration.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/env/node/gk/mcp/integration.ts b/src/env/node/gk/mcp/integration.ts index 6f1dd15de9fe0..94f48e479229f 100644 --- a/src/env/node/gk/mcp/integration.ts +++ b/src/env/node/gk/mcp/integration.ts @@ -95,18 +95,24 @@ export class GkMcpProvider implements McpServerDefinitionProvider, Disposable { return undefined; } - let output = await runCLICommand(['mcp', 'config', appName, '--source=gitlens', `--scheme=${env.uriScheme}`], { - cwd: cliPath, - }); - output = output.replace(CLIProxyMCPConfigOutputs.checkingForUpdates, '').trim(); - try { + let output = await runCLICommand( + ['mcp', 'config', appName, '--source=gitlens', `--scheme=${env.uriScheme}`], + { + cwd: cliPath, + }, + ); + output = output.replace(CLIProxyMCPConfigOutputs.checkingForUpdates, '').trim(); + const config: McpConfiguration = JSON.parse(output); + if (!config.type || !config.command || !Array.isArray(config.args)) { + throw new Error(`Invalid MCP configuration: missing required properties (${output})`); + } this.onRegistrationCompleted(cliInstall.version); return { - name: config.name, + name: config.name ?? 'GitKraken', type: config.type, command: config.command, args: config.args, @@ -114,7 +120,7 @@ export class GkMcpProvider implements McpServerDefinitionProvider, Disposable { }; } catch (ex) { Logger.error(`Error getting MCP configuration: ${ex}`); - this.onRegistrationFailed('Error getting MCP configuration', undefined, cliInstall.version); + this.onRegistrationFailed('Error getting MCP configuration', String(ex), cliInstall.version); } return undefined; From e2956a331169b63329ba0938d9e0cf7bc190236c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 16 Oct 2025 23:58:40 -0400 Subject: [PATCH 20/83] Updates CHANGELOG --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c58b539bd70af..9327250072e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Changes the minimum VS Code version to 1.95.0 ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) +## [17.6.2] - 2025-10-16 + +### Changed + +- Reduces view refresh frequency for showing last fetched time to improve performance and reduce overhead +- Replaces OS-specific shell-based unzip with JS solution for better cross-platform support and reliability +- Improves MCP checks and adds offline check ([#4687](https://github.com/gitkraken/vscode-gitlens/issues/4687)) +- Updates auto-compose instructions setting text to a link on _Commit Composer_ + ### Fixed +- Fixes MCP registration from breaking VS Code chat ([#4701](https://github.com/gitkraken/vscode-gitlens/issues/4701)) - Fixes MCP extension registration not working on Kiro ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) +- Fixes intermittent issue with autolinks not showing up ([#4692](https://github.com/gitkraken/vscode-gitlens/issues/4692)) ## [17.6.1] - 2025-10-08 @@ -6397,7 +6408,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Initial release but still heavily a work in progress. -[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.1...HEAD +[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.2...HEAD +[17.6.2]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.1...gitkraken:v17.6.2 [17.6.1]: https://github.com/gitkraken/vscode-gitlens/compare/v17.6.0...gitkraken:v17.6.1 [17.6.0]: https://github.com/gitkraken/vscode-gitlens/compare/v17.5.1...gitkraken:v17.6.0 [17.5.1]: https://github.com/gitkraken/vscode-gitlens/compare/v17.5.0...gitkraken:v17.5.1 From 201d9108f9fe4f7de587fd55c5d51a28d13dc1d3 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 00:16:10 -0400 Subject: [PATCH 21/83] Updates dependencies --- ThirdPartyNotices.txt | 14 +- package.json | 54 +- pnpm-lock.yaml | 1542 ++++++++++++++++++++++------------------- pnpm-workspace.yaml | 2 - 4 files changed, 848 insertions(+), 764 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index a60d3644b527f..da8ac242d51db 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -9,17 +9,17 @@ This project incorporates components from the projects listed below. 4. @lit/context version 1.1.6 (https://github.com/lit/lit) 5. @lit/react version 1.0.8 (https://github.com/lit/lit) 6. @lit/task version 1.0.3 (https://github.com/lit/lit) -7. @octokit/graphql version 9.0.1 (https://github.com/octokit/graphql.js) -8. @octokit/request-error version 7.0.0 (https://github.com/octokit/request-error.js) -9. @octokit/request version 10.0.3 (https://github.com/octokit/request.js) -10. @octokit/types version 14.1.0 (https://github.com/octokit/types.ts) +7. @octokit/graphql version 9.0.2 (https://github.com/octokit/graphql.js) +8. @octokit/request-error version 7.0.1 (https://github.com/octokit/request-error.js) +9. @octokit/request version 10.0.5 (https://github.com/octokit/request.js) +10. @octokit/types version 15.0.0 (https://github.com/octokit/types.ts) 11. @opentelemetry/api version 1.9.0 (https://github.com/open-telemetry/opentelemetry-js) -12. @opentelemetry/exporter-trace-otlp-http version 0.205.0 (https://github.com/open-telemetry/opentelemetry-js) +12. @opentelemetry/exporter-trace-otlp-http version 0.206.0 (https://github.com/open-telemetry/opentelemetry-js) 13. @opentelemetry/resources version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js) 14. @opentelemetry/sdk-trace-base version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js) 15. @opentelemetry/semantic-conventions version 1.37.0 (https://github.com/open-telemetry/opentelemetry-js) 16. @shoelace-style/shoelace version 2.20.1 (https://github.com/shoelace-style/shoelace) -17. @vscode/codicons version 0.0.40 (https://github.com/microsoft/vscode-codicons) +17. @vscode/codicons version 0.0.41 (https://github.com/microsoft/vscode-codicons) 18. billboard.js version 3.17.0 (https://github.com/naver/billboard.js) 19. diff2html version 3.4.52 (https://github.com/rtfpessoa/diff2html) 20. driver.js version 1.3.6 (https://github.com/kamranahmedse/driver.js) @@ -27,7 +27,7 @@ This project incorporates components from the projects listed below. 22. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent) 23. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite) 24. lit version 3.3.1 (https://github.com/lit/lit) -25. marked version 16.3.0 (https://github.com/markedjs/marked) +25. marked version 16.4.0 (https://github.com/markedjs/marked) 26. microsoft/vscode (https://github.com/microsoft/vscode) 27. node-fetch version 2.7.0 (https://github.com/bitinn/node-fetch) 28. os-browserify version 0.3.0 (https://github.com/CoderPuppy/os-browserify) diff --git a/package.json b/package.json index 687527d010883..510f144b36763 100644 --- a/package.json +++ b/package.json @@ -25055,17 +25055,17 @@ "@lit/context": "1.1.6", "@lit/react": "1.0.8", "@lit/task": "1.0.3", - "@octokit/graphql": "9.0.1", - "@octokit/request": "10.0.3", - "@octokit/request-error": "7.0.0", - "@octokit/types": "14.1.0", + "@octokit/graphql": "9.0.2", + "@octokit/request": "10.0.5", + "@octokit/request-error": "7.0.1", + "@octokit/types": "15.0.0", "@opentelemetry/api": "1.9.0", - "@opentelemetry/exporter-trace-otlp-http": "0.205.0", + "@opentelemetry/exporter-trace-otlp-http": "0.206.0", "@opentelemetry/resources": "2.1.0", "@opentelemetry/sdk-trace-base": "2.1.0", "@opentelemetry/semantic-conventions": "1.37.0", "@shoelace-style/shoelace": "2.20.1", - "@vscode/codicons": "0.0.40", + "@vscode/codicons": "0.0.41", "billboard.js": "3.17.0", "diff2html": "3.4.52", "driver.js": "1.3.6", @@ -25073,7 +25073,7 @@ "https-proxy-agent": "5.0.1", "iconv-lite": "0.6.3", "lit": "3.3.1", - "marked": "16.3.0", + "marked": "16.4.0", "node-fetch": "2.7.0", "os-browserify": "0.3.0", "path-browserify": "1.0.1", @@ -25084,26 +25084,26 @@ "sortablejs": "1.15.6" }, "devDependencies": { - "@custom-elements-manifest/analyzer": "0.10.5", + "@custom-elements-manifest/analyzer": "0.10.10", "@eamodio/eslint-lite-webpack-plugin": "0.3.2", "@eslint/compat": "1.4.0", - "@eslint/js": "9.36.0", - "@playwright/test": "1.55.0", + "@eslint/js": "9.37.0", + "@playwright/test": "1.56.0", "@prettier/plugin-oxc": "0.0.4", "@swc/core": "1.13.5", "@twbs/fantasticon": "3.1.0", "@types/mocha": "10.0.10", - "@types/node": "20.14.15", - "@types/react": "19.0.12", - "@types/react-dom": "19.0.4", + "@types/node": "20.16.15", + "@types/react": "19.0.14", + "@types/react-dom": "19.0.6", "@types/sinon": "17.0.4", "@types/slug": "5.0.9", "@types/sortablejs": "1.15.8", "@types/vscode": "1.95.0", - "@typescript-eslint/parser": "8.45.0", - "@vscode/test-cli": "0.0.11", + "@typescript-eslint/parser": "8.46.1", + "@vscode/test-cli": "0.0.12", "@vscode/test-electron": "2.5.2", - "@vscode/test-web": "0.0.73", + "@vscode/test-web": "0.0.74", "@vscode/vsce": "3.6.2", "cheerio": "1.0.0-rc.12", "circular-dependency-plugin": "5.2.2", @@ -25114,15 +25114,15 @@ "css-minimizer-webpack-plugin": "7.0.2", "cssnano-preset-advanced": "7.0.9", "esbuild": "0.25.10", - "esbuild-loader": "4.3.0", + "esbuild-loader": "4.4.0", "esbuild-node-externals": "1.18.0", "esbuild-sass-plugin": "3.3.1", - "eslint": "9.36.0", + "eslint": "9.37.0", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-anti-trojan-source": "1.1.1", "eslint-plugin-import-x": "4.16.1", "eslint-plugin-lit": "2.1.1", - "eslint-plugin-wc": "3.0.1", + "eslint-plugin-wc": "3.0.2", "fork-ts-checker-webpack-plugin": "9.1.0", "glob": "11.0.3", "globals": "16.4.0", @@ -25133,21 +25133,21 @@ "license-checker-rseidelsohn": "4.4.2", "lz-string": "1.5.0", "mini-css-extract-plugin": "2.9.4", - "ovsx": "0.10.5", - "playwright": "1.55.0", + "ovsx": "0.10.6", + "playwright": "1.56.0", "prettier": "3.6.2", "regex-to-strings": "2.1.0", - "sass": "1.90.0", + "sass": "1.93.2", "sass-loader": "16.0.5", - "schema-utils": "4.3.2", - "sharp": "0.34.3", + "schema-utils": "4.3.3", + "sharp": "0.34.4", "sinon": "21.0.0", "svgo": "4.0.0", "terser-webpack-plugin": "5.3.14", "ts-loader": "9.5.4", - "typescript": "5.9.2", - "typescript-eslint": "8.45.0", - "webpack": "5.101.3", + "typescript": "5.9.3", + "typescript-eslint": "8.46.1", + "webpack": "5.102.1", "webpack-bundle-analyzer": "4.10.2", "webpack-cli": "6.0.1", "webpack-node-externals": "3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd76efd3ba387..bb780da838d15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: dependencies: '@gitkraken/gitkraken-components': specifier: 13.0.0-vnext.9 - version: 13.0.0-vnext.9(@types/react@19.0.12)(react@19.0.0) + version: 13.0.0-vnext.9(@types/react@19.0.14)(react@19.0.0) '@gitkraken/provider-apis': specifier: 0.29.7 version: 0.29.7(encoding@0.1.13) @@ -38,28 +38,28 @@ importers: version: 1.1.6 '@lit/react': specifier: 1.0.8 - version: 1.0.8(@types/react@19.0.12) + version: 1.0.8(@types/react@19.0.14) '@lit/task': specifier: 1.0.3 version: 1.0.3 '@octokit/graphql': - specifier: 9.0.1 - version: 9.0.1 + specifier: 9.0.2 + version: 9.0.2 '@octokit/request': - specifier: 10.0.3 - version: 10.0.3 + specifier: 10.0.5 + version: 10.0.5 '@octokit/request-error': - specifier: 7.0.0 - version: 7.0.0 + specifier: 7.0.1 + version: 7.0.1 '@octokit/types': - specifier: 14.1.0 - version: 14.1.0 + specifier: 15.0.0 + version: 15.0.0 '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 '@opentelemetry/exporter-trace-otlp-http': - specifier: 0.205.0 - version: 0.205.0(@opentelemetry/api@1.9.0) + specifier: 0.206.0 + version: 0.206.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': specifier: 2.1.0 version: 2.1.0(@opentelemetry/api@1.9.0) @@ -71,10 +71,10 @@ importers: version: 1.37.0 '@shoelace-style/shoelace': specifier: 2.20.1 - version: 2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.0.12) + version: 2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.0.14) '@vscode/codicons': - specifier: 0.0.40 - version: 0.0.40 + specifier: 0.0.41 + version: 0.0.41 billboard.js: specifier: 3.17.0 version: 3.17.0 @@ -97,8 +97,8 @@ importers: specifier: 3.3.1 version: 3.3.1 marked: - specifier: 16.3.0 - version: 16.3.0 + specifier: 16.4.0 + version: 16.4.0 node-fetch: specifier: 2.7.0 version: 2.7.0(encoding@0.1.13) @@ -125,20 +125,20 @@ importers: version: 1.15.6 devDependencies: '@custom-elements-manifest/analyzer': - specifier: 0.10.5 - version: 0.10.5 + specifier: 0.10.10 + version: 0.10.10 '@eamodio/eslint-lite-webpack-plugin': specifier: 0.3.2 - version: 0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.36.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.101.3) + version: 0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.37.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.102.1) '@eslint/compat': specifier: 1.4.0 - version: 1.4.0(eslint@9.36.0(jiti@2.4.0)) + version: 1.4.0(eslint@9.37.0(jiti@2.4.0)) '@eslint/js': - specifier: 9.36.0 - version: 9.36.0 + specifier: 9.37.0 + version: 9.37.0 '@playwright/test': - specifier: 1.55.0 - version: 1.55.0 + specifier: 1.56.0 + version: 1.56.0 '@prettier/plugin-oxc': specifier: 0.0.4 version: 0.0.4 @@ -152,14 +152,14 @@ importers: specifier: 10.0.10 version: 10.0.10 '@types/node': - specifier: 20.14.15 - version: 20.14.15 + specifier: 20.16.15 + version: 20.16.15 '@types/react': - specifier: 19.0.12 - version: 19.0.12 + specifier: 19.0.14 + version: 19.0.14 '@types/react-dom': - specifier: 19.0.4 - version: 19.0.4(@types/react@19.0.12) + specifier: 19.0.6 + version: 19.0.6(@types/react@19.0.14) '@types/sinon': specifier: 17.0.4 version: 17.0.4 @@ -173,17 +173,17 @@ importers: specifier: 1.95.0 version: 1.95.0 '@typescript-eslint/parser': - specifier: 8.45.0 - version: 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) + specifier: 8.46.1 + version: 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) '@vscode/test-cli': - specifier: 0.0.11 - version: 0.0.11 + specifier: 0.0.12 + version: 0.0.12 '@vscode/test-electron': specifier: 2.5.2 version: 2.5.2 '@vscode/test-web': - specifier: 0.0.73 - version: 0.0.73 + specifier: 0.0.74 + version: 0.0.74 '@vscode/vsce': specifier: 3.6.2 version: 3.6.2 @@ -192,22 +192,22 @@ importers: version: 1.0.0-rc.12 circular-dependency-plugin: specifier: 5.2.2 - version: 5.2.2(webpack@5.101.3) + version: 5.2.2(webpack@5.102.1) clean-webpack-plugin: specifier: 4.0.0 - version: 4.0.0(webpack@5.101.3) + version: 4.0.0(webpack@5.102.1) copy-webpack-plugin: specifier: 13.0.1 - version: 13.0.1(webpack@5.101.3) + version: 13.0.1(webpack@5.102.1) csp-html-webpack-plugin: specifier: 5.1.0 - version: 5.1.0(html-webpack-plugin@5.6.4(webpack@5.101.3))(webpack@5.101.3) + version: 5.1.0(html-webpack-plugin@5.6.4(webpack@5.102.1))(webpack@5.102.1) css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.101.3) + version: 7.1.2(webpack@5.102.1) css-minimizer-webpack-plugin: specifier: 7.0.2 - version: 7.0.2(esbuild@0.25.10)(webpack@5.101.3) + version: 7.0.2(esbuild@0.25.10)(webpack@5.102.1) cssnano-preset-advanced: specifier: 7.0.9 version: 7.0.9(postcss@8.5.6) @@ -215,8 +215,8 @@ importers: specifier: 0.25.10 version: 0.25.10 esbuild-loader: - specifier: 4.3.0 - version: 4.3.0(webpack@5.101.3) + specifier: 4.4.0 + version: 4.4.0(webpack@5.102.1) esbuild-node-externals: specifier: 1.18.0 version: 1.18.0(esbuild@0.25.10) @@ -224,26 +224,26 @@ importers: specifier: 3.3.1 version: 3.3.1(esbuild@0.25.10)(sass-embedded@1.77.8) eslint: - specifier: 9.36.0 - version: 9.36.0(jiti@2.4.0) + specifier: 9.37.0 + version: 9.37.0(jiti@2.4.0) eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.36.0(jiti@2.4.0)) + version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.37.0(jiti@2.4.0)) eslint-plugin-anti-trojan-source: specifier: 1.1.1 version: 1.1.1 eslint-plugin-import-x: specifier: 4.16.1 - version: 4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)) + version: 4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)) eslint-plugin-lit: specifier: 2.1.1 - version: 2.1.1(eslint@9.36.0(jiti@2.4.0)) + version: 2.1.1(eslint@9.37.0(jiti@2.4.0)) eslint-plugin-wc: - specifier: 3.0.1 - version: 3.0.1(eslint@9.36.0(jiti@2.4.0)) + specifier: 3.0.2 + version: 3.0.2(eslint@9.37.0(jiti@2.4.0)) fork-ts-checker-webpack-plugin: specifier: 9.1.0 - version: 9.1.0(typescript@5.9.2)(webpack@5.101.3) + version: 9.1.0(typescript@5.9.3)(webpack@5.102.1) glob: specifier: 11.0.3 version: 11.0.3 @@ -255,13 +255,13 @@ importers: version: 3.0.2 html-loader: specifier: 5.1.0 - version: 5.1.0(webpack@5.101.3) + version: 5.1.0(webpack@5.102.1) html-webpack-plugin: specifier: 5.6.4 - version: 5.6.4(webpack@5.101.3) + version: 5.6.4(webpack@5.102.1) image-minimizer-webpack-plugin: specifier: 4.1.4 - version: 4.1.4(sharp@0.34.3)(svgo@4.0.0)(webpack@5.101.3) + version: 4.1.4(sharp@0.34.4)(svgo@4.0.0)(webpack@5.102.1) license-checker-rseidelsohn: specifier: 4.4.2 version: 4.4.2 @@ -270,13 +270,13 @@ importers: version: 1.5.0 mini-css-extract-plugin: specifier: 2.9.4 - version: 2.9.4(webpack@5.101.3) + version: 2.9.4(webpack@5.102.1) ovsx: - specifier: 0.10.5 - version: 0.10.5 + specifier: 0.10.6 + version: 0.10.6 playwright: - specifier: 1.55.0 - version: 1.55.0 + specifier: 1.56.0 + version: 1.56.0 prettier: specifier: 3.6.2 version: 3.6.2 @@ -284,17 +284,17 @@ importers: specifier: 2.1.0 version: 2.1.0 sass: - specifier: 1.90.0 - version: 1.90.0 + specifier: 1.93.2 + version: 1.93.2 sass-loader: specifier: 16.0.5 - version: 16.0.5(sass-embedded@1.77.8)(sass@1.90.0)(webpack@5.101.3) + version: 16.0.5(sass-embedded@1.77.8)(sass@1.93.2)(webpack@5.102.1) schema-utils: - specifier: 4.3.2 - version: 4.3.2 + specifier: 4.3.3 + version: 4.3.3 sharp: - specifier: 0.34.3 - version: 0.34.3 + specifier: 0.34.4 + version: 0.34.4 sinon: specifier: 21.0.0 version: 21.0.0 @@ -303,31 +303,31 @@ importers: version: 4.0.0 terser-webpack-plugin: specifier: 5.3.14 - version: 5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.101.3) + version: 5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.102.1) ts-loader: specifier: 9.5.4 - version: 9.5.4(typescript@5.9.2)(webpack@5.101.3) + version: 9.5.4(typescript@5.9.3)(webpack@5.102.1) typescript: - specifier: 5.9.2 - version: 5.9.2 + specifier: 5.9.3 + version: 5.9.3 typescript-eslint: - specifier: 8.45.0 - version: 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) + specifier: 8.46.1 + version: 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) webpack: - specifier: 5.101.3 - version: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + specifier: 5.102.1 + version: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) webpack-bundle-analyzer: specifier: 4.10.2 version: 4.10.2 webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3) + version: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1) webpack-node-externals: specifier: 3.0.0 version: 3.0.0 webpack-require-from: specifier: 1.8.6 - version: 1.8.6(tapable@2.2.3) + version: 1.8.6(tapable@2.3.0) packages: @@ -367,24 +367,24 @@ packages: resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} engines: {node: '>=20.0.0'} - '@azure/identity@4.12.0': - resolution: {integrity: sha512-6vuh2R3Cte6SD6azNalLCjIDoryGdcvDVEV7IDRPtm5lHX5ffkDlIalaoOp5YJU08e4ipjJENel20kSMDLAcug==} + '@azure/identity@4.13.0': + resolution: {integrity: sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==} engines: {node: '>=20.0.0'} '@azure/logger@1.3.0': resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/msal-browser@4.23.0': - resolution: {integrity: sha512-uHnfRwGAEHaYVXzpCtYsruy6PQxL2v76+MJ3+n/c/3PaTiTIa5ch7VofTUNoA39nHyjJbdiqTwFZK40OOTOkjw==} + '@azure/msal-browser@4.25.0': + resolution: {integrity: sha512-kbL+Ae7/UC62wSzxirZddYeVnHvvkvAnSZkBqL55X+jaSXTAXfngnNsDM5acEWU0Q/SAv3gEQfxO1igWOn87Pg==} engines: {node: '>=0.8.0'} - '@azure/msal-common@15.12.0': - resolution: {integrity: sha512-4ucXbjVw8KJ5QBgnGJUeA07c8iznwlk5ioHIhI4ASXcXgcf2yRFhWzYOyWg/cI49LC9ekpFJeQtO3zjDTbl6TQ==} + '@azure/msal-common@15.13.0': + resolution: {integrity: sha512-8oF6nj02qX7eE/6+wFT5NluXRHc05AgdCC3fJnkjiJooq8u7BcLmxaYYSwc2AfEkWRMRi6Eyvvbeqk4U4412Ag==} engines: {node: '>=0.8.0'} - '@azure/msal-node@3.7.4': - resolution: {integrity: sha512-fjqvhrThwzzPvqhFOdkkGRJCHPQZTNijpceVy8QjcfQuH482tOVEjHyamZaioOhVtx+FK1u+eMpJA2Zz4U9LVg==} + '@azure/msal-node@3.8.0': + resolution: {integrity: sha512-23BXm82Mp5XnRhrcd4mrHa0xuUNRp96ivu3nRatrfdAqjoeWAGyD0eEAafxAOHAEWWmdlyFK4ELFcdziXyw2sA==} engines: {node: '>=16'} '@babel/code-frame@7.27.1': @@ -399,8 +399,9 @@ packages: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - '@bcoe/v8-coverage@0.2.3': - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} '@bufbuild/protobuf@1.10.1': resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==} @@ -409,12 +410,12 @@ packages: resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} engines: {node: '>=14'} - '@custom-elements-manifest/analyzer@0.10.5': - resolution: {integrity: sha512-Y9iUIhTDtcoaiH9XLwkK5POTxVJkcDuN9buCH4kQJmPmTMdm8Fhq7yk0l8Pu3TYC+RuXy6xA49+1IwvFJLF5mg==} + '@custom-elements-manifest/analyzer@0.10.10': + resolution: {integrity: sha512-R1pbKssP3Psb2OiGfheiUbXtBgTGQ0Vu5cn2CHSdZoJV66oZPSSw/TdCf8WlnQ6dfKSy5L8hNneClnmD80GEwA==} hasBin: true - '@custom-elements-manifest/find-dependencies@0.0.5': - resolution: {integrity: sha512-fKIMMZCDFSoL2ySUoz8knWgpV4jpb0lUXgLOvdZQMQFHxgxz1PqOJpUIypwvEVyKk3nEHRY4f10gNol02HjeCg==} + '@custom-elements-manifest/find-dependencies@0.0.6': + resolution: {integrity: sha512-2iVksJ156XuaeeC6jB6oMG6k9ROHS3W1delwJLL804yQMri9NnQW78JDCYMtFfW8b4locUG+3+hrtAHxk+fNGg==} '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} @@ -619,12 +620,8 @@ packages: resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.3.1': - resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.15.2': - resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + '@eslint/config-helpers@0.4.0': + resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/core@0.16.0': @@ -635,16 +632,16 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.36.0': - resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} + '@eslint/js@9.37.0': + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.3.5': - resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + '@eslint/plugin-kit@0.4.0': + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@floating-ui/core@1.7.3': @@ -698,138 +695,142 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.4': + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.4': + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.3': + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.3': + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.3': + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} + '@img/sharp-libvips-linux-arm@1.2.3': + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} + '@img/sharp-libvips-linux-ppc64@1.2.3': + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-s390x@1.2.3': + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.3': + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.4': + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.4': + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} + '@img/sharp-linux-ppc64@0.34.4': + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-s390x@0.34.4': + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.4': + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.4': + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.4': + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.4': + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} + '@img/sharp-win32-arm64@0.34.4': + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.4': + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.4': + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1028,30 +1029,30 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs - '@octokit/endpoint@11.0.0': - resolution: {integrity: sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==} + '@octokit/endpoint@11.0.1': + resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==} engines: {node: '>= 20'} - '@octokit/graphql@9.0.1': - resolution: {integrity: sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==} + '@octokit/graphql@9.0.2': + resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==} engines: {node: '>= 20'} - '@octokit/openapi-types@25.1.0': - resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + '@octokit/openapi-types@26.0.0': + resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/request-error@7.0.0': - resolution: {integrity: sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==} + '@octokit/request-error@7.0.1': + resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==} engines: {node: '>= 20'} - '@octokit/request@10.0.3': - resolution: {integrity: sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==} + '@octokit/request@10.0.5': + resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==} engines: {node: '>= 20'} - '@octokit/types@14.1.0': - resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} + '@octokit/types@15.0.0': + resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} - '@opentelemetry/api-logs@0.205.0': - resolution: {integrity: sha512-wBlPk1nFB37Hsm+3Qy73yQSobVn28F4isnWIBvKpd5IUH/eat8bwcL02H9yzmHyyPmukeccSl2mbN5sDQZYnPg==} + '@opentelemetry/api-logs@0.206.0': + resolution: {integrity: sha512-yIVDu9jX//nV5wSMLZLdHdb1SKHIMj9k+wQVFtln5Flcgdldz9BkHtavvExQiJqBZg2OpEEJEZmzQazYztdz2A==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.0': @@ -1064,20 +1065,20 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-trace-otlp-http@0.205.0': - resolution: {integrity: sha512-vr2bwwPCSc9u7rbKc74jR+DXFvyMFQo9o5zs+H/fgbK672Whw/1izUKVf+xfWOdJOvuwTnfWxy+VAY+4TSo74Q==} + '@opentelemetry/exporter-trace-otlp-http@0.206.0': + resolution: {integrity: sha512-xiEhJZxE9yDb13FVW4XaF7J56boLv1NALOGEVu3F8jMC24iZmX5TSVRJCNGLWyy1Xb3N27Yu31kdSsmEBCnxyw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-exporter-base@0.205.0': - resolution: {integrity: sha512-2MN0C1IiKyo34M6NZzD6P9Nv9Dfuz3OJ3rkZwzFmF6xzjDfqqCTatc9v1EpNfaP55iDOCLHFyYNCgs61FFgtUQ==} + '@opentelemetry/otlp-exporter-base@0.206.0': + resolution: {integrity: sha512-Rv54oSNKMHYS5hv+H5EGksfBUtvPQWFTK+Dk6MjJun9tOijCsFJrhRFvAqg5d67TWSMn+ZQYRKIeXh5oLVrpAQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.205.0': - resolution: {integrity: sha512-KmObgqPtk9k/XTlWPJHdMbGCylRAmMJNXIRh6VYJmvlRDMfe+DonH41G7eenG8t4FXn3fxOGh14o/WiMRR6vPg==} + '@opentelemetry/otlp-transformer@0.206.0': + resolution: {integrity: sha512-Li2Cik1WnmNbU2mmTnw7DxvRiXhMcnAuTfAclP8y/zy7h5+GrLDpTZ+Z0XUs+Q3MLkb/h3ry4uFrC/z+2a6X7g==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -1088,8 +1089,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-logs@0.205.0': - resolution: {integrity: sha512-nyqhNQ6eEzPWQU60Nc7+A5LIq8fz3UeIzdEVBQYefB4+msJZ2vuVtRuk9KxPMw1uHoHDtYEwkr2Ct0iG29jU8w==} + '@opentelemetry/sdk-logs@0.206.0': + resolution: {integrity: sha512-SQ2yTmqe4Mw9RI3a/glVkfjWPsXh6LySvnljXubiZq4zu+UP8NMJt2j82ZsYb+KpD7Eu+/41/7qlJnjdeVjz7Q==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' @@ -1300,12 +1301,12 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/browser-chromium@1.55.0': - resolution: {integrity: sha512-HxG0+6v8NGLFLYMxrGb4T4DAmKwwx6C0V3uIn/i91tOVqcNnaBBllhpxLEqXCnxjprL3HDDMXsVPjk1/vsCVAw==} + '@playwright/browser-chromium@1.56.0': + resolution: {integrity: sha512-+OABx0PwbzoWXO5qOmonvQlIZq0u89XpDkRYf+ZTOs+wsI3r/NV90rzGr8nsJZTj7o10tdPMmuGmZ3OKP9ag4Q==} engines: {node: '>=18'} - '@playwright/test@1.55.0': - resolution: {integrity: sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==} + '@playwright/test@1.56.0': + resolution: {integrity: sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==} engines: {node: '>=18'} hasBin: true @@ -1597,8 +1598,8 @@ packages: '@types/mocha@10.0.10': resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} - '@types/node@20.14.15': - resolution: {integrity: sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==} + '@types/node@20.16.15': + resolution: {integrity: sha512-DV58qQz9dBMqVVn+qnKwGa51QzCD4YM/tQM16qLKxdf5tqz5W4QwtrMzjSTbabN1cFTSuyxVYBy+QWHjWW8X/g==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1606,8 +1607,8 @@ packages: '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - '@types/react-dom@19.0.4': - resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} + '@types/react-dom@19.0.6': + resolution: {integrity: sha512-lo6MuY+rFr8kIiFnr+7TzO+Av0wUPcEcepiPV4epGP0eTQpkDfp9czudg73isV8UxKauCUNlL1N8fXhcnx4iBw==} peerDependencies: '@types/react': ^19.0.0 @@ -1616,8 +1617,8 @@ packages: peerDependencies: '@types/react': '*' - '@types/react@19.0.12': - resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + '@types/react@19.0.14': + resolution: {integrity: sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw==} '@types/sarif@2.1.7': resolution: {integrity: sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==} @@ -1652,63 +1653,63 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.45.0': - resolution: {integrity: sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==} + '@typescript-eslint/eslint-plugin@8.46.1': + resolution: {integrity: sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.45.0 + '@typescript-eslint/parser': ^8.46.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.45.0': - resolution: {integrity: sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==} + '@typescript-eslint/parser@8.46.1': + resolution: {integrity: sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.45.0': - resolution: {integrity: sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==} + '@typescript-eslint/project-service@8.46.1': + resolution: {integrity: sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.45.0': - resolution: {integrity: sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==} + '@typescript-eslint/scope-manager@8.46.1': + resolution: {integrity: sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.45.0': - resolution: {integrity: sha512-aFdr+c37sc+jqNMGhH+ajxPXwjv9UtFZk79k8pLoJ6p4y0snmYpPA52GuWHgt2ZF4gRRW6odsEj41uZLojDt5w==} + '@typescript-eslint/tsconfig-utils@8.46.1': + resolution: {integrity: sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.45.0': - resolution: {integrity: sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==} + '@typescript-eslint/type-utils@8.46.1': + resolution: {integrity: sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.45.0': - resolution: {integrity: sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==} + '@typescript-eslint/types@8.46.1': + resolution: {integrity: sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.45.0': - resolution: {integrity: sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==} + '@typescript-eslint/typescript-estree@8.46.1': + resolution: {integrity: sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.45.0': - resolution: {integrity: sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==} + '@typescript-eslint/utils@8.46.1': + resolution: {integrity: sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.45.0': - resolution: {integrity: sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==} + '@typescript-eslint/visitor-keys@8.46.1': + resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.3.1': @@ -1818,11 +1819,11 @@ packages: cpu: [x64] os: [win32] - '@vscode/codicons@0.0.40': - resolution: {integrity: sha512-R8sEDXthD86JHsk3xERrMcTN6sMovbk1AXYB5/tGoEYCE8DWwya6al5VLrAmQYXC1bQhUHIfHALj8ijQUs11cQ==} + '@vscode/codicons@0.0.41': + resolution: {integrity: sha512-v6/8nx76zau3Joxjzi3eN/FVw+7jKBq4j7LTZY5FhFhq2g0OoFebZ3vRZbv/pUopGpbCnJJ4FOz+NzbjVsmoiw==} - '@vscode/test-cli@0.0.11': - resolution: {integrity: sha512-qO332yvzFqGhBMJrp6TdwbIydiHgCtxXc2Nl6M58mbH/Z+0CyLR76Jzv4YWPEthhrARprzCRJUqzFvTHFhTj7Q==} + '@vscode/test-cli@0.0.12': + resolution: {integrity: sha512-iYN0fDg29+a2Xelle/Y56Xvv7Nc8Thzq4VwpzAF/SIE6918rDicqfsQxV6w1ttr2+SOm+10laGuY9FG2ptEKsQ==} engines: {node: '>=18'} hasBin: true @@ -1830,8 +1831,8 @@ packages: resolution: {integrity: sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==} engines: {node: '>=16'} - '@vscode/test-web@0.0.73': - resolution: {integrity: sha512-xCvUsZi33/asatnFZHOUzrlcfjwqy+I34tjG0pM4LZmDV1jAeczNAyFRZw6VJE+uSAy9N4ncZz/cemdBaU+yZg==} + '@vscode/test-web@0.0.74': + resolution: {integrity: sha512-rXIcru66y56j1RPOhFJYSNs5MAw6yZCFUktqa5tPrxsRel/Lj6vDszq8E47XsVN1NjwsLj8L3FMqwR4/B+0QmA==} engines: {node: '>=20'} hasBin: true @@ -1845,13 +1846,13 @@ packages: cpu: [x64] os: [alpine] - '@vscode/vsce-sign-darwin-arm64@2.0.6': - resolution: {integrity: sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==} + '@vscode/vsce-sign-darwin-arm64@2.0.2': + resolution: {integrity: sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==} cpu: [arm64] os: [darwin] - '@vscode/vsce-sign-darwin-x64@2.0.6': - resolution: {integrity: sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==} + '@vscode/vsce-sign-darwin-x64@2.0.2': + resolution: {integrity: sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==} cpu: [x64] os: [darwin] @@ -1880,8 +1881,8 @@ packages: cpu: [x64] os: [win32] - '@vscode/vsce-sign@2.0.7': - resolution: {integrity: sha512-cz0GFW8qCxpypOy3y509u26K1FIPMlDIHBwGmDyvEbgoma2v3y5YIHHuijr8zCYBp9kzCCOJd28s/0PG7cA7ew==} + '@vscode/vsce-sign@2.0.8': + resolution: {integrity: sha512-H7p8E11cZMj6mt8xIi3QXZ7dSU/2MH3Y7c+5JfUhHAV4xfaPNc8ozwLVK282c6ah596KoIJIdPUlNHV7Qs/5JA==} '@vscode/vsce@3.6.2': resolution: {integrity: sha512-gvBfarWF+Ii20ESqjA3dpnPJpQJ8fFJYtcWtjwbRADommCzGg1emtmb34E+DKKhECYvaVyAl+TF9lWS/3GSPvg==} @@ -1967,6 +1968,60 @@ packages: engines: {node: '>=10.0.0'} deprecated: this version is no longer supported, please update to at least 0.8.* + '@xn-sakina/rml-darwin-arm64@2.6.0': + resolution: {integrity: sha512-RuFHj6ro6Q24gPqNQGvH4uxpsvbgqBBy+ZUK+jbMuMaw4wyti7F6klQWuikBJAxhWpmRbhAB/jrq0PC82qlh5A==} + engines: {node: '>=14'} + cpu: [arm64] + os: [darwin] + + '@xn-sakina/rml-darwin-x64@2.6.0': + resolution: {integrity: sha512-85bsP7viqtgw5nVYBdl8I4c2+q4sYFcBMTeFnTf4RqhUUwBLerP7D+XXnWwv3waO+aZ0Fe0ij9Fji3oTiREOCg==} + engines: {node: '>=14'} + cpu: [x64] + os: [darwin] + + '@xn-sakina/rml-linux-arm-gnueabihf@2.6.0': + resolution: {integrity: sha512-ySI529TPraG1Mf/YiKhLLNGJ1js0Y3BnZRAihUpF4IlyFKmeL3slXEdvK2tVndyX2O21EYWv/DcSAmFMNOolfA==} + engines: {node: '>=14'} + cpu: [arm] + os: [linux] + + '@xn-sakina/rml-linux-arm64-gnu@2.6.0': + resolution: {integrity: sha512-Ytzkmty4vVWAqe+mbu/ql5dqwUH49eVgPT38uJK78LTZRsdogxlQbuAoLKlb/N8CIXAE7BRoywz3lSEGToXylw==} + engines: {node: '>=14'} + cpu: [arm64] + os: [linux] + + '@xn-sakina/rml-linux-arm64-musl@2.6.0': + resolution: {integrity: sha512-DIBSDWlTmWk+r6Xp7mL9Cw8DdWNyJGg7YhOV1sSSRykdGs2TNtS3z0nbHRuUBMqrbtDk0IwqFSepLx12Bix/zw==} + engines: {node: '>=14'} + cpu: [arm64] + os: [linux] + + '@xn-sakina/rml-linux-x64-gnu@2.6.0': + resolution: {integrity: sha512-8Pks6hMicFGWYQmylKul7Gmn64pG4HkRL7skVWEPAF0LZHeI5yvV/EnQUnXXbxPp4Viy2H4420jl6BVS7Uetng==} + engines: {node: '>=14'} + cpu: [x64] + os: [linux] + + '@xn-sakina/rml-linux-x64-musl@2.6.0': + resolution: {integrity: sha512-xHX/rNKcATVrJt2no0FdO6kqnV4P5cP/3MgHA0KwhD/YJmWa66JIfWtzrPv9n/s0beGSorLkh8PLt5lVLFGvlQ==} + engines: {node: '>=14'} + cpu: [x64] + os: [linux] + + '@xn-sakina/rml-win32-arm64-msvc@2.6.0': + resolution: {integrity: sha512-aIOu5frDsxRp5naN6YjBtbCHS4K2WHIx2EClGclv3wGFrOn1oSROxpVOV/MODUuWITj/26pWbZ/tnbvva6ZV8A==} + engines: {node: '>=14'} + cpu: [arm64] + os: [win32] + + '@xn-sakina/rml-win32-x64-msvc@2.6.0': + resolution: {integrity: sha512-XXbzy2gLEs6PpHdM2IUC5QujOIjz6LpSQpJ+ow43gVc7BhagIF5YlMyTFZCbJehjK9yNgPCzdrzsukCjsH5kIA==} + engines: {node: '>=14'} + cpu: [x64] + os: [win32] + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -2044,8 +2099,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ansi-escapes@7.1.0: - resolution: {integrity: sha512-YdhtCd19sKRKfAAUsrcC1wzm4JuzJoiX4pOJqIoW2qmKj5WzG/dL8uUJ0361zaXtHqK7gEhOwtAtz7t3Yq3X5g==} + ansi-escapes@7.1.1: + resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} engines: {node: '>=18'} ansi-regex@5.0.1: @@ -2171,8 +2226,8 @@ packages: azure-devops-node-api@12.5.0: resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} - b4a@1.7.1: - resolution: {integrity: sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==} + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -2185,8 +2240,8 @@ packages: bare-events@2.7.0: resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==} - bare-fs@4.4.4: - resolution: {integrity: sha512-Q8yxM1eLhJfuM7KXVP3zjhBvtMJCYRByoTT+wHXjpdMELv0xICFJX+1w4c7csa+WZEOsq4ItJ4RGwvzid6m/dw==} + bare-fs@4.4.7: + resolution: {integrity: sha512-huJQxUWc2d1T+6dxnC/FoYpBgEHzJp33mYZqFtQqTTPPyP9xPvmjC16VpR4wTte4ZKd5VxkFAcfDYi51iwWMcg==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -2218,8 +2273,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.6: - resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} + baseline-browser-mapping@2.8.15: + resolution: {integrity: sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q==} hasBin: true basic-auth@2.0.1: @@ -2268,8 +2323,8 @@ packages: browserify-zlib@0.1.4: resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==} - browserslist@4.26.2: - resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} + browserslist@4.26.3: + resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2296,10 +2351,15 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - c8@9.1.0: - resolution: {integrity: sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg==} - engines: {node: '>=14.14.0'} + c8@10.1.3: + resolution: {integrity: sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==} + engines: {node: '>=18'} hasBin: true + peerDependencies: + monocart-coverage-reports: ^2 + peerDependenciesMeta: + monocart-coverage-reports: + optional: true cacache@16.1.3: resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} @@ -2335,8 +2395,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001743: - resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} + caniuse-lite@1.0.30001749: + resolution: {integrity: sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==} case@1.6.3: resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} @@ -2441,17 +2501,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} @@ -2880,8 +2933,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.1.0: - resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} diff2html@3.4.52: @@ -2961,8 +3014,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.222: - resolution: {integrity: sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==} + electron-to-chromium@1.5.234: + resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} emoji-regex@10.5.0: resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} @@ -3006,8 +3059,8 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - envinfo@7.14.0: - resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} + envinfo@7.17.0: + resolution: {integrity: sha512-GpfViocsFM7viwClFgxK26OtjMlKN67GCR5v6ASFkotxtpBWd9d+vNy+AH7F2E1TUkMDZ8P/dDPZX71/NG8xnQ==} engines: {node: '>=4'} hasBin: true @@ -3033,9 +3086,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@0.9.3: - resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -3055,8 +3105,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild-loader@4.3.0: - resolution: {integrity: sha512-D7HeJNdkDKKMarPQO/3dlJT6RwN2YJO7ENU6RPlpOz5YxSHnUNi2yvW41Bckvi1EVwctIaLzlb0ni5ag2GINYA==} + esbuild-loader@4.4.0: + resolution: {integrity: sha512-4J+hXTpTtEdzUNLoY8ReqDNJx2NoldfiljRCiKbeYUuZmVaiJeDqFgyAzz8uOopaekwRoCcqBFyEroGQLFVZ1g==} peerDependencies: webpack: ^4.40.0 || ^5.0.0 @@ -3170,8 +3220,8 @@ packages: peerDependencies: eslint: '>= 8' - eslint-plugin-wc@3.0.1: - resolution: {integrity: sha512-0p1wkSlA2Ue3FA4qW+5LZ+15sy0p1nUyVl1eyBMLq4rtN1LtE9IdI49BXNWMz8N8bM/y7Ulx8SWGAni5f8XO5g==} + eslint-plugin-wc@3.0.2: + resolution: {integrity: sha512-siwTrxPTw6GU2JmP3faInw8nhi0ZCnKsiSRM3j7EAkZmBTGYdDAToeseLYsvPrc5Urp/vPz+g7Ewh7XcICLxww==} peerDependencies: eslint: '>=8.40.0' @@ -3191,8 +3241,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.36.0: - resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} + eslint@9.37.0: + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -3230,8 +3280,8 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - events-universal@1.0.0: - resolution: {integrity: sha512-1KVXP1Oq8SiC0HsRraCryA4XGrZ2uJgIt/h4X+mB/8pzMKE7L8yBDN2lBlqJZeUwLAt7kf80m/5GX3HvoCrSGA==} + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} @@ -3407,6 +3457,10 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This package is no longer supported. + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3427,8 +3481,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.12.0: + resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==} github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -3716,8 +3770,8 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} - index-to-position@1.1.0: - resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} engines: {node: '>=18'} infer-owner@1.0.4: @@ -3762,9 +3816,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.4: - resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -3824,8 +3875,8 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -3880,6 +3931,10 @@ packages: resolution: {integrity: sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==} engines: {node: '>=6'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-plain-obj@1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} @@ -4140,8 +4195,8 @@ packages: lit@3.3.1: resolution: {integrity: sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==} - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} loader-utils@2.0.4: @@ -4219,8 +4274,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.1: - resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==} + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} lru-cache@6.0.0: @@ -4255,8 +4310,8 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true - marked@16.3.0: - resolution: {integrity: sha512-K3UxuKu6l6bmA5FUwYho8CfJBlsUWAooKtdGgMcERSpF7gcBUrCGsLH7wDaaNOzwq18JzSUDyoEb/YsrqMac3w==} + marked@16.4.0: + resolution: {integrity: sha512-CTPAcRBq57cn3R8n3hwc2REddc28hjR7RzDXQ+lXLmMJYqn20BaI2cGw6QjgZGIgVfp2Wdfw4aMzgNteQ6qJgQ==} engines: {node: '>= 20'} hasBin: true @@ -4407,8 +4462,8 @@ packages: mnemonist@0.39.8: resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} - mocha@11.7.2: - resolution: {integrity: sha512-lkqVJPmqqG/w5jmmFtiRvtA2jkDyNVUcefFJKb2uyX4dekk8Okgqop3cgbFiaIvj8uCRJVTP5x9dfxGyXm2jvQ==} + mocha@11.7.4: + resolution: {integrity: sha512-1jYAaY8x0kAZ0XszLWu14pzsf4KV740Gld4HXkhNTXwcHx4AUEDkPzgEHg9CM5dVcW+zv036tjpsEbLraPJj4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true @@ -4440,8 +4495,8 @@ packages: napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - napi-postinstall@0.3.3: - resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true @@ -4462,8 +4517,8 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-abi@3.77.0: - resolution: {integrity: sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==} + node-abi@3.78.0: + resolution: {integrity: sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==} engines: {node: '>=10'} node-abort-controller@3.1.1: @@ -4489,8 +4544,8 @@ packages: engines: {node: ^12.13 || ^14.13 || >=16} hasBin: true - node-releases@2.0.21: - resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} + node-releases@2.0.23: + resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} node-sarif-builder@3.2.0: resolution: {integrity: sha512-kVIOdynrF2CRodHZeP/97Rh1syTUHBNiw17hUCIVhlhEsWlfJm19MuO56s4MdKbr22xWx6mzMnNAgXzVlIYM9Q==} @@ -4611,8 +4666,8 @@ packages: os-browserify@0.3.0: resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - ovsx@0.10.5: - resolution: {integrity: sha512-jfulG5k9vjWcolg2kubC51t1eHKA8ANPcKCQKaWPfOsJZ9VlIppP0Anf8pJ1LJHZFHoRmeMXITG9a5NXHwY9tA==} + ovsx@0.10.6: + resolution: {integrity: sha512-MZ7pgQ+IS5kumAfZGnhEjmdOUwW0UlmlekMwuA5DeUJeft7jFu9fTIEhH71ypjdUSpdqchodoKgb5y/ilh7b5g==} engines: {node: '>= 20'} hasBin: true @@ -4782,13 +4837,13 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - playwright-core@1.55.0: - resolution: {integrity: sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==} + playwright-core@1.56.0: + resolution: {integrity: sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==} engines: {node: '>=18'} hasBin: true - playwright@1.55.0: - resolution: {integrity: sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==} + playwright@1.56.0: + resolution: {integrity: sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==} engines: {node: '>=18'} hasBin: true @@ -5280,6 +5335,10 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rs-module-lexer@2.6.0: + resolution: {integrity: sha512-aT0lO0icZ3Hq0IWvo+ORgVc6BJDoKfaDBdRIDQkL2PtBnFQJ0DuvExiiWI4GxjEjH8Yyro++NPArHFaD8bvS9w==} + engines: {node: '>=14'} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -5457,8 +5516,8 @@ packages: webpack: optional: true - sass@1.90.0: - resolution: {integrity: sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==} + sass@1.93.2: + resolution: {integrity: sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==} engines: {node: '>=14.0.0'} hasBin: true @@ -5472,8 +5531,8 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} secretlint@10.2.2: @@ -5489,8 +5548,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -5525,8 +5584,8 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} + sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -5578,9 +5637,6 @@ packages: resolution: {integrity: sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==} engines: {node: '>=10'} - simple-swizzle@0.2.4: - resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} - sinon@21.0.0: resolution: {integrity: sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==} @@ -5769,6 +5825,10 @@ packages: peerDependencies: postcss: ^8.4.32 + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -5777,10 +5837,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - supports-hyperlinks@3.2.0: resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} engines: {node: '>=14.18'} @@ -5814,8 +5870,8 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tapable@2.2.3: - resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} tar-fs@2.1.4: @@ -5860,9 +5916,9 @@ packages: engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@7.0.1: + resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} + engines: {node: '>=18'} text-decoder@1.2.3: resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} @@ -6001,8 +6057,8 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typescript-eslint@8.45.0: - resolution: {integrity: sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==} + typescript-eslint@8.46.1: + resolution: {integrity: sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -6018,8 +6074,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true @@ -6052,8 +6108,8 @@ packages: underscore@1.13.7: resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} unfetch@4.2.0: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} @@ -6176,8 +6232,8 @@ packages: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} - webpack@5.101.3: - resolution: {integrity: sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==} + webpack@5.102.1: + resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -6369,7 +6425,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/identity@4.12.0': + '@azure/identity@4.13.0': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 @@ -6378,8 +6434,8 @@ snapshots: '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@azure/msal-browser': 4.23.0 - '@azure/msal-node': 3.7.4 + '@azure/msal-browser': 4.25.0 + '@azure/msal-node': 3.8.0 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -6392,15 +6448,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-browser@4.23.0': + '@azure/msal-browser@4.25.0': dependencies: - '@azure/msal-common': 15.12.0 + '@azure/msal-common': 15.13.0 - '@azure/msal-common@15.12.0': {} + '@azure/msal-common@15.13.0': {} - '@azure/msal-node@3.7.4': + '@azure/msal-node@3.8.0': dependencies: - '@azure/msal-common': 15.12.0 + '@azure/msal-common': 15.13.0 jsonwebtoken: 9.0.2 uuid: 8.3.2 @@ -6414,15 +6470,15 @@ snapshots: '@babel/runtime@7.28.4': {} - '@bcoe/v8-coverage@0.2.3': {} + '@bcoe/v8-coverage@1.0.2': {} '@bufbuild/protobuf@1.10.1': {} '@ctrl/tinycolor@4.2.0': {} - '@custom-elements-manifest/analyzer@0.10.5': + '@custom-elements-manifest/analyzer@0.10.10': dependencies: - '@custom-elements-manifest/find-dependencies': 0.0.5 + '@custom-elements-manifest/find-dependencies': 0.0.6 '@github/catalyst': 1.7.0 '@web/config-loader': 0.1.3 chokidar: 3.5.2 @@ -6433,21 +6489,21 @@ snapshots: globby: 11.0.4 typescript: 5.4.5 - '@custom-elements-manifest/find-dependencies@0.0.5': + '@custom-elements-manifest/find-dependencies@0.0.6': dependencies: - es-module-lexer: 0.9.3 + rs-module-lexer: 2.6.0 '@discoveryjs/json-ext@0.5.7': {} '@discoveryjs/json-ext@0.6.3': {} - '@eamodio/eslint-lite-webpack-plugin@0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.36.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.101.3)': + '@eamodio/eslint-lite-webpack-plugin@0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.37.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.102.1)': dependencies: '@types/eslint': 9.6.1 '@types/webpack': 5.28.5(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) minimatch: 10.0.3 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -6548,18 +6604,18 @@ snapshots: '@esbuild/win32-x64@0.25.10': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@2.4.0))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0(jiti@2.4.0))': dependencies: - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.4.0(eslint@9.36.0(jiti@2.4.0))': + '@eslint/compat@1.4.0(eslint@9.37.0(jiti@2.4.0))': dependencies: '@eslint/core': 0.16.0 optionalDependencies: - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) '@eslint/config-array@0.21.0': dependencies: @@ -6569,11 +6625,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.3.1': {} - - '@eslint/core@0.15.2': + '@eslint/config-helpers@0.4.0': dependencies: - '@types/json-schema': 7.0.15 + '@eslint/core': 0.16.0 '@eslint/core@0.16.0': dependencies: @@ -6593,13 +6647,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.36.0': {} + '@eslint/js@9.37.0': {} '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.3.5': + '@eslint/plugin-kit@0.4.0': dependencies: - '@eslint/core': 0.15.2 + '@eslint/core': 0.16.0 levn: 0.4.1 '@floating-ui/core@1.7.3': @@ -6617,13 +6671,13 @@ snapshots: '@github/catalyst@1.7.0': {} - '@gitkraken/gitkraken-components@13.0.0-vnext.9(@types/react@19.0.12)(react@19.0.0)': + '@gitkraken/gitkraken-components@13.0.0-vnext.9(@types/react@19.0.14)(react@19.0.0)': dependencies: '@axosoft/react-virtualized': 9.22.3-gitkraken.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) classnames: 2.5.1 re-resizable: 6.11.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 - react-bootstrap: 2.10.7(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-bootstrap: 2.10.7(@types/react@19.0.14)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-dom: 19.0.0(react@19.0.0) react-dragula: 1.1.17 react-onclickoutside: 6.13.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -6660,90 +6714,92 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/sharp-darwin-arm64@0.34.3': + '@img/colour@1.0.0': {} + + '@img/sharp-darwin-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 + '@img/sharp-libvips-darwin-arm64': 1.2.3 optional: true - '@img/sharp-darwin-x64@0.34.3': + '@img/sharp-darwin-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 + '@img/sharp-libvips-darwin-x64': 1.2.3 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': + '@img/sharp-libvips-darwin-arm64@1.2.3': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': + '@img/sharp-libvips-darwin-x64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': + '@img/sharp-libvips-linux-arm64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': + '@img/sharp-libvips-linux-arm@1.2.3': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': + '@img/sharp-libvips-linux-ppc64@1.2.3': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': + '@img/sharp-libvips-linux-s390x@1.2.3': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': + '@img/sharp-libvips-linux-x64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': + '@img/sharp-libvips-linuxmusl-x64@1.2.3': optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-linux-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.3 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-arm': 1.2.3 optional: true - '@img/sharp-linux-ppc64@0.34.3': + '@img/sharp-linux-ppc64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 + '@img/sharp-libvips-linux-ppc64': 1.2.3 optional: true - '@img/sharp-linux-s390x@0.34.3': + '@img/sharp-linux-s390x@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 + '@img/sharp-libvips-linux-s390x': 1.2.3 optional: true - '@img/sharp-linux-x64@0.34.3': + '@img/sharp-linux-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 + '@img/sharp-libvips-linux-x64': 1.2.3 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': + '@img/sharp-linuxmusl-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': + '@img/sharp-linuxmusl-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-wasm32@0.34.4': dependencies: '@emnapi/runtime': 1.5.0 optional: true - '@img/sharp-win32-arm64@0.34.3': + '@img/sharp-win32-arm64@0.34.4': optional: true - '@img/sharp-win32-ia32@0.34.3': + '@img/sharp-win32-ia32@0.34.4': optional: true - '@img/sharp-win32-x64@0.34.3': + '@img/sharp-win32-x64@0.34.4': optional: true '@isaacs/balanced-match@4.0.1': {} @@ -6772,7 +6828,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.15 + '@types/node': 20.16.15 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -6832,9 +6888,9 @@ snapshots: dependencies: '@lit/reactive-element': 2.1.1 - '@lit/react@1.0.8(@types/react@19.0.12)': + '@lit/react@1.0.8(@types/react@19.0.14)': dependencies: - '@types/react': 19.0.12 + '@types/react': 19.0.14 '@lit/reactive-element@2.1.1': dependencies: @@ -6927,47 +6983,47 @@ snapshots: '@npmcli/fs@2.1.2': dependencies: '@gar/promisify': 1.1.3 - semver: 7.7.2 + semver: 7.7.3 '@npmcli/fs@3.1.1': dependencies: - semver: 7.7.2 + semver: 7.7.3 '@npmcli/move-file@2.0.1': dependencies: mkdirp: 1.0.4 rimraf: 3.0.2 - '@octokit/endpoint@11.0.0': + '@octokit/endpoint@11.0.1': dependencies: - '@octokit/types': 14.1.0 + '@octokit/types': 15.0.0 universal-user-agent: 7.0.3 - '@octokit/graphql@9.0.1': + '@octokit/graphql@9.0.2': dependencies: - '@octokit/request': 10.0.3 - '@octokit/types': 14.1.0 + '@octokit/request': 10.0.5 + '@octokit/types': 15.0.0 universal-user-agent: 7.0.3 - '@octokit/openapi-types@25.1.0': {} + '@octokit/openapi-types@26.0.0': {} - '@octokit/request-error@7.0.0': + '@octokit/request-error@7.0.1': dependencies: - '@octokit/types': 14.1.0 + '@octokit/types': 15.0.0 - '@octokit/request@10.0.3': + '@octokit/request@10.0.5': dependencies: - '@octokit/endpoint': 11.0.0 - '@octokit/request-error': 7.0.0 - '@octokit/types': 14.1.0 + '@octokit/endpoint': 11.0.1 + '@octokit/request-error': 7.0.1 + '@octokit/types': 15.0.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 - '@octokit/types@14.1.0': + '@octokit/types@15.0.0': dependencies: - '@octokit/openapi-types': 25.1.0 + '@octokit/openapi-types': 26.0.0 - '@opentelemetry/api-logs@0.205.0': + '@opentelemetry/api-logs@0.206.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -6978,28 +7034,28 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.37.0 - '@opentelemetry/exporter-trace-otlp-http@0.205.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-http@0.206.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.205.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.205.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base@0.205.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-exporter-base@0.206.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.205.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer@0.205.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-transformer@0.206.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.205.0 + '@opentelemetry/api-logs': 0.206.0 '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.205.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0) protobufjs: 7.5.4 @@ -7010,10 +7066,10 @@ snapshots: '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 - '@opentelemetry/sdk-logs@0.205.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-logs@0.206.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.205.0 + '@opentelemetry/api-logs': 0.206.0 '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) @@ -7145,13 +7201,13 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/browser-chromium@1.55.0': + '@playwright/browser-chromium@1.56.0': dependencies: - playwright-core: 1.55.0 + playwright-core: 1.56.0 - '@playwright/test@1.55.0': + '@playwright/test@1.56.0': dependencies: - playwright: 1.55.0 + playwright: 1.56.0 '@polka/url@1.0.0-next.29': {} @@ -7291,11 +7347,11 @@ snapshots: '@shoelace-style/localize@3.2.1': {} - '@shoelace-style/shoelace@2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.0.12)': + '@shoelace-style/shoelace@2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.0.14)': dependencies: '@ctrl/tinycolor': 4.2.0 '@floating-ui/dom': 1.7.4 - '@lit/react': 1.0.8(@types/react@19.0.12) + '@lit/react': 1.0.8(@types/react@19.0.14) '@shoelace-style/animations': 1.2.0 '@shoelace-style/localize': 3.2.1 composed-offset-position: 0.0.6(@floating-ui/utils@0.2.10) @@ -7454,7 +7510,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 20.14.15 + '@types/node': 20.16.15 '@types/html-minifier-terser@6.1.0': {} @@ -7481,23 +7537,23 @@ snapshots: '@types/mocha@10.0.10': {} - '@types/node@20.14.15': + '@types/node@20.16.15': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 '@types/normalize-package-data@2.4.4': {} '@types/prop-types@15.7.15': {} - '@types/react-dom@19.0.4(@types/react@19.0.12)': + '@types/react-dom@19.0.6(@types/react@19.0.14)': dependencies: - '@types/react': 19.0.12 + '@types/react': 19.0.14 - '@types/react-transition-group@4.4.12(@types/react@19.0.12)': + '@types/react-transition-group@4.4.12(@types/react@19.0.14)': dependencies: - '@types/react': 19.0.12 + '@types/react': 19.0.14 - '@types/react@19.0.12': + '@types/react@19.0.14': dependencies: csstype: 3.1.3 @@ -7521,9 +7577,9 @@ snapshots: '@types/webpack@5.28.5(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1)': dependencies: - '@types/node': 20.14.15 - tapable: 2.2.3 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + '@types/node': 20.16.15 + tapable: 2.3.0 + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -7536,97 +7592,97 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/type-utils': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.45.0 - eslint: 9.36.0(jiti@2.4.0) + '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.1 + '@typescript-eslint/type-utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.1 + eslint: 9.37.0(jiti@2.4.0) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2)': + '@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.45.0 + '@typescript-eslint/scope-manager': 8.46.1 + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.1 debug: 4.4.3(supports-color@8.1.1) - eslint: 9.36.0(jiti@2.4.0) - typescript: 5.9.2 + eslint: 9.37.0(jiti@2.4.0) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.45.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.46.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.2) - '@typescript-eslint/types': 8.45.0 + '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) + '@typescript-eslint/types': 8.46.1 debug: 4.4.3(supports-color@8.1.1) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.45.0': + '@typescript-eslint/scope-manager@8.46.1': dependencies: - '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/visitor-keys': 8.45.0 + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/visitor-keys': 8.46.1 - '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.46.1(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 - '@typescript-eslint/type-utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) - eslint: 9.36.0(jiti@2.4.0) - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + eslint: 9.37.0(jiti@2.4.0) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.45.0': {} + '@typescript-eslint/types@8.46.1': {} - '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.46.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.45.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.2) - '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/visitor-keys': 8.45.0 + '@typescript-eslint/project-service': 8.46.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/visitor-keys': 8.46.1 debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2)': + '@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.4.0)) - '@typescript-eslint/scope-manager': 8.45.0 - '@typescript-eslint/types': 8.45.0 - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - eslint: 9.36.0(jiti@2.4.0) - typescript: 5.9.2 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.4.0)) + '@typescript-eslint/scope-manager': 8.46.1 + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) + eslint: 9.37.0(jiti@2.4.0) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.45.0': + '@typescript-eslint/visitor-keys@8.46.1': dependencies: - '@typescript-eslint/types': 8.45.0 + '@typescript-eslint/types': 8.46.1 eslint-visitor-keys: 4.2.1 '@typespec/ts-http-runtime@0.3.1': @@ -7696,19 +7752,21 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vscode/codicons@0.0.40': {} + '@vscode/codicons@0.0.41': {} - '@vscode/test-cli@0.0.11': + '@vscode/test-cli@0.0.12': dependencies: '@types/mocha': 10.0.10 - c8: 9.1.0 + c8: 10.1.3 chokidar: 3.6.0 enhanced-resolve: 5.18.3 glob: 10.4.5 minimatch: 9.0.5 - mocha: 11.7.2 - supports-color: 9.4.0 + mocha: 11.7.4 + supports-color: 10.2.2 yargs: 17.7.2 + transitivePeerDependencies: + - monocart-coverage-reports '@vscode/test-electron@2.5.2': dependencies: @@ -7716,15 +7774,15 @@ snapshots: https-proxy-agent: 5.0.1 jszip: 3.10.1 ora: 8.2.0 - semver: 7.7.2 + semver: 7.7.3 transitivePeerDependencies: - supports-color - '@vscode/test-web@0.0.73': + '@vscode/test-web@0.0.74': dependencies: '@koa/cors': 5.0.0 '@koa/router': 14.0.0 - '@playwright/browser-chromium': 1.55.0 + '@playwright/browser-chromium': 1.56.0 gunzip-maybe: 1.4.2 http-proxy-agent: 7.0.2 https-proxy-agent: 5.0.1 @@ -7733,7 +7791,7 @@ snapshots: koa-mount: 4.2.0 koa-static: 5.0.0 minimist: 1.2.8 - playwright: 1.55.0 + playwright: 1.56.0 tar-fs: 3.1.1 tinyglobby: 0.2.14 vscode-uri: 3.1.0 @@ -7748,10 +7806,10 @@ snapshots: '@vscode/vsce-sign-alpine-x64@2.0.6': optional: true - '@vscode/vsce-sign-darwin-arm64@2.0.6': + '@vscode/vsce-sign-darwin-arm64@2.0.2': optional: true - '@vscode/vsce-sign-darwin-x64@2.0.6': + '@vscode/vsce-sign-darwin-x64@2.0.2': optional: true '@vscode/vsce-sign-linux-arm64@2.0.6': @@ -7769,12 +7827,12 @@ snapshots: '@vscode/vsce-sign-win32-x64@2.0.6': optional: true - '@vscode/vsce-sign@2.0.7': + '@vscode/vsce-sign@2.0.8': optionalDependencies: '@vscode/vsce-sign-alpine-arm64': 2.0.6 '@vscode/vsce-sign-alpine-x64': 2.0.6 - '@vscode/vsce-sign-darwin-arm64': 2.0.6 - '@vscode/vsce-sign-darwin-x64': 2.0.6 + '@vscode/vsce-sign-darwin-arm64': 2.0.2 + '@vscode/vsce-sign-darwin-x64': 2.0.2 '@vscode/vsce-sign-linux-arm': 2.0.6 '@vscode/vsce-sign-linux-arm64': 2.0.6 '@vscode/vsce-sign-linux-x64': 2.0.6 @@ -7783,12 +7841,12 @@ snapshots: '@vscode/vsce@3.6.2': dependencies: - '@azure/identity': 4.12.0 + '@azure/identity': 4.13.0 '@secretlint/node': 10.2.2 '@secretlint/secretlint-formatter-sarif': 10.2.2 '@secretlint/secretlint-rule-no-dotenv': 10.2.2 '@secretlint/secretlint-rule-preset-recommend': 10.2.2 - '@vscode/vsce-sign': 2.0.7 + '@vscode/vsce-sign': 2.0.8 azure-devops-node-api: 12.5.0 chalk: 4.1.2 cheerio: 1.0.0-rc.12 @@ -7805,7 +7863,7 @@ snapshots: parse-semver: 1.1.1 read: 1.0.7 secretlint: 10.2.2 - semver: 7.7.2 + semver: 7.7.3 tmp: 0.2.5 typed-rest-client: 1.8.11 url-join: 4.0.1 @@ -7819,7 +7877,7 @@ snapshots: '@web/config-loader@0.1.3': dependencies: - semver: 7.7.2 + semver: 7.7.3 '@webassemblyjs/ast@1.14.1': dependencies: @@ -7897,23 +7955,50 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.101.3)': + '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.102.1)': dependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1) - '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.101.3)': + '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.102.1)': dependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1) - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.101.3)': + '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.102.1)': dependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1) '@xmldom/xmldom@0.7.13': {} + '@xn-sakina/rml-darwin-arm64@2.6.0': + optional: true + + '@xn-sakina/rml-darwin-x64@2.6.0': + optional: true + + '@xn-sakina/rml-linux-arm-gnueabihf@2.6.0': + optional: true + + '@xn-sakina/rml-linux-arm64-gnu@2.6.0': + optional: true + + '@xn-sakina/rml-linux-arm64-musl@2.6.0': + optional: true + + '@xn-sakina/rml-linux-x64-gnu@2.6.0': + optional: true + + '@xn-sakina/rml-linux-x64-musl@2.6.0': + optional: true + + '@xn-sakina/rml-win32-arm64-msvc@2.6.0': + optional: true + + '@xn-sakina/rml-win32-x64-msvc@2.6.0': + optional: true + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -7985,7 +8070,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-escapes@7.1.0: + ansi-escapes@7.1.1: dependencies: environment: 1.1.0 @@ -8107,8 +8192,8 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.26.2 - caniuse-lite: 1.0.30001743 + browserslist: 4.26.3 + caniuse-lite: 1.0.30001749 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -8125,13 +8210,13 @@ snapshots: tunnel: 0.0.6 typed-rest-client: 1.8.11 - b4a@1.7.1: {} + b4a@1.7.3: {} balanced-match@1.0.2: {} bare-events@2.7.0: {} - bare-fs@4.4.4: + bare-fs@4.4.7: dependencies: bare-events: 2.7.0 bare-path: 3.0.0 @@ -8167,7 +8252,7 @@ snapshots: base64-js@1.5.1: optional: true - baseline-browser-mapping@2.8.6: {} + baseline-browser-mapping@2.8.15: {} basic-auth@2.0.1: dependencies: @@ -8233,13 +8318,13 @@ snapshots: dependencies: pako: 0.2.9 - browserslist@4.26.2: + browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.6 - caniuse-lite: 1.0.30001743 - electron-to-chromium: 1.5.222 - node-releases: 2.0.21 - update-browserslist-db: 1.1.3(browserslist@4.26.2) + baseline-browser-mapping: 2.8.15 + caniuse-lite: 1.0.30001749 + electron-to-chromium: 1.5.234 + node-releases: 2.0.23 + update-browserslist-db: 1.1.3(browserslist@4.26.3) buffer-builder@0.2.0: {} @@ -8263,16 +8348,16 @@ snapshots: dependencies: run-applescript: 7.1.0 - c8@9.1.0: + c8@10.1.3: dependencies: - '@bcoe/v8-coverage': 0.2.3 + '@bcoe/v8-coverage': 1.0.2 '@istanbuljs/schema': 0.1.3 find-up: 5.0.0 foreground-child: 3.3.1 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 - test-exclude: 6.0.0 + test-exclude: 7.0.1 v8-to-istanbul: 9.3.0 yargs: 17.7.2 yargs-parser: 21.1.1 @@ -8336,12 +8421,12 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.26.2 - caniuse-lite: 1.0.30001743 + browserslist: 4.26.3 + caniuse-lite: 1.0.30001749 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001743: {} + caniuse-lite@1.0.30001749: {} case@1.6.3: {} @@ -8410,9 +8495,9 @@ snapshots: ci-info@3.9.0: {} - circular-dependency-plugin@5.2.2(webpack@5.101.3): + circular-dependency-plugin@5.2.2(webpack@5.102.1): dependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) classnames@2.5.1: {} @@ -8422,10 +8507,10 @@ snapshots: clean-stack@2.2.0: {} - clean-webpack-plugin@4.0.0(webpack@5.101.3): + clean-webpack-plugin@4.0.0(webpack@5.102.1): dependencies: del: 4.1.1 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) cli-cursor@5.0.0: dependencies: @@ -8455,18 +8540,8 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.4 - color-support@1.1.3: {} - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - colord@2.9.3: {} colorette@2.0.20: {} @@ -8528,25 +8603,25 @@ snapshots: depd: 2.0.0 keygrip: 1.1.0 - copy-webpack-plugin@13.0.1(webpack@5.101.3): + copy-webpack-plugin@13.0.1(webpack@5.102.1): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.15 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) core-util-is@1.0.3: {} - cosmiconfig@8.3.6(typescript@5.9.2): + cosmiconfig@8.3.6(typescript@5.9.3): dependencies: import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 cross-spawn@7.0.6: dependencies: @@ -8558,18 +8633,18 @@ snapshots: dependencies: custom-event: 1.0.0 - csp-html-webpack-plugin@5.1.0(html-webpack-plugin@5.6.4(webpack@5.101.3))(webpack@5.101.3): + csp-html-webpack-plugin@5.1.0(html-webpack-plugin@5.6.4(webpack@5.102.1))(webpack@5.102.1): dependencies: cheerio: 1.0.0-rc.12 - html-webpack-plugin: 5.6.4(webpack@5.101.3) + html-webpack-plugin: 5.6.4(webpack@5.102.1) lodash: 4.17.21 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) css-declaration-sorter@7.3.0(postcss@8.5.6): dependencies: postcss: 8.5.6 - css-loader@7.1.2(webpack@5.101.3): + css-loader@7.1.2(webpack@5.102.1): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -8578,19 +8653,19 @@ snapshots: postcss-modules-scope: 3.2.1(postcss@8.5.6) postcss-modules-values: 4.0.0(postcss@8.5.6) postcss-value-parser: 4.2.0 - semver: 7.7.2 + semver: 7.7.3 optionalDependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - css-minimizer-webpack-plugin@7.0.2(esbuild@0.25.10)(webpack@5.101.3): + css-minimizer-webpack-plugin@7.0.2(esbuild@0.25.10)(webpack@5.102.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 cssnano: 7.1.1(postcss@8.5.6) jest-worker: 29.7.0 postcss: 8.5.6 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) optionalDependencies: esbuild: 0.25.10 @@ -8627,7 +8702,7 @@ snapshots: cssnano-preset-advanced@7.0.9(postcss@8.5.6): dependencies: autoprefixer: 10.4.21(postcss@8.5.6) - browserslist: 4.26.2 + browserslist: 4.26.3 cssnano-preset-default: 7.0.9(postcss@8.5.6) postcss: 8.5.6 postcss-discard-unused: 7.0.4(postcss@8.5.6) @@ -8637,7 +8712,7 @@ snapshots: cssnano-preset-default@7.0.9(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 css-declaration-sorter: 7.3.0(postcss@8.5.6) cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 @@ -8881,7 +8956,7 @@ snapshots: detect-libc@1.0.3: optional: true - detect-libc@2.1.0: {} + detect-libc@2.1.2: {} diff2html@3.4.52: dependencies: @@ -8983,7 +9058,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.222: {} + electron-to-chromium@1.5.234: {} emoji-regex@10.5.0: {} @@ -9007,7 +9082,7 @@ snapshots: enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.3 + tapable: 2.3.0 entities@2.2.0: {} @@ -9017,7 +9092,7 @@ snapshots: env-paths@2.2.1: {} - envinfo@7.14.0: {} + envinfo@7.17.0: {} environment@1.1.0: {} @@ -9089,8 +9164,6 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@0.9.3: {} - es-module-lexer@1.7.0: {} es-object-atoms@1.1.1: @@ -9116,12 +9189,12 @@ snapshots: is-symbol: 1.1.1 optional: true - esbuild-loader@4.3.0(webpack@5.101.3): + esbuild-loader@4.4.0(webpack@5.102.1): dependencies: esbuild: 0.25.10 - get-tsconfig: 4.10.1 + get-tsconfig: 4.12.0 loader-utils: 2.0.4 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) webpack-sources: 1.4.3 esbuild-node-externals@1.18.0(esbuild@0.25.10): @@ -9134,7 +9207,7 @@ snapshots: esbuild: 0.25.10 resolve: 1.22.10 safe-identifier: 0.4.2 - sass: 1.90.0 + sass: 1.93.2 sass-embedded: 1.77.8 esbuild@0.25.10: @@ -9176,7 +9249,7 @@ snapshots: eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.10.1 + get-tsconfig: 4.12.0 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 @@ -9190,30 +9263,30 @@ snapshots: - supports-color optional: true - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.36.0(jiti@2.4.0)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.37.0(jiti@2.4.0)): dependencies: debug: 4.4.3(supports-color@8.1.1) - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.10.1 + get-tsconfig: 4.12.0 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@2.4.0)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@2.4.0)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@2.4.0)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@2.4.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - eslint: 9.36.0(jiti@2.4.0) + '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + eslint: 9.37.0(jiti@2.4.0) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.36.0(jiti@2.4.0)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)))(eslint-plugin-import@2.29.1)(eslint@9.37.0(jiti@2.4.0)) transitivePeerDependencies: - supports-color optional: true @@ -9222,25 +9295,25 @@ snapshots: dependencies: anti-trojan-source: 1.4.1 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.4.0)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.37.0(jiti@2.4.0)): dependencies: - '@typescript-eslint/types': 8.45.0 + '@typescript-eslint/types': 8.46.1 comment-parser: 1.4.1 debug: 4.4.3(supports-color@8.1.1) - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.0.3 - semver: 7.7.2 + semver: 7.7.3 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@2.4.0)): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@2.4.0)): dependencies: array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 @@ -9248,9 +9321,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@2.4.0)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@2.4.0)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -9261,22 +9334,22 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) + '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color optional: true - eslint-plugin-lit@2.1.1(eslint@9.36.0(jiti@2.4.0)): + eslint-plugin-lit@2.1.1(eslint@9.37.0(jiti@2.4.0)): dependencies: - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) parse5: 6.0.1 parse5-htmlparser2-tree-adapter: 6.0.1 - eslint-plugin-wc@3.0.1(eslint@9.36.0(jiti@2.4.0)): + eslint-plugin-wc@3.0.2(eslint@9.37.0(jiti@2.4.0)): dependencies: - eslint: 9.36.0(jiti@2.4.0) + eslint: 9.37.0(jiti@2.4.0) is-valid-element-name: 1.0.0 js-levenshtein-esm: 2.0.0 @@ -9294,16 +9367,16 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.36.0(jiti@2.4.0): + eslint@9.37.0(jiti@2.4.0): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.4.0)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.4.0)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.3.1 - '@eslint/core': 0.15.2 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.36.0 - '@eslint/plugin-kit': 0.3.5 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -9358,7 +9431,7 @@ snapshots: esutils@2.0.3: {} - events-universal@1.0.0: + events-universal@1.0.1: dependencies: bare-events: 2.7.0 @@ -9454,22 +9527,22 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.2)(webpack@5.101.3): + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.102.1): dependencies: '@babel/code-frame': 7.27.1 chalk: 4.1.2 chokidar: 4.0.3 - cosmiconfig: 8.3.6(typescript@5.9.2) + cosmiconfig: 8.3.6(typescript@5.9.3) deepmerge: 4.3.1 fs-extra: 10.1.0 memfs: 3.5.3 minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.7.2 - tapable: 2.2.3 - typescript: 5.9.2 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + semver: 7.7.3 + tapable: 2.3.0 + typescript: 5.9.3 + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) form-data@4.0.4: dependencies: @@ -9538,6 +9611,9 @@ snapshots: strip-ansi: 6.0.1 wide-align: 1.1.5 + generator-function@2.0.1: + optional: true + get-caller-file@2.0.5: {} get-east-asian-width@1.4.0: {} @@ -9567,7 +9643,7 @@ snapshots: get-intrinsic: 1.3.0 optional: true - get-tsconfig@4.10.1: + get-tsconfig@4.12.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -9745,11 +9821,11 @@ snapshots: html-escaper@2.0.2: {} - html-loader@5.1.0(webpack@5.101.3): + html-loader@5.1.0(webpack@5.102.1): dependencies: html-minifier-terser: 7.2.0 parse5: 7.3.0 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) html-minifier-terser@6.1.0: dependencies: @@ -9771,15 +9847,15 @@ snapshots: relateurl: 0.2.7 terser: 5.44.0 - html-webpack-plugin@5.6.4(webpack@5.101.3): + html-webpack-plugin@5.6.4(webpack@5.102.1): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 - tapable: 2.2.3 + tapable: 2.3.0 optionalDependencies: - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) htmlparser2@6.1.0: dependencies: @@ -9866,13 +9942,13 @@ snapshots: ignore@7.0.5: {} - image-minimizer-webpack-plugin@4.1.4(sharp@0.34.3)(svgo@4.0.0)(webpack@5.101.3): + image-minimizer-webpack-plugin@4.1.4(sharp@0.34.4)(svgo@4.0.0)(webpack@5.102.1): dependencies: - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) optionalDependencies: - sharp: 0.34.3 + sharp: 0.34.4 svgo: 4.0.0 immediate@3.0.6: {} @@ -9897,7 +9973,7 @@ snapshots: indent-string@5.0.0: {} - index-to-position@1.1.0: {} + index-to-position@1.2.0: {} infer-owner@1.0.4: {} @@ -9939,8 +10015,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.4: {} - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -9967,7 +10041,7 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 is-callable@1.2.7: optional: true @@ -10006,9 +10080,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.1.0: + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 + generator-function: 2.0.1 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -10056,6 +10131,8 @@ snapshots: dependencies: path-is-inside: 1.0.2 + is-path-inside@3.0.3: {} + is-plain-obj@1.1.0: {} is-plain-obj@2.1.0: {} @@ -10176,7 +10253,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.15 + '@types/node': 20.16.15 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -10184,13 +10261,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.14.15 + '@types/node': 20.16.15 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 20.14.15 + '@types/node': 20.16.15 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -10251,7 +10328,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.7.2 + semver: 7.7.3 jszip@3.10.1: dependencies: @@ -10353,7 +10430,7 @@ snapshots: mkdirp: 1.0.4 nopt: 7.2.1 read-installed-packages: 2.0.1 - semver: 7.7.2 + semver: 7.7.3 spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 spdx-satisfies: 5.0.1 @@ -10389,7 +10466,7 @@ snapshots: lit-element: 4.2.1 lit-html: 3.3.1 - loader-runner@4.3.0: {} + loader-runner@4.3.1: {} loader-utils@2.0.4: dependencies: @@ -10455,7 +10532,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.1: {} + lru-cache@11.2.2: {} lru-cache@6.0.0: dependencies: @@ -10467,7 +10544,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 make-fetch-happen@10.2.1: dependencies: @@ -10504,7 +10581,7 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - marked@16.3.0: {} + marked@16.4.0: {} math-intrinsics@1.1.0: {} @@ -10565,11 +10642,11 @@ snapshots: mimic-response@3.1.0: optional: true - mini-css-extract-plugin@2.9.4(webpack@5.101.3): + mini-css-extract-plugin@2.9.4(webpack@5.102.1): dependencies: - schema-utils: 4.3.2 - tapable: 2.2.3 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + schema-utils: 4.3.3 + tapable: 2.3.0 + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) minimatch@10.0.3: dependencies: @@ -10643,7 +10720,7 @@ snapshots: dependencies: obliterator: 2.0.5 - mocha@11.7.2: + mocha@11.7.4: dependencies: browser-stdout: 1.3.1 chokidar: 4.0.3 @@ -10653,6 +10730,7 @@ snapshots: find-up: 5.0.0 glob: 10.4.5 he: 1.2.0 + is-path-inside: 3.0.3 js-yaml: 4.1.0 log-symbols: 4.1.0 minimatch: 9.0.5 @@ -10691,7 +10769,7 @@ snapshots: napi-build-utils@2.0.0: optional: true - napi-postinstall@0.3.3: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -10706,9 +10784,9 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 - node-abi@3.77.0: + node-abi@3.78.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 optional: true node-abort-controller@3.1.1: {} @@ -10735,14 +10813,14 @@ snapshots: nopt: 6.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.7.2 + semver: 7.7.3 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: - bluebird - supports-color - node-releases@2.0.21: {} + node-releases@2.0.23: {} node-sarif-builder@3.2.0: dependencies: @@ -10765,20 +10843,20 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.16.1 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 normalize-package-data@5.0.0: dependencies: hosted-git-info: 6.1.3 is-core-module: 2.16.1 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -10889,14 +10967,14 @@ snapshots: os-browserify@0.3.0: {} - ovsx@0.10.5: + ovsx@0.10.6: dependencies: '@vscode/vsce': 3.6.2 commander: 6.2.1 follow-redirects: 1.15.11 is-ci: 2.0.0 leven: 3.1.0 - semver: 7.7.2 + semver: 7.7.3 tmp: 0.2.5 yauzl-promise: 4.0.0 transitivePeerDependencies: @@ -10985,7 +11063,7 @@ snapshots: parse-json@8.3.0: dependencies: '@babel/code-frame': 7.27.1 - index-to-position: 1.1.0 + index-to-position: 1.2.0 type-fest: 4.41.0 parse-semver@1.1.1: @@ -11033,7 +11111,7 @@ snapshots: path-scurry@2.0.0: dependencies: - lru-cache: 11.2.1 + lru-cache: 11.2.2 minipass: 7.1.2 path-to-regexp@8.3.0: {} @@ -11070,11 +11148,11 @@ snapshots: dependencies: find-up: 4.1.0 - playwright-core@1.55.0: {} + playwright-core@1.56.0: {} - playwright@1.55.0: + playwright@1.56.0: dependencies: - playwright-core: 1.55.0 + playwright-core: 1.56.0 optionalDependencies: fsevents: 2.3.2 @@ -11093,7 +11171,7 @@ snapshots: postcss-colormin@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.5.6 @@ -11101,7 +11179,7 @@ snapshots: postcss-convert-values@7.0.7(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -11141,7 +11219,7 @@ snapshots: postcss-merge-rules@7.0.6(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 caniuse-api: 3.0.0 cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 @@ -11161,7 +11239,7 @@ snapshots: postcss-minify-params@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 cssnano-utils: 5.0.1(postcss@8.5.6) postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -11224,7 +11302,7 @@ snapshots: postcss-normalize-unicode@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -11251,7 +11329,7 @@ snapshots: postcss-reduce-initial@7.0.4(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 caniuse-api: 3.0.0 postcss: 8.5.6 @@ -11290,13 +11368,13 @@ snapshots: prebuild-install@7.1.3: dependencies: - detect-libc: 2.1.0 + detect-libc: 2.1.2 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 - node-abi: 3.77.0 + node-abi: 3.78.0 pump: 3.0.3 rc: 1.2.8 simple-get: 4.0.1 @@ -11346,7 +11424,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.14.15 + '@types/node': 20.16.15 long: 5.3.2 pump@2.0.1: @@ -11405,13 +11483,13 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-bootstrap@2.10.7(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-bootstrap@2.10.7(@types/react@19.0.14)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.28.4 '@restart/hooks': 0.4.16(react@19.0.0) '@restart/ui': 1.9.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@types/prop-types': 15.7.15 - '@types/react-transition-group': 4.4.12(@types/react@19.0.12) + '@types/react-transition-group': 4.4.12(@types/react@19.0.14) classnames: 2.5.1 dom-helpers: 5.2.1 invariant: 2.2.4 @@ -11423,7 +11501,7 @@ snapshots: uncontrollable: 7.2.1(react@19.0.0) warning: 4.0.3 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.0.14 react-dom@19.0.0(react@19.0.0): dependencies: @@ -11460,7 +11538,7 @@ snapshots: '@npmcli/fs': 3.1.1 debug: 4.4.3(supports-color@8.1.1) read-package-json: 6.0.4 - semver: 7.7.2 + semver: 7.7.3 slide: 1.1.6 optionalDependencies: graceful-fs: 4.2.11 @@ -11612,6 +11690,18 @@ snapshots: dependencies: glob: 7.2.3 + rs-module-lexer@2.6.0: + optionalDependencies: + '@xn-sakina/rml-darwin-arm64': 2.6.0 + '@xn-sakina/rml-darwin-x64': 2.6.0 + '@xn-sakina/rml-linux-arm-gnueabihf': 2.6.0 + '@xn-sakina/rml-linux-arm64-gnu': 2.6.0 + '@xn-sakina/rml-linux-arm64-musl': 2.6.0 + '@xn-sakina/rml-linux-x64-gnu': 2.6.0 + '@xn-sakina/rml-linux-x64-musl': 2.6.0 + '@xn-sakina/rml-win32-arm64-msvc': 2.6.0 + '@xn-sakina/rml-win32-x64-msvc': 2.6.0 + run-applescript@7.1.0: {} run-parallel@1.2.0: @@ -11732,15 +11822,15 @@ snapshots: sass-embedded-win32-ia32: 1.77.8 sass-embedded-win32-x64: 1.77.8 - sass-loader@16.0.5(sass-embedded@1.77.8)(sass@1.90.0)(webpack@5.101.3): + sass-loader@16.0.5(sass-embedded@1.77.8)(sass@1.93.2)(webpack@5.102.1): dependencies: neo-async: 2.6.2 optionalDependencies: - sass: 1.90.0 + sass: 1.93.2 sass-embedded: 1.77.8 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - sass@1.90.0: + sass@1.93.2: dependencies: chokidar: 4.0.3 immutable: 5.1.3 @@ -11758,7 +11848,7 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) - schema-utils@4.3.2: + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 ajv: 8.17.1 @@ -11782,7 +11872,7 @@ snapshots: semver@6.3.1: optional: true - semver@7.7.2: {} + semver@7.7.3: {} serialize-javascript@6.0.2: dependencies: @@ -11825,34 +11915,34 @@ snapshots: dependencies: kind-of: 6.0.3 - sharp@0.34.3: + sharp@0.34.4: dependencies: - color: 4.2.3 - detect-libc: 2.1.0 - semver: 7.7.2 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 shebang-command@2.0.0: dependencies: @@ -11910,10 +12000,6 @@ snapshots: simple-invariant@2.0.1: {} - simple-swizzle@0.2.4: - dependencies: - is-arrayish: 0.3.4 - sinon@21.0.0: dependencies: '@sinonjs/commons': 3.0.1 @@ -12030,7 +12116,7 @@ snapshots: streamx@2.23.0: dependencies: - events-universal: 1.0.0 + events-universal: 1.0.1 fast-fifo: 1.3.2 text-decoder: 1.2.3 transitivePeerDependencies: @@ -12112,10 +12198,12 @@ snapshots: stylehacks@7.0.6(postcss@8.5.6): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 postcss: 8.5.6 postcss-selector-parser: 7.1.0 + supports-color@10.2.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -12124,8 +12212,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@9.4.0: {} - supports-hyperlinks@3.2.0: dependencies: has-flag: 4.0.0 @@ -12171,7 +12257,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tapable@2.2.3: {} + tapable@2.3.0: {} tar-fs@2.1.4: dependencies: @@ -12186,7 +12272,7 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 4.4.4 + bare-fs: 4.4.7 bare-path: 3.0.0 transitivePeerDependencies: - bare-buffer @@ -12203,7 +12289,7 @@ snapshots: tar-stream@3.1.7: dependencies: - b4a: 1.7.1 + b4a: 1.7.3 fast-fifo: 1.3.2 streamx: 2.23.0 transitivePeerDependencies: @@ -12220,17 +12306,17 @@ snapshots: terminal-link@4.0.0: dependencies: - ansi-escapes: 7.1.0 + ansi-escapes: 7.1.1 supports-hyperlinks: 3.2.0 - terser-webpack-plugin@5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.101.3): + terser-webpack-plugin@5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.102.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.0 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) optionalDependencies: '@swc/core': 1.13.5(@swc/helpers@0.5.17) esbuild: 0.25.10 @@ -12242,15 +12328,15 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: + test-exclude@7.0.1: dependencies: '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 + glob: 10.4.5 + minimatch: 9.0.5 text-decoder@1.2.3: dependencies: - b4a: 1.7.1 + b4a: 1.7.3 transitivePeerDependencies: - react-native-b4a @@ -12293,19 +12379,19 @@ snapshots: trim-newlines@4.1.1: {} - ts-api-utils@2.1.0(typescript@5.9.2): + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: - typescript: 5.9.2 + typescript: 5.9.3 - ts-loader@9.5.4(typescript@5.9.2)(webpack@5.101.3): + ts-loader@9.5.4(typescript@5.9.3)(webpack@5.102.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.18.3 micromatch: 4.0.8 - semver: 7.7.2 + semver: 7.7.3 source-map: 0.7.6 - typescript: 5.9.2 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + typescript: 5.9.3 + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) tsconfig-paths@3.15.0: dependencies: @@ -12406,14 +12492,14 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.7 - typescript-eslint@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2): + typescript-eslint@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - '@typescript-eslint/parser': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.45.0(eslint@9.36.0(jiti@2.4.0))(typescript@5.9.2) - eslint: 9.36.0(jiti@2.4.0) - typescript: 5.9.2 + '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + eslint: 9.37.0(jiti@2.4.0) + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -12421,7 +12507,7 @@ snapshots: typescript@5.4.5: {} - typescript@5.9.2: {} + typescript@5.9.3: {} typical@4.0.0: {} @@ -12441,7 +12527,7 @@ snapshots: uncontrollable@7.2.1(react@19.0.0): dependencies: '@babel/runtime': 7.28.4 - '@types/react': 19.0.12 + '@types/react': 19.0.14 invariant: 2.2.4 react: 19.0.0 react-lifecycles-compat: 3.0.4 @@ -12452,7 +12538,7 @@ snapshots: underscore@1.13.7: {} - undici-types@5.26.5: {} + undici-types@6.19.8: {} unfetch@4.2.0: {} @@ -12474,7 +12560,7 @@ snapshots: unrs-resolver@1.11.1: dependencies: - napi-postinstall: 0.3.3 + napi-postinstall: 0.3.4 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 @@ -12496,9 +12582,9 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - update-browserslist-db@1.1.3(browserslist@4.26.2): + update-browserslist-db@1.1.3(browserslist@4.26.3): dependencies: - browserslist: 4.26.2 + browserslist: 4.26.3 escalade: 3.2.0 picocolors: 1.1.1 @@ -12562,21 +12648,21 @@ snapshots: - bufferutil - utf-8-validate - webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3): + webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1): dependencies: '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.101.3) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.101.3) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.101.3) + '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.102.1) + '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.102.1) + '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.102.1) colorette: 2.0.20 commander: 12.1.0 cross-spawn: 7.0.6 - envinfo: 7.14.0 + envinfo: 7.17.0 fastest-levenshtein: 1.0.16 import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) + webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) webpack-merge: 6.0.1 optionalDependencies: webpack-bundle-analyzer: 4.10.2 @@ -12589,9 +12675,9 @@ snapshots: webpack-node-externals@3.0.0: {} - webpack-require-from@1.8.6(tapable@2.2.3): + webpack-require-from@1.8.6(tapable@2.3.0): dependencies: - tapable: 2.2.3 + tapable: 2.3.0 webpack-sources@1.4.3: dependencies: @@ -12600,7 +12686,7 @@ snapshots: webpack-sources@3.3.3: {} - webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1): + webpack@5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -12610,7 +12696,7 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.2 + browserslist: 4.26.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.3 es-module-lexer: 1.7.0 @@ -12619,16 +12705,16 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.3 - terser-webpack-plugin: 5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.101.3) + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.14(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack@5.102.1) watchpack: 2.4.4 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.101.3) + webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.102.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -12656,7 +12742,7 @@ snapshots: is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 + is-generator-function: 1.1.2 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fe4ab98c4af42..fe45a55ee2ab1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,4 @@ minimumReleaseAge: 10080 minimumReleaseAgeExclude: - '@gitkraken/*' - '@typescript-eslint/*' - - '@vscode/vsce' - - 'billboard.js' - 'typescript-eslint' From 6c7a6040f3f8155534d41c33d49086e9360282bc Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 01:41:36 -0400 Subject: [PATCH 22/83] Improves command type generation script - Groups commands by their contribution points - Tracks unused/orphaned commands Cleans up orphaned and internal commands Adds `gitlens.showQuickCommitDetails` to the command palette Adds keybinding support for launchpad copy action (ctrl+c / cmd+c) --- contributions.json | 39 ++----- package.json | 73 ++------------ scripts/generateCommandTypes.mts | 60 +++++++++-- src/commands/showQuickCommit.ts | 14 +-- src/constants.commands.generated.ts | 140 ++++++++++++++++++++------ src/constants.commands.ts | 7 ++ src/webviews/settings/registration.ts | 1 - 7 files changed, 189 insertions(+), 145 deletions(-) diff --git a/contributions.json b/contributions.json index 41f09ba47af95..4de4e6671671b 100644 --- a/contributions.json +++ b/contributions.json @@ -370,10 +370,6 @@ ] } }, - "gitlens.ai.undoGenerateRebase": { - "label": "Undo AI Generated Changes (Preview)...", - "icon": "$(discard)" - }, "gitlens.annotations.nextChange": { "label": "Next Change", "icon": "$(arrow-down)" @@ -3348,9 +3344,6 @@ ] } }, - "gitlens.openCloudPatch": { - "label": "Open Cloud Patch..." - }, "gitlens.openCommitOnRemote": { "label": "Open Commit on Remote", "icon": "$(globe)", @@ -4241,10 +4234,6 @@ ] } }, - "gitlens.showInCommitGraphView": { - "label": "Open in Commit Graph", - "icon": "$(gitlens-graph)" - }, "gitlens.showInDetailsView": { "label": "Inspect Details", "icon": "$(eye)", @@ -4344,7 +4333,8 @@ "commandPalette": "gitlens:enabled" }, "gitlens.showQuickCommitDetails": { - "label": "Quick Show Commit" + "label": "Quick Show Commit", + "commandPalette": "resource in gitlens:tabs:blameable" }, "gitlens.showQuickCommitFileDetails": { "label": "Quick Show Line Commit", @@ -4947,10 +4937,6 @@ ] } }, - "gitlens.showSettingsPage!views": { - "label": "Open Settings", - "icon": "$(gear)" - }, "gitlens.showSettingsPage!worktrees-view": { "label": "Open View Settings", "icon": "$(gear)", @@ -5585,10 +5571,6 @@ ] } }, - "gitlens.toggleFileChangesOnly": { - "label": "Toggle File Changes", - "icon": "$(gitlens-gitlens)" - }, "gitlens.toggleFileHeatmap": { "label": "Toggle File Heatmap", "icon": "$(gitlens-gitlens)", @@ -5850,11 +5832,6 @@ ] } }, - "gitlens.views.addPullRequestRemote": { - "label": "Add Pull Request Remote", - "icon": "$(add)", - "enablement": "!operationInProgress" - }, "gitlens.views.addRemote": { "label": "Add Remote...", "icon": "$(add)", @@ -9392,7 +9369,14 @@ } }, "gitlens.views.launchpad.copy": { - "label": "Copy" + "label": "Copy", + "keybindings": [ + { + "key": "ctrl+c", + "when": "focusedView == gitlens.views.launchpad", + "mac": "cmd+c" + } + ] }, "gitlens.views.launchpad.info": { "label": "Learn about Launchpad...", @@ -9793,9 +9777,6 @@ ] } }, - "gitlens.views.loadMoreChildren": { - "label": "Load More" - }, "gitlens.views.mergeBranchInto": { "label": "Merge Branch into Current Branch...", "enablement": "!operationInProgress", diff --git a/package.json b/package.json index 510f144b36763..58a22fe4b9e1c 100644 --- a/package.json +++ b/package.json @@ -6340,11 +6340,6 @@ "command": "gitlens.ai.switchProvider:scm", "title": "Switch GitLens AI Provider/Model..." }, - { - "command": "gitlens.ai.undoGenerateRebase", - "title": "Undo AI Generated Changes (Preview)...", - "icon": "$(discard)" - }, { "command": "gitlens.annotations.nextChange", "title": "Next Change", @@ -7531,10 +7526,6 @@ "title": "Open Changed Files", "category": "GitLens" }, - { - "command": "gitlens.openCloudPatch", - "title": "Open Cloud Patch..." - }, { "command": "gitlens.openCommitOnRemote", "title": "Open Commit on Remote", @@ -7858,11 +7849,6 @@ "title": "Open in Commit Graph", "icon": "$(gitlens-graph)" }, - { - "command": "gitlens.showInCommitGraphView", - "title": "Open in Commit Graph", - "icon": "$(gitlens-graph)" - }, { "command": "gitlens.showInDetailsView", "title": "Inspect Details", @@ -7908,7 +7894,8 @@ }, { "command": "gitlens.showQuickCommitDetails", - "title": "Quick Show Commit" + "title": "Quick Show Commit", + "category": "GitLens" }, { "command": "gitlens.showQuickCommitFileDetails", @@ -8041,11 +8028,6 @@ "title": "Open View Settings", "icon": "$(gear)" }, - { - "command": "gitlens.showSettingsPage!views", - "title": "Open Settings", - "icon": "$(gear)" - }, { "command": "gitlens.showSettingsPage!worktrees-view", "title": "Open View Settings", @@ -8278,11 +8260,6 @@ "title": "Toggle File Changes", "icon": "$(gitlens-gitlens)" }, - { - "command": "gitlens.toggleFileChangesOnly", - "title": "Toggle File Changes", - "icon": "$(gitlens-gitlens)" - }, { "command": "gitlens.toggleFileHeatmap", "title": "Toggle File Heatmap", @@ -8381,12 +8358,6 @@ "title": "Add Co-authors...", "icon": "$(person-add)" }, - { - "command": "gitlens.views.addPullRequestRemote", - "title": "Add Pull Request Remote", - "icon": "$(add)", - "enablement": "!operationInProgress" - }, { "command": "gitlens.views.addRemote", "title": "Add Remote...", @@ -9140,10 +9111,6 @@ "title": "Load All", "icon": "$(gitlens-expand)" }, - { - "command": "gitlens.views.loadMoreChildren", - "title": "Load More" - }, { "command": "gitlens.views.mergeBranchInto", "title": "Merge Branch into Current Branch...", @@ -11124,10 +11091,6 @@ "command": "gitlens.ai.switchProvider:scm", "when": "false" }, - { - "command": "gitlens.ai.undoGenerateRebase", - "when": "false" - }, { "command": "gitlens.annotations.nextChange", "when": "false" @@ -12064,10 +12027,6 @@ "command": "gitlens.openChangedFiles", "when": "gitlens:enabled" }, - { - "command": "gitlens.openCloudPatch", - "when": "false" - }, { "command": "gitlens.openCommitOnRemote", "when": "gitlens:repos:withRemotes" @@ -12288,10 +12247,6 @@ "command": "gitlens.showInCommitGraph", "when": "false" }, - { - "command": "gitlens.showInCommitGraphView", - "when": "false" - }, { "command": "gitlens.showInDetailsView", "when": "false" @@ -12326,7 +12281,7 @@ }, { "command": "gitlens.showQuickCommitDetails", - "when": "false" + "when": "resource in gitlens:tabs:blameable" }, { "command": "gitlens.showQuickCommitFileDetails", @@ -12420,10 +12375,6 @@ "command": "gitlens.showSettingsPage!tags-view", "when": "false" }, - { - "command": "gitlens.showSettingsPage!views", - "when": "false" - }, { "command": "gitlens.showSettingsPage!worktrees-view", "when": "false" @@ -12588,10 +12539,6 @@ "command": "gitlens.toggleFileChanges:editor/title", "when": "false" }, - { - "command": "gitlens.toggleFileChangesOnly", - "when": "false" - }, { "command": "gitlens.toggleFileHeatmap", "when": "resource in gitlens:tabs:blameable || config.gitlens.heatmap.toggleMode == window" @@ -12668,10 +12615,6 @@ "command": "gitlens.views.addAuthors", "when": "false" }, - { - "command": "gitlens.views.addPullRequestRemote", - "when": "false" - }, { "command": "gitlens.views.addRemote", "when": "false" @@ -13296,10 +13239,6 @@ "command": "gitlens.views.loadAllChildren", "when": "false" }, - { - "command": "gitlens.views.loadMoreChildren", - "when": "false" - }, { "command": "gitlens.views.mergeBranchInto", "when": "false" @@ -24183,6 +24122,12 @@ "when": "focusedView == gitlens.views.fileHistory", "mac": "cmd+c" }, + { + "command": "gitlens.views.launchpad.copy", + "key": "ctrl+c", + "when": "focusedView == gitlens.views.launchpad", + "mac": "cmd+c" + }, { "command": "gitlens.views.lineHistory.copy", "key": "ctrl+c", diff --git a/scripts/generateCommandTypes.mts b/scripts/generateCommandTypes.mts index cb6320dfd0a9d..84c04e1bd1dc5 100644 --- a/scripts/generateCommandTypes.mts +++ b/scripts/generateCommandTypes.mts @@ -16,41 +16,81 @@ function generateCommandTypesFromContributions(): void { readFileSync(path.join(__dirname, 'contributions.json'), 'utf8'), ); - const commands: string[] = []; - const kbCommands: string[] = []; - const paletteCommands: string[] = []; + const commands = new Set(); + const paletteCommands = new Set(); + const kbCommands = new Set(); + const internalCommands = new Set(); + let internal: boolean; for (const [id, command] of Object.entries(contributions.commands)) { + internal = true; + if (command.menus) { + internal = false; + commands.add(id); + + for (const menus of Object.values(command.menus)) { + for (const menu of menus) { + if (menu.alt) { + commands.add(menu.alt); + } + } + } + } + if (command.commandPalette) { - paletteCommands.push(id); - } else { - commands.push(id); + internal = false; + paletteCommands.add(id); + } + + if (command.keybindings) { + internal = false; + kbCommands.add(id); + } + + if (internal) { + internalCommands.add(id); } } for (const kb of contributions.keybindings) { - kbCommands.push(kb.command); + kbCommands.add(kb.command); + } + + // Remove from internal any commands that are in other lists + for (const id of [...commands, ...paletteCommands, ...kbCommands]) { + internalCommands.delete(id); } const contents = `// This file is generated by (vscode-gitlens)/${relativeFilename} // Do not edit this file directly -export type ContributedCommands = ContributedKeybindingCommands | ContributedPaletteCommands | ${commands +export type ContributedCommands = ContributedKeybindingCommands | ContributedPaletteCommands | ContributedOrphansOrInternalCommands | ${[ + ...commands, + ] .sort() .map(c => `'${c}'`) .join(' | ')}; -export type ContributedPaletteCommands = ${paletteCommands +export type ContributedPaletteCommands = ${[...paletteCommands] .sort() .map(c => `'${c}'`) .join(' | ')}; -export type ContributedKeybindingCommands = ${kbCommands +export type ContributedKeybindingCommands = ${[...kbCommands] .filter(c => c.startsWith('gitlens.')) .sort() .map(c => `'${c}'`) .join(' | ')}; +/** + * Commands that are not contributed anywhere, not the command palette, menus (or alts), nor keybindings. + * Either their contribution point is missing or are simply internal and should be removed at some point + */ +export type ContributedOrphansOrInternalCommands = ${[...internalCommands] + .sort() + .map(c => `'${c}'`) + .join(' | ')}; + `; const file = path.join(__dirname, 'src', 'constants.commands.generated.ts'); diff --git a/src/commands/showQuickCommit.ts b/src/commands/showQuickCommit.ts index 136af74f87d2c..44a30b158e205 100644 --- a/src/commands/showQuickCommit.ts +++ b/src/commands/showQuickCommit.ts @@ -47,8 +47,7 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand { } if (context.type === 'viewItem') { - args = { ...args }; - args.sha = context.node.uri.sha; + args = { ...args, sha: context.node.uri.sha }; if (isCommandContextViewNodeHasCommit(context)) { args.commit = context.node.commit; @@ -59,6 +58,8 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand { } async execute(editor?: TextEditor, uri?: Uri, args?: ShowQuickCommitCommandArgs): Promise { + args = { ...args }; + let gitUri; let repoPath; if (args?.commit == null) { @@ -73,19 +74,14 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand { repoPath = gitUri.repoPath!; } } else { - if (args.sha == null) { - args.sha = args.commit.sha; - } + args.sha ??= args.commit.sha; gitUri = args.commit.getGitUri(); repoPath = args.commit.repoPath; - if (uri == null) { - uri = args.commit.file?.uri; - } + uri ??= args.commit.file?.uri; } - args = { ...args }; if (args.sha == null) { if (editor == null) return; diff --git a/src/constants.commands.generated.ts b/src/constants.commands.generated.ts index 2a6f47b1eab86..0b4338d9a462c 100644 --- a/src/constants.commands.generated.ts +++ b/src/constants.commands.generated.ts @@ -4,6 +4,8 @@ export type ContributedCommands = | ContributedKeybindingCommands | ContributedPaletteCommands + | ContributedOrphansOrInternalCommands + | 'gitlens.addAuthors' | 'gitlens.ai.explainBranch:graph' | 'gitlens.ai.explainBranch:views' | 'gitlens.ai.explainCommit:graph' @@ -24,43 +26,62 @@ export type ContributedCommands = | 'gitlens.ai.rebaseOntoCommit:graph' | 'gitlens.ai.rebaseOntoCommit:views' | 'gitlens.ai.switchProvider:scm' - | 'gitlens.ai.undoGenerateRebase' - | 'gitlens.annotations.nextChange' - | 'gitlens.annotations.previousChange' | 'gitlens.changeUpstream:graph' | 'gitlens.changeUpstream:views' + | 'gitlens.clearFileAnnotations' + | 'gitlens.closeUnchangedFiles' | 'gitlens.composeCommits:graph' | 'gitlens.composeCommits:scm' | 'gitlens.composeCommits:views' | 'gitlens.composer.refresh' | 'gitlens.computingFileAnnotations' + | 'gitlens.connectRemoteProvider' | 'gitlens.copyDeepLinkToBranch' | 'gitlens.copyDeepLinkToCommit' | 'gitlens.copyDeepLinkToComparison' | 'gitlens.copyDeepLinkToFile' | 'gitlens.copyDeepLinkToFileAtRevision' | 'gitlens.copyDeepLinkToLines' + | 'gitlens.copyDeepLinkToRepo' | 'gitlens.copyDeepLinkToTag' | 'gitlens.copyDeepLinkToWorkspace' + | 'gitlens.copyMessageToClipboard' | 'gitlens.copyPatchToClipboard:graph' | 'gitlens.copyPatchToClipboard:scm' | 'gitlens.copyPatchToClipboard:views' + | 'gitlens.copyRelativePathToClipboard' | 'gitlens.copyRemoteBranchUrl' | 'gitlens.copyRemoteBranchesUrl' + | 'gitlens.copyRemoteCommitUrl' | 'gitlens.copyRemoteComparisonUrl' + | 'gitlens.copyRemoteFileUrlFrom' + | 'gitlens.copyRemoteFileUrlToClipboard' | 'gitlens.copyRemoteFileUrlWithoutRange' | 'gitlens.copyRemotePullRequestUrl' | 'gitlens.copyRemoteRepositoryUrl' + | 'gitlens.copyShaToClipboard' | 'gitlens.copyWorkingChangesToWorktree:views' + | 'gitlens.createCloudPatch' + | 'gitlens.createPatch' + | 'gitlens.diffDirectory' + | 'gitlens.diffDirectoryWithHead' + | 'gitlens.diffFolderWithRevision' + | 'gitlens.diffFolderWithRevisionFrom' + | 'gitlens.diffLineWithPrevious' + | 'gitlens.diffLineWithWorking' | 'gitlens.diffWithNext:editor/title' - | 'gitlens.diffWithNext:key' | 'gitlens.diffWithPrevious:editor' | 'gitlens.diffWithPrevious:editor/title' | 'gitlens.diffWithPrevious:explorer' - | 'gitlens.diffWithPrevious:key' + | 'gitlens.diffWithRevision' + | 'gitlens.diffWithRevisionFrom' | 'gitlens.diffWithWorking:editor' | 'gitlens.diffWithWorking:editor/title' - | 'gitlens.diffWithWorking:key' + | 'gitlens.disconnectRemoteProvider' + | 'gitlens.externalDiff' + | 'gitlens.externalDiffAll' + | 'gitlens.fetchRepositories' + | 'gitlens.getStarted' | 'gitlens.ghpr.views.openOrCreateWorktree' | 'gitlens.graph.addAuthor' | 'gitlens.graph.associateIssueWithBranch' @@ -137,7 +158,6 @@ export type ContributedCommands = | 'gitlens.graph.publishBranch' | 'gitlens.graph.pull' | 'gitlens.graph.push' - | 'gitlens.graph.pushWithForce' | 'gitlens.graph.rebaseOntoBranch' | 'gitlens.graph.rebaseOntoCommit' | 'gitlens.graph.rebaseOntoUpstream' @@ -162,31 +182,54 @@ export type ContributedCommands = | 'gitlens.graph.scrollMarkerTagOn' | 'gitlens.graph.shareAsCloudPatch' | 'gitlens.graph.showInDetailsView' + | 'gitlens.graph.split' | 'gitlens.graph.switchToAnotherBranch' | 'gitlens.graph.switchToBranch' | 'gitlens.graph.switchToCommit' + | 'gitlens.graph.switchToEditorLayout' + | 'gitlens.graph.switchToPanelLayout' | 'gitlens.graph.switchToTag' | 'gitlens.graph.undoCommit' | 'gitlens.inviteToLiveShare' - | 'gitlens.openCloudPatch' + | 'gitlens.openBranchesOnRemote' + | 'gitlens.openChangedFiles' + | 'gitlens.openCommitOnRemote' | 'gitlens.openComparisonOnRemote' + | 'gitlens.openFileHistory' + | 'gitlens.openFileOnRemote' + | 'gitlens.openFileOnRemoteFrom' | 'gitlens.openFolderHistory' + | 'gitlens.openOnlyChangedFiles' + | 'gitlens.openPatch' | 'gitlens.openPullRequestOnRemote' + | 'gitlens.openRepoOnRemote' | 'gitlens.openRevisionFile:editor/title' | 'gitlens.openWorkingFile:editor/context' | 'gitlens.openWorkingFile:editor/title' - | 'gitlens.plus.cloudIntegrations.connect' + | 'gitlens.plus.login' + | 'gitlens.pullRepositories' + | 'gitlens.pushRepositories' + | 'gitlens.quickOpenFileHistory' | 'gitlens.regenerateMarkdownDocument' | 'gitlens.restore.file:views' | 'gitlens.restorePrevious.file:views' + | 'gitlens.revealCommitInView' | 'gitlens.setUpstream:graph' | 'gitlens.setUpstream:views' + | 'gitlens.shareAsCloudPatch' + | 'gitlens.showCommitSearch' + | 'gitlens.showCommitsInView' + | 'gitlens.showGraph' | 'gitlens.showInCommitGraph' - | 'gitlens.showInCommitGraphView' | 'gitlens.showInDetailsView' - | 'gitlens.showQuickCommitDetails' + | 'gitlens.showLineCommitInView' + | 'gitlens.showLineHistoryView' + | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickRevisionDetails:editor' | 'gitlens.showQuickRevisionDetails:editor/title' + | 'gitlens.showRepositoriesView' + | 'gitlens.showSettingsPage' + | 'gitlens.showSettingsPage!autolinks' | 'gitlens.showSettingsPage!branches-view' | 'gitlens.showSettingsPage!commit-graph' | 'gitlens.showSettingsPage!commits-view' @@ -199,7 +242,6 @@ export type ContributedCommands = | 'gitlens.showSettingsPage!search-compare-view' | 'gitlens.showSettingsPage!stashes-view' | 'gitlens.showSettingsPage!tags-view' - | 'gitlens.showSettingsPage!views' | 'gitlens.showSettingsPage!worktrees-view' | 'gitlens.star.branch.multi:views' | 'gitlens.star.branch:graph' @@ -215,16 +257,19 @@ export type ContributedCommands = | 'gitlens.stashRename:views' | 'gitlens.stashSave.files:scm' | 'gitlens.stashSave.files:views' + | 'gitlens.stashSave.staged:scm' + | 'gitlens.stashSave.unstaged:scm' | 'gitlens.stashSave:graph' + | 'gitlens.stashSave:scm' | 'gitlens.stashSave:views' | 'gitlens.stashesApply:views' | 'gitlens.timeline.refresh' + | 'gitlens.timeline.split' + | 'gitlens.toggleFileBlame' | 'gitlens.toggleFileBlame:editor' | 'gitlens.toggleFileBlame:editor/title' - | 'gitlens.toggleFileBlame:key' | 'gitlens.toggleFileChanges:editor' | 'gitlens.toggleFileChanges:editor/title' - | 'gitlens.toggleFileChangesOnly' | 'gitlens.toggleFileHeatmap:editor' | 'gitlens.toggleFileHeatmap:editor/title' | 'gitlens.toggleFileHeatmapInDiffLeft' @@ -238,12 +283,10 @@ export type ContributedCommands = | 'gitlens.views.addAuthor' | 'gitlens.views.addAuthor.multi' | 'gitlens.views.addAuthors' - | 'gitlens.views.addPullRequestRemote' | 'gitlens.views.addRemote' | 'gitlens.views.applyChanges' | 'gitlens.views.associateIssueWithBranch' | 'gitlens.views.branches.attach' - | 'gitlens.views.branches.copy' | 'gitlens.views.branches.refresh' | 'gitlens.views.branches.setFilesLayoutToAuto' | 'gitlens.views.branches.setFilesLayoutToList' @@ -273,7 +316,6 @@ export type ContributedCommands = | 'gitlens.views.collapseNode' | 'gitlens.views.commitDetails.refresh' | 'gitlens.views.commits.attach' - | 'gitlens.views.commits.copy' | 'gitlens.views.commits.refresh' | 'gitlens.views.commits.setCommitsFilterAuthors' | 'gitlens.views.commits.setCommitsFilterOff' @@ -301,7 +343,6 @@ export type ContributedCommands = | 'gitlens.views.compareWithWorking' | 'gitlens.views.continuePausedOperation' | 'gitlens.views.contributors.attach' - | 'gitlens.views.contributors.copy' | 'gitlens.views.contributors.refresh' | 'gitlens.views.contributors.setFilesLayoutToAuto' | 'gitlens.views.contributors.setFilesLayoutToList' @@ -334,7 +375,6 @@ export type ContributedCommands = | 'gitlens.views.dismissNode' | 'gitlens.views.draft.open' | 'gitlens.views.draft.openOnWeb' - | 'gitlens.views.drafts.copy' | 'gitlens.views.drafts.create' | 'gitlens.views.drafts.delete' | 'gitlens.views.drafts.info' @@ -346,7 +386,6 @@ export type ContributedCommands = | 'gitlens.views.fetch' | 'gitlens.views.fileHistory.attach' | 'gitlens.views.fileHistory.changeBase' - | 'gitlens.views.fileHistory.copy' | 'gitlens.views.fileHistory.refresh' | 'gitlens.views.fileHistory.setCursorFollowingOff' | 'gitlens.views.fileHistory.setCursorFollowingOn' @@ -378,7 +417,6 @@ export type ContributedCommands = | 'gitlens.views.home.refresh' | 'gitlens.views.home.whatsNew' | 'gitlens.views.launchpad.attach' - | 'gitlens.views.launchpad.copy' | 'gitlens.views.launchpad.info' | 'gitlens.views.launchpad.refresh' | 'gitlens.views.launchpad.setFilesLayoutToAuto' @@ -388,14 +426,12 @@ export type ContributedCommands = | 'gitlens.views.launchpad.setShowAvatarsOn' | 'gitlens.views.launchpad.viewOptionsTitle' | 'gitlens.views.lineHistory.changeBase' - | 'gitlens.views.lineHistory.copy' | 'gitlens.views.lineHistory.refresh' | 'gitlens.views.lineHistory.setEditorFollowingOff' | 'gitlens.views.lineHistory.setEditorFollowingOn' | 'gitlens.views.lineHistory.setShowAvatarsOff' | 'gitlens.views.lineHistory.setShowAvatarsOn' | 'gitlens.views.loadAllChildren' - | 'gitlens.views.loadMoreChildren' | 'gitlens.views.mergeBranchInto' | 'gitlens.views.mergeChangesWithWorking' | 'gitlens.views.openBranchOnRemote' @@ -437,7 +473,6 @@ export type ContributedCommands = | 'gitlens.views.publishRepository' | 'gitlens.views.pull' | 'gitlens.views.pullRequest.close' - | 'gitlens.views.pullRequest.copy' | 'gitlens.views.pullRequest.refresh' | 'gitlens.views.pullRequest.setFilesLayoutToAuto' | 'gitlens.views.pullRequest.setFilesLayoutToList' @@ -452,7 +487,6 @@ export type ContributedCommands = | 'gitlens.views.rebaseOntoUpstream' | 'gitlens.views.refreshNode' | 'gitlens.views.remotes.attach' - | 'gitlens.views.remotes.copy' | 'gitlens.views.remotes.refresh' | 'gitlens.views.remotes.setFilesLayoutToAuto' | 'gitlens.views.remotes.setFilesLayoutToList' @@ -467,7 +501,6 @@ export type ContributedCommands = | 'gitlens.views.removeRemote' | 'gitlens.views.renameBranch' | 'gitlens.views.repositories.attach' - | 'gitlens.views.repositories.copy' | 'gitlens.views.repositories.refresh' | 'gitlens.views.repositories.setAutoRefreshToOff' | 'gitlens.views.repositories.setAutoRefreshToOn' @@ -580,7 +613,6 @@ export type ContributedCommands = | 'gitlens.views.scm.grouped.worktrees.visibility.show' | 'gitlens.views.searchAndCompare.attach' | 'gitlens.views.searchAndCompare.clear' - | 'gitlens.views.searchAndCompare.copy' | 'gitlens.views.searchAndCompare.refresh' | 'gitlens.views.searchAndCompare.searchCommits' | 'gitlens.views.searchAndCompare.selectForCompare' @@ -609,7 +641,6 @@ export type ContributedCommands = | 'gitlens.views.stageDirectory' | 'gitlens.views.stageFile' | 'gitlens.views.stashes.attach' - | 'gitlens.views.stashes.copy' | 'gitlens.views.stashes.refresh' | 'gitlens.views.stashes.setFilesLayoutToAuto' | 'gitlens.views.stashes.setFilesLayoutToList' @@ -620,7 +651,6 @@ export type ContributedCommands = | 'gitlens.views.switchToCommit' | 'gitlens.views.switchToTag' | 'gitlens.views.tags.attach' - | 'gitlens.views.tags.copy' | 'gitlens.views.tags.refresh' | 'gitlens.views.tags.setFilesLayoutToAuto' | 'gitlens.views.tags.setFilesLayoutToList' @@ -642,7 +672,7 @@ export type ContributedCommands = | 'gitlens.views.workspaces.addReposFromLinked' | 'gitlens.views.workspaces.changeAutoAddSetting' | 'gitlens.views.workspaces.convert' - | 'gitlens.views.workspaces.copy' + | 'gitlens.views.workspaces.create' | 'gitlens.views.workspaces.createLocal' | 'gitlens.views.workspaces.delete' | 'gitlens.views.workspaces.info' @@ -656,7 +686,6 @@ export type ContributedCommands = | 'gitlens.views.workspaces.repo.openInNewWindow' | 'gitlens.views.workspaces.repo.remove' | 'gitlens.views.worktrees.attach' - | 'gitlens.views.worktrees.copy' | 'gitlens.views.worktrees.refresh' | 'gitlens.views.worktrees.setFilesLayoutToAuto' | 'gitlens.views.worktrees.setFilesLayoutToList' @@ -839,6 +868,7 @@ export type ContributedPaletteCommands = | 'gitlens.showLineHistoryView' | 'gitlens.showPatchDetailsPage' | 'gitlens.showQuickBranchHistory' + | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory' @@ -877,6 +907,11 @@ export type ContributedPaletteCommands = | 'gitlens.visualizeHistory.file'; export type ContributedKeybindingCommands = + | 'gitlens.diffLineWithPrevious' + | 'gitlens.diffWithNext:key' + | 'gitlens.diffWithPrevious:key' + | 'gitlens.diffWithWorking:key' + | 'gitlens.gitCommands' | 'gitlens.key.alt+,' | 'gitlens.key.alt+.' | 'gitlens.key.alt+enter' @@ -887,4 +922,45 @@ export type ContributedKeybindingCommands = | 'gitlens.key.ctrl+right' | 'gitlens.key.escape' | 'gitlens.key.left' - | 'gitlens.key.right'; + | 'gitlens.key.right' + | 'gitlens.showQuickCommitFileDetails' + | 'gitlens.showQuickFileHistory' + | 'gitlens.showQuickRepoHistory' + | 'gitlens.showQuickRepoStatus' + | 'gitlens.toggleCodeLens' + | 'gitlens.toggleFileBlame:key' + | 'gitlens.views.branches.copy' + | 'gitlens.views.commits.copy' + | 'gitlens.views.contributors.copy' + | 'gitlens.views.drafts.copy' + | 'gitlens.views.fileHistory.copy' + | 'gitlens.views.launchpad.copy' + | 'gitlens.views.lineHistory.copy' + | 'gitlens.views.pullRequest.copy' + | 'gitlens.views.remotes.copy' + | 'gitlens.views.repositories.copy' + | 'gitlens.views.scm.grouped.branches' + | 'gitlens.views.scm.grouped.commits' + | 'gitlens.views.scm.grouped.contributors' + | 'gitlens.views.scm.grouped.fileHistory' + | 'gitlens.views.scm.grouped.launchpad' + | 'gitlens.views.scm.grouped.remotes' + | 'gitlens.views.scm.grouped.searchAndCompare' + | 'gitlens.views.scm.grouped.stashes' + | 'gitlens.views.scm.grouped.tags' + | 'gitlens.views.scm.grouped.worktrees' + | 'gitlens.views.searchAndCompare.copy' + | 'gitlens.views.stashes.copy' + | 'gitlens.views.tags.copy' + | 'gitlens.views.workspaces.copy' + | 'gitlens.views.worktrees.copy'; + +/** + * Commands that are not contributed anywhere, not the command palette, menus (or alts), nor keybindings. + * Either their contribution point is missing or are simply internal and should be removed at some point + */ +export type ContributedOrphansOrInternalCommands = + | 'gitlens.annotations.nextChange' + | 'gitlens.annotations.previousChange' + | 'gitlens.graph.pushWithForce' + | 'gitlens.plus.cloudIntegrations.connect'; diff --git a/src/constants.commands.ts b/src/constants.commands.ts index b92c2f414180b..b1690a15b12ce 100644 --- a/src/constants.commands.ts +++ b/src/constants.commands.ts @@ -94,6 +94,8 @@ type InternalSearchAndCompareViewCommands = 'gitlens.views.searchAndCompare.comp type InternalTimelineWebviewViewCommands = 'gitlens.views.timeline.openInTab'; +type InternalViewCommands = 'gitlens.views.loadMoreChildren'; + type InternalWalkthroughCommands = | 'gitlens.walkthrough.connectIntegrations' | 'gitlens.walkthrough.enableAiSetting' @@ -128,6 +130,7 @@ type InternalGlCommands = | 'gitlens.ai.feedback.helpful' | 'gitlens.ai.feedback.unhelpful' | 'gitlens.ai.mcp.authCLI' + | 'gitlens.ai.undoGenerateRebase' | 'gitlens.changeBranchMergeTarget' | 'gitlens.diffWith' | 'gitlens.diffWithPrevious:codelens' @@ -135,12 +138,15 @@ type InternalGlCommands = | 'gitlens.diffWithPrevious:views' | 'gitlens.diffWithWorking:command' | 'gitlens.diffWithWorking:views' + | 'gitlens.openCloudPatch' | 'gitlens.openOnRemote' | 'gitlens.openWalkthrough' | 'gitlens.openWorkingFile:command' | 'gitlens.refreshHover' | 'gitlens.regenerateMarkdownDocument' | 'gitlens.showComposerPage' + | 'gitlens.showInCommitGraphView' + | 'gitlens.showQuickCommitDetails' | 'gitlens.storage.store' | 'gitlens.toggleFileBlame:codelens' | 'gitlens.toggleFileBlame:mode' @@ -161,6 +167,7 @@ type InternalGlCommands = | InternalScmGroupedViewCommands | InternalSearchAndCompareViewCommands | InternalTimelineWebviewViewCommands + | InternalViewCommands | InternalWalkthroughCommands; export type GlCommands = ContributedCommands | InternalGlCommands; // | GlCommandsDeprecated; diff --git a/src/webviews/settings/registration.ts b/src/webviews/settings/registration.ts index 6274cc56ff27a..38f613b96983e 100644 --- a/src/webviews/settings/registration.ts +++ b/src/webviews/settings/registration.ts @@ -53,7 +53,6 @@ export function registerSettingsWebviewCommands( 'gitlens.showSettingsPage!stashes-view', 'gitlens.showSettingsPage!tags-view', 'gitlens.showSettingsPage!worktrees-view', - 'gitlens.showSettingsPage!views', 'gitlens.showSettingsPage!commit-graph', 'gitlens.showSettingsPage!autolinks', ] satisfies GlCommands[] From 9dfce1502657f58e8acdb6287a8e1551c85ec222 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 01:46:28 -0400 Subject: [PATCH 23/83] Adds navigation commands to Changes Annotations - Adds "Next Change" and "Previous Change" to the editor toolbar --- contributions.json | 26 +++++++++++++--- package.json | 24 ++++++++++----- src/annotations/fileAnnotationController.ts | 33 ++++++++++++++------- src/constants.commands.generated.ts | 4 +-- src/constants.context.ts | 4 ++- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/contributions.json b/contributions.json index 4de4e6671671b..6021c43df0d8c 100644 --- a/contributions.json +++ b/contributions.json @@ -372,11 +372,29 @@ }, "gitlens.annotations.nextChange": { "label": "Next Change", - "icon": "$(arrow-down)" + "icon": "$(arrow-down)", + "menus": { + "editor/title": [ + { + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed:changes\\b/ || (resource in gitlens:tabs:annotated:changes && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "group": "navigation", + "order": -99 + } + ] + } }, "gitlens.annotations.previousChange": { "label": "Previous Change", - "icon": "$(arrow-up)" + "icon": "$(arrow-up)", + "menus": { + "editor/title": [ + { + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed:changes\\b/ || (resource in gitlens:tabs:annotated:changes && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "group": "navigation", + "order": -100 + } + ] + } }, "gitlens.applyPatchFromClipboard": { "label": "Apply Copied Changes (Patch)", @@ -449,7 +467,7 @@ "menus": { "editor/title": [ { - "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated == computed || (resource in gitlens:tabs:annotated && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed\\b/ || (resource in gitlens:tabs:annotated && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", "group": "navigation", "order": 100 } @@ -582,7 +600,7 @@ "menus": { "editor/title": [ { - "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated == computing || resource in gitlens:tabs:annotated:computing) && config.gitlens.menus.editorGroup.blame", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed\\b/ || resource in gitlens:tabs:annotated:computing) && config.gitlens.menus.editorGroup.blame", "group": "navigation", "order": 100 } diff --git a/package.json b/package.json index 58a22fe4b9e1c..2238681244665 100644 --- a/package.json +++ b/package.json @@ -14476,6 +14476,16 @@ } ], "editor/title": [ + { + "command": "gitlens.annotations.previousChange", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed:changes\\b/ || (resource in gitlens:tabs:annotated:changes && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "group": "navigation@-100" + }, + { + "command": "gitlens.annotations.nextChange", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed:changes\\b/ || (resource in gitlens:tabs:annotated:changes && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "group": "navigation@-99" + }, { "command": "gitlens.composer.refresh", "when": "activeWebviewPanelId === gitlens.composer", @@ -14491,6 +14501,11 @@ "when": "activeWebviewPanelId === gitlens.timeline", "group": "navigation@-99" }, + { + "submenu": "gitlens/graph/configuration", + "when": "activeWebviewPanelId === gitlens.graph", + "group": "navigation@-98" + }, { "command": "gitlens.graph.split", "when": "activeWebviewPanelId == gitlens.graph && resourceScheme == webview-panel && config.gitlens.graph.allowMultiple", @@ -14503,12 +14518,12 @@ }, { "command": "gitlens.clearFileAnnotations", - "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated == computed || (resource in gitlens:tabs:annotated && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed\\b/ || (resource in gitlens:tabs:annotated && resource not in gitlens:tabs:annotated:computing)) && config.gitlens.menus.editorGroup.blame", "group": "navigation@100" }, { "command": "gitlens.computingFileAnnotations", - "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated == computing || resource in gitlens:tabs:annotated:computing) && config.gitlens.menus.editorGroup.blame", + "when": "resource in gitlens:tabs:blameable && (gitlens:window:annotated =~ /computed\\b/ || resource in gitlens:tabs:annotated:computing) && config.gitlens.menus.editorGroup.blame", "group": "navigation@100" }, { @@ -14565,11 +14580,6 @@ "when": "resourceScheme =~ /^(gitlens|pr)$/ && gitlens:enabled", "group": "navigation@-98" }, - { - "submenu": "gitlens/graph/configuration", - "when": "activeWebviewPanelId === gitlens.graph", - "group": "navigation@-98" - }, { "command": "gitlens.openRevisionFile:editor/title", "when": "resourceScheme =~ /^(gitlens|pr)$/ && gitlens:enabled && isInDiffEditor", diff --git a/src/annotations/fileAnnotationController.ts b/src/annotations/fileAnnotationController.ts index 0340250cfa071..688cc20183971 100644 --- a/src/annotations/fileAnnotationController.ts +++ b/src/annotations/fileAnnotationController.ts @@ -334,10 +334,12 @@ export class FileAnnotationController implements Disposable { } private readonly _annotatedUris = new UriSet(); + private readonly _annotatedChangesUris = new UriSet(); private readonly _computingUris = new UriSet(); async onProviderEditorStatusChanged( editor: TextEditor | undefined, + annotationType: FileAnnotationType | undefined, status: AnnotationStatus | undefined, ): Promise { if (editor == null) return; @@ -346,10 +348,11 @@ export class FileAnnotationController implements Disposable { let windowStatus; if (this.isInWindowToggle()) { - windowStatus = status; + windowStatus = status ? (annotationType ? (`${status}:${annotationType}` as const) : status) : undefined; changed = Boolean(this._annotatedUris.size || this._computingUris.size); this._annotatedUris.clear(); + this._annotatedChangesUris.clear(); this._computingUris.clear(); } else { windowStatus = undefined; @@ -373,11 +376,19 @@ export class FileAnnotationController implements Disposable { if (provider == null) { if (this._annotatedUris.has(uri)) { this._annotatedUris.delete(uri); + this._annotatedChangesUris.delete(uri); + changed = true; + } + } else { + if (!this._annotatedUris.has(uri)) { + this._annotatedUris.add(uri); + changed = true; + } + + if (provider.annotationType === 'changes' && !this._annotatedChangesUris.has(uri)) { + this._annotatedChangesUris.add(uri); changed = true; } - } else if (!this._annotatedUris.has(uri)) { - this._annotatedUris.add(uri); - changed = true; } if (this._computingUris.has(uri)) { @@ -389,6 +400,7 @@ export class FileAnnotationController implements Disposable { default: if (this._annotatedUris.has(uri)) { this._annotatedUris.delete(uri); + this._annotatedChangesUris.delete(uri); changed = true; } @@ -406,6 +418,7 @@ export class FileAnnotationController implements Disposable { setContext('gitlens:window:annotated', windowStatus), setContext('gitlens:tabs:annotated:computing', [...this._computingUris]), setContext('gitlens:tabs:annotated', [...this._annotatedUris]), + setContext('gitlens:tabs:annotated:changes', [...this._annotatedChangesUris]), ]); } @@ -463,12 +476,12 @@ export class FileAnnotationController implements Disposable { const provider = await window.withProgress( { location: ProgressLocation.Window }, async (progress: Progress<{ message: string }>) => { - void this.onProviderEditorStatusChanged(editor, 'computing'); + void this.onProviderEditorStatusChanged(editor, type, 'computing'); const computingAnnotations = this.showAnnotationsCore(currentProvider, editor, type, context, progress); void (await computingAnnotations); - void this.onProviderEditorStatusChanged(editor, 'computed'); + void this.onProviderEditorStatusChanged(editor, type, 'computed'); return computingAnnotations; }, @@ -574,7 +587,7 @@ export class FileAnnotationController implements Disposable { if (!this._annotationProviders.size || key === getEditorCorrelationKey(this._editor)) { if (this._editor != null) { - void this.onProviderEditorStatusChanged(this._editor, undefined); + void this.onProviderEditorStatusChanged(this._editor, undefined, undefined); } await this.detachKeyboardHook(); @@ -636,7 +649,7 @@ export class FileAnnotationController implements Disposable { ); provider = new GutterBlameAnnotationProvider( this.container, - e => this.onProviderEditorStatusChanged(e.editor, e.status), + e => this.onProviderEditorStatusChanged(e.editor, type, e.status), editor, trackedDocument, ); @@ -648,7 +661,7 @@ export class FileAnnotationController implements Disposable { ); provider = new GutterChangesAnnotationProvider( this.container, - e => this.onProviderEditorStatusChanged(e.editor, e.status), + e => this.onProviderEditorStatusChanged(e.editor, type, e.status), editor, trackedDocument, ); @@ -660,7 +673,7 @@ export class FileAnnotationController implements Disposable { ); provider = new GutterHeatmapBlameAnnotationProvider( this.container, - e => this.onProviderEditorStatusChanged(e.editor, e.status), + e => this.onProviderEditorStatusChanged(e.editor, type, e.status), editor, trackedDocument, ); diff --git a/src/constants.commands.generated.ts b/src/constants.commands.generated.ts index 0b4338d9a462c..5361baf30bdc6 100644 --- a/src/constants.commands.generated.ts +++ b/src/constants.commands.generated.ts @@ -26,6 +26,8 @@ export type ContributedCommands = | 'gitlens.ai.rebaseOntoCommit:graph' | 'gitlens.ai.rebaseOntoCommit:views' | 'gitlens.ai.switchProvider:scm' + | 'gitlens.annotations.nextChange' + | 'gitlens.annotations.previousChange' | 'gitlens.changeUpstream:graph' | 'gitlens.changeUpstream:views' | 'gitlens.clearFileAnnotations' @@ -960,7 +962,5 @@ export type ContributedKeybindingCommands = * Either their contribution point is missing or are simply internal and should be removed at some point */ export type ContributedOrphansOrInternalCommands = - | 'gitlens.annotations.nextChange' - | 'gitlens.annotations.previousChange' | 'gitlens.graph.pushWithForce' | 'gitlens.plus.cloudIntegrations.connect'; diff --git a/src/constants.context.ts b/src/constants.context.ts index 62d2b717a0754..9bbf188f2b7a7 100644 --- a/src/constants.context.ts +++ b/src/constants.context.ts @@ -1,4 +1,5 @@ import type { Uri } from 'vscode'; +import type { FileAnnotationType } from './config'; import type { AnnotationStatus, Keys } from './constants'; import type { SubscriptionState } from './constants.subscription'; import type { CustomEditorTypes, GroupableTreeViewTypes, WebviewTypes, WebviewViewTypes } from './constants.views'; @@ -42,6 +43,7 @@ export type ContextKeys = { 'gitlens:tabs:ai:unhelpful': Uri[]; 'gitlens:tabs:ai:changelog': Uri[]; 'gitlens:tabs:annotated': Uri[]; + 'gitlens:tabs:annotated:changes': Uri[]; 'gitlens:tabs:annotated:computing': Uri[]; 'gitlens:tabs:blameable': Uri[]; 'gitlens:tabs:tracked': Uri[]; @@ -63,7 +65,7 @@ export type ContextKeys = { 'gitlens:views:scm:grouped:view': GroupableTreeViewTypes; 'gitlens:views:scm:grouped:welcome': boolean; 'gitlens:vsls': boolean | 'host' | 'guest'; - 'gitlens:window:annotated': AnnotationStatus; + 'gitlens:window:annotated': AnnotationStatus | `${AnnotationStatus}:${FileAnnotationType}`; 'gitlens:walkthroughSupported': boolean; } & Record<`gitlens:action:${string}`, number> & Record<`gitlens:feature:unsupported:${Features}`, boolean> & From 47038c9e87f3297bab2cfc41a31223cbf0112cb9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 02:14:08 -0400 Subject: [PATCH 24/83] Fixes copy shortcut key on grouped views --- contributions.json | 22 +++++++++++----------- package.json | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/contributions.json b/contributions.json index 6021c43df0d8c..ad619c838fb8f 100644 --- a/contributions.json +++ b/contributions.json @@ -5947,7 +5947,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.branches", + "when": "focusedView == gitlens.views.branches || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches)", "mac": "cmd+c" } ] @@ -6753,7 +6753,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.commits", + "when": "focusedView == gitlens.views.commits || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == commits)", "mac": "cmd+c" } ] @@ -7538,7 +7538,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.contributors", + "when": "focusedView == gitlens.views.contributors || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == contributors)", "mac": "cmd+c" } ] @@ -8623,7 +8623,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.fileHistory", + "when": "focusedView == gitlens.views.fileHistory || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == fileHistory)", "mac": "cmd+c" } ] @@ -9391,7 +9391,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.launchpad", + "when": "focusedView == gitlens.views.launchpad || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == launchpad)", "mac": "cmd+c" } ] @@ -10889,7 +10889,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.remotes", + "when": "focusedView == gitlens.views.remotes || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == remotes)", "mac": "cmd+c" } ] @@ -11317,7 +11317,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.repositories", + "when": "focusedView == gitlens.views.repositories || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == repositories)", "mac": "cmd+c" } ] @@ -13552,7 +13552,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.searchAndCompare", + "when": "focusedView == gitlens.views.searchAndCompare || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == searchAndCompare)", "mac": "cmd+c" } ] @@ -14565,7 +14565,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.stashes", + "when": "focusedView == gitlens.views.stashes || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == stashes)", "mac": "cmd+c" } ] @@ -14871,7 +14871,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.tags", + "when": "focusedView == gitlens.views.tags || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == tags)", "mac": "cmd+c" } ] @@ -15678,7 +15678,7 @@ "keybindings": [ { "key": "ctrl+c", - "when": "focusedView == gitlens.views.worktrees", + "when": "focusedView == gitlens.views.worktrees || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == worktrees)", "mac": "cmd+c" } ] diff --git a/package.json b/package.json index 2238681244665..7bb073d0f3e20 100644 --- a/package.json +++ b/package.json @@ -24105,19 +24105,19 @@ { "command": "gitlens.views.branches.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.branches", + "when": "focusedView == gitlens.views.branches || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches)", "mac": "cmd+c" }, { "command": "gitlens.views.commits.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.commits", + "when": "focusedView == gitlens.views.commits || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == commits)", "mac": "cmd+c" }, { "command": "gitlens.views.contributors.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.contributors", + "when": "focusedView == gitlens.views.contributors || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == contributors)", "mac": "cmd+c" }, { @@ -24129,13 +24129,13 @@ { "command": "gitlens.views.fileHistory.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.fileHistory", + "when": "focusedView == gitlens.views.fileHistory || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == fileHistory)", "mac": "cmd+c" }, { "command": "gitlens.views.launchpad.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.launchpad", + "when": "focusedView == gitlens.views.launchpad || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == launchpad)", "mac": "cmd+c" }, { @@ -24153,13 +24153,13 @@ { "command": "gitlens.views.remotes.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.remotes", + "when": "focusedView == gitlens.views.remotes || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == remotes)", "mac": "cmd+c" }, { "command": "gitlens.views.repositories.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.repositories", + "when": "focusedView == gitlens.views.repositories || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == repositories)", "mac": "cmd+c" }, { @@ -24215,19 +24215,19 @@ { "command": "gitlens.views.searchAndCompare.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.searchAndCompare", + "when": "focusedView == gitlens.views.searchAndCompare || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == searchAndCompare)", "mac": "cmd+c" }, { "command": "gitlens.views.stashes.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.stashes", + "when": "focusedView == gitlens.views.stashes || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == stashes)", "mac": "cmd+c" }, { "command": "gitlens.views.tags.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.tags", + "when": "focusedView == gitlens.views.tags || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == tags)", "mac": "cmd+c" }, { @@ -24239,7 +24239,7 @@ { "command": "gitlens.views.worktrees.copy", "key": "ctrl+c", - "when": "focusedView == gitlens.views.worktrees", + "when": "focusedView == gitlens.views.worktrees || (focusedView == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == worktrees)", "mac": "cmd+c" } ], From 558cce1ed00d66b55d507ba7c10d4af1e4874fab Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Fri, 17 Oct 2025 07:46:41 -0700 Subject: [PATCH 25/83] Adds support for untracked files in composer (#4653) * Adds support for untracked files in composer * Shortens try/catch block --- src/env/node/git/sub-providers/staging.ts | 8 ++- src/git/gitProvider.ts | 2 +- src/webviews/plus/composer/composerWebview.ts | 50 +++++++++++++++++-- src/webviews/plus/composer/utils.ts | 3 +- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/env/node/git/sub-providers/staging.ts b/src/env/node/git/sub-providers/staging.ts index b247ab6ed3693..44cfc189f864c 100644 --- a/src/env/node/git/sub-providers/staging.ts +++ b/src/env/node/git/sub-providers/staging.ts @@ -78,11 +78,15 @@ export class StagingGitSubProvider implements GitStagingSubProvider { } @log() - async stageFiles(repoPath: string, pathOrUri: string[] | Uri[]): Promise { + async stageFiles( + repoPath: string, + pathOrUri: string[] | Uri[], + options?: { intentToAdd?: boolean }, + ): Promise { await this.git.exec( { cwd: repoPath }, 'add', - '-A', + options?.intentToAdd ? '-N' : '-A', '--', ...pathOrUri.map(p => (typeof p === 'string' ? p : splitPath(p, repoPath)[0])), ); diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 462e3af94b83a..0245547ea384a 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -653,7 +653,7 @@ export interface DisposableTemporaryGitIndex extends UnifiedAsyncDisposable { export interface GitStagingSubProvider { createTemporaryIndex(repoPath: string, base: string): Promise; stageFile(repoPath: string, pathOrUri: string | Uri): Promise; - stageFiles(repoPath: string, pathOrUri: string[] | Uri[]): Promise; + stageFiles(repoPath: string, pathOrUri: string[] | Uri[], options?: { intentToAdd?: boolean }): Promise; stageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise; unstageFile(repoPath: string, pathOrUri: string | Uri): Promise; unstageFiles(repoPath: string, pathOrUri: string[] | Uri[]): Promise; diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index dd8c486181660..bf1ca711e3830 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -78,6 +78,7 @@ import { ReloadComposerCommand, } from './protocol'; import type { ComposerWebviewShowingArgs } from './registration'; +import type { WorkingTreeDiffs } from './utils'; import { convertToComposerDiffInfo, createCombinedDiffForCommit, @@ -108,6 +109,9 @@ export class ComposerWebviewProvider implements WebviewProvider, @@ -299,6 +303,17 @@ export class ComposerWebviewProvider implements WebviewProvider { + // Stop repo change subscription so we can deal with untracked files + this._repositorySubscription?.dispose(); + const status = await repo.git.status?.getStatus(); + const untrackedPaths = status?.untrackedChanges.map(f => f.path); + if (untrackedPaths?.length) { + try { + await repo.git.staging?.stageFiles(untrackedPaths, { intentToAdd: true }); + this._ignoreIndexChange = true; + } catch {} + } + const [diffsResult, commitResult, branchResult] = await Promise.allSettled([ // Handle baseCommit - could be string (old format) or ComposerBaseCommit (new format) getWorkingTreeDiffs(repo), @@ -306,6 +321,10 @@ export class ComposerWebviewProvider implements WebviewProvider { if (e.repository.id !== this._currentRepository?.id) return; - + const ignoreIndexChange = this._ignoreIndexChange; + this._ignoreIndexChange = false; // Only care about index changes (staged/unstaged changes) - if (!e.changed(RepositoryChange.Index, RepositoryChangeComparisonMode.Any)) { + if ( + !e.changed(RepositoryChange.Index, RepositoryChangeComparisonMode.Any) || + (ignoreIndexChange && e.changed(RepositoryChange.Index, RepositoryChangeComparisonMode.Exclusive)) + ) { return; } @@ -1089,7 +1112,26 @@ export class ComposerWebviewProvider implements WebviewProvider f.path); + if (untrackedPaths?.length) { + try { + workingTreeDiffs = await getWorkingTreeDiffs(repo); + await repo.git.staging?.stageFiles(untrackedPaths); + } catch {} + } + } + + const validation = await validateSafetyState( + repo, + this._safetyState, + hunksBeingCommitted, + workingTreeDiffs, + ); if (!validation.isValid) { // Clear loading state and show safety error await this.host.notify(DidFinishCommittingNotification, undefined); @@ -1197,7 +1239,7 @@ export class ComposerWebviewProvider implements WebviewProvider { const errors: string[] = []; @@ -361,7 +362,7 @@ export async function validateSafetyState( // 2. Smart diff validation - only check diffs for sources being committed if (hunksBeingCommitted?.length) { - const { staged, unstaged /*, unified*/ } = await getWorkingTreeDiffs(repo); + const { staged, unstaged /*, unified*/ } = workingTreeDiffs ?? (await getWorkingTreeDiffs(repo)); const hashes = { staged: staged?.contents ? await sha256(staged.contents) : null, From 9233c3ba2416e7bfea95562c0ceebc0a3ed022b0 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Fri, 17 Oct 2025 08:12:50 -0700 Subject: [PATCH 26/83] Adds support for composing without a base commit (#4656) --- src/env/node/git/git.ts | 4 +- src/env/node/git/sub-providers/patch.ts | 23 ++++++- src/env/node/git/sub-providers/staging.ts | 40 ++++++------ src/git/gitProvider.ts | 5 +- src/git/models/revision.ts | 2 + .../apps/plus/composer/components/app.ts | 1 + .../plus/composer/components/commit-item.ts | 5 +- .../plus/composer/components/commits-panel.ts | 34 +++++++--- .../plus/composer/components/composer.css.ts | 9 +++ src/webviews/plus/composer/composerWebview.ts | 62 +++++++++---------- src/webviews/plus/composer/protocol.ts | 19 +++--- src/webviews/plus/composer/utils.ts | 10 +-- 12 files changed, 125 insertions(+), 89 deletions(-) diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 493a74da6a5e8..63b0c9bcdeee1 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -34,6 +34,7 @@ import { } from '../../../git/errors'; import type { GitDir } from '../../../git/gitProvider'; import type { GitDiffFilter } from '../../../git/models/diff'; +import { rootSha } from '../../../git/models/revision'; import { parseGitRemoteUrl } from '../../../git/parsers/remoteParser'; import { isUncommitted, isUncommittedStaged, shortenRevision } from '../../../git/utils/revision.utils'; import { getCancellationTokenId } from '../../../system/-webview/cancellation'; @@ -69,9 +70,6 @@ export const maxGitCliLength = 30000; const textDecoder = new TextDecoder('utf8'); -// This is a root sha of all git repo's if using sha1 -const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; - export const GitErrors = { alreadyCheckedOut: /already checked out/i, alreadyExists: /already exists/i, diff --git a/src/env/node/git/sub-providers/patch.ts b/src/env/node/git/sub-providers/patch.ts index c5460f4d9f4b3..f731e7d7adddc 100644 --- a/src/env/node/git/sub-providers/patch.ts +++ b/src/env/node/git/sub-providers/patch.ts @@ -177,7 +177,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider { @log({ args: { 2: p => p.length } }) async createUnreachableCommitsFromPatches( repoPath: string, - base: string, + base: string | undefined, patches: { message: string; patch: string }[], ): Promise { // Create a temporary index file @@ -198,7 +198,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider { private async createUnreachableCommitForPatchCore( env: Record, repoPath: string, - base: string, + base: string | undefined, message: string, patch: string, ): Promise { @@ -222,7 +222,14 @@ export class PatchGitSubProvider implements GitPatchSubProvider { const tree = result.stdout.trim(); // Create new commit from the tree - result = await this.git.exec({ cwd: repoPath, env: env }, 'commit-tree', tree, '-p', base, '-m', message); + result = await this.git.exec( + { cwd: repoPath, env: env }, + 'commit-tree', + tree, + ...(base ? ['-p', base] : []), + '-m', + message, + ); const sha = result.stdout.trim(); return sha; @@ -234,6 +241,16 @@ export class PatchGitSubProvider implements GitPatchSubProvider { } } + async createEmptyInitialCommit(repoPath: string): Promise { + const emptyTree = await this.git.exec({ cwd: repoPath }, 'hash-object', '-t', 'tree', '/dev/null'); + const result = await this.git.exec({ cwd: repoPath }, 'commit-tree', emptyTree.stdout.trim(), '-m', 'temp'); + // create ref/heaads/main and point to it + await this.git.exec({ cwd: repoPath }, 'update-ref', 'refs/heads/main', result.stdout.trim()); + // point HEAD to the branch + await this.git.exec({ cwd: repoPath }, 'symbolic-ref', 'HEAD', 'refs/heads/main'); + return result.stdout.trim(); + } + @log({ args: { 1: false } }) async validatePatch(repoPath: string | undefined, contents: string): Promise { try { diff --git a/src/env/node/git/sub-providers/staging.ts b/src/env/node/git/sub-providers/staging.ts index 44cfc189f864c..b4a8612208ea7 100644 --- a/src/env/node/git/sub-providers/staging.ts +++ b/src/env/node/git/sub-providers/staging.ts @@ -2,6 +2,7 @@ import { promises as fs } from 'fs'; import { tmpdir } from 'os'; import type { Uri } from 'vscode'; import type { Container } from '../../../../container'; +import { GitErrorHandling } from '../../../../git/commandOptions'; import type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '../../../../git/gitProvider'; import { splitPath } from '../../../../system/-webview/path'; import { log } from '../../../../system/decorators/log'; @@ -18,7 +19,7 @@ export class StagingGitSubProvider implements GitStagingSubProvider { ) {} @log() - async createTemporaryIndex(repoPath: string, base: string): Promise { + async createTemporaryIndex(repoPath: string, base: string | undefined): Promise { // Create a temporary index file const tempDir = await fs.mkdtemp(joinPaths(tmpdir(), 'gl-')); const tempIndex = joinPaths(tempDir, 'index'); @@ -37,24 +38,27 @@ export class StagingGitSubProvider implements GitStagingSubProvider { const env = { GIT_INDEX_FILE: tempIndex }; // Create the temp index file from a base ref/sha + if (base) { + // Get the tree of the base + const newIndexResult = await this.git.exec( + { cwd: repoPath, env: env }, + 'ls-tree', + '-z', + '-r', + '--full-name', + base, + ); - // Get the tree of the base - const newIndexResult = await this.git.exec( - { cwd: repoPath, env: env }, - 'ls-tree', - '-z', - '-r', - '--full-name', - base, - ); - - // Write the tree to our temp index - await this.git.exec( - { cwd: repoPath, env: env, stdin: newIndexResult.stdout }, - 'update-index', - '-z', - '--index-info', - ); + if (newIndexResult.stdout.trim()) { + // Write the tree to our temp index + await this.git.exec( + { cwd: repoPath, env: env, stdin: newIndexResult.stdout }, + 'update-index', + '-z', + '--index-info', + ); + } + } return mixinAsyncDisposable({ path: tempIndex, env: { GIT_INDEX_FILE: tempIndex } }, dispose); } catch (ex) { diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 0245547ea384a..925d9f9c266f9 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -534,9 +534,10 @@ export interface GitPatchSubProvider { ): Promise; createUnreachableCommitsFromPatches( repoPath: string, - base: string, + base: string | undefined, patches: { message: string; patch: string }[], ): Promise; + createEmptyInitialCommit(repoPath: string): Promise; validatePatch(repoPath: string | undefined, contents: string): Promise; } @@ -651,7 +652,7 @@ export interface DisposableTemporaryGitIndex extends UnifiedAsyncDisposable { } export interface GitStagingSubProvider { - createTemporaryIndex(repoPath: string, base: string): Promise; + createTemporaryIndex(repoPath: string, base: string | undefined): Promise; stageFile(repoPath: string, pathOrUri: string | Uri): Promise; stageFiles(repoPath: string, pathOrUri: string[] | Uri[], options?: { intentToAdd?: boolean }): Promise; stageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise; diff --git a/src/git/models/revision.ts b/src/git/models/revision.ts index b08eeeea5bce9..1cabf515f05b4 100644 --- a/src/git/models/revision.ts +++ b/src/git/models/revision.ts @@ -1,6 +1,8 @@ export const deletedOrMissing = '0000000000000000000000000000000000000000-'; export const uncommitted = '0000000000000000000000000000000000000000'; export const uncommittedStaged = '0000000000000000000000000000000000000000:'; +// This is a root sha of all git repo's if using sha1 +export const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; export type GitRevisionRange = | `${GitRevisionRangeNotation}${string}` diff --git a/src/webviews/apps/plus/composer/components/app.ts b/src/webviews/apps/plus/composer/components/app.ts index 278a84a545c21..8b4628c9a5d37 100644 --- a/src/webviews/apps/plus/composer/components/app.ts +++ b/src/webviews/apps/plus/composer/components/app.ts @@ -1582,6 +1582,7 @@ export class ComposerApp extends LitElement { .canGenerateCommitsWithAI=${this.canGenerateCommitsWithAI} .isPreviewMode=${this.isPreviewMode} .baseCommit=${this.state.baseCommit} + .repoName=${this.state.baseCommit?.repoName ?? this.state.repositoryState?.current.name} .customInstructions=${this.customInstructions} .hasUsedAutoCompose=${this.state.hasUsedAutoCompose} .hasChanges=${this.state.hasChanges} diff --git a/src/webviews/apps/plus/composer/components/commit-item.ts b/src/webviews/apps/plus/composer/components/commit-item.ts index ba6a141a3542a..fe7ae54219d31 100644 --- a/src/webviews/apps/plus/composer/components/commit-item.ts +++ b/src/webviews/apps/plus/composer/components/commit-item.ts @@ -86,6 +86,9 @@ export class CommitItem extends LitElement { @property({ type: Boolean }) first = false; + @property({ type: Boolean }) + last = false; + override connectedCallback() { super.connectedCallback?.(); // Set the data attribute for sortable access @@ -120,7 +123,7 @@ export class CommitItem extends LitElement {
-
+
-
${this.baseCommit?.message || 'HEAD'}
+
+ ${this.baseCommit?.message || 'No commits yet'} +
- ${this.baseCommit?.repoName || 'Repository'} - / - ${this.baseCommit?.branchName || 'main'} + ${this.repoName || 'Repository'} + ${this.baseCommit?.branchName + ? html`/${this.baseCommit.branchName}` + : ''}
@@ -1291,6 +1300,7 @@ export class CommitsPanel extends LitElement { .multiSelected=${this.selectedCommitIds.has(commit.id)} .isPreviewMode=${this.isPreviewMode} ?first=${i === 0} + ?last=${i === this.commits.length - 1 && !this.baseCommit} @click=${(e: MouseEvent) => this.dispatchCommitSelect(commit.id, e)} @keydown=${(e: KeyboardEvent) => this.dispatchCommitSelect(commit.id, e)} > @@ -1301,13 +1311,17 @@ export class CommitsPanel extends LitElement {
-
+
-
${this.baseCommit?.message || 'HEAD'}
+
+ ${this.baseCommit?.message || 'No commits yet'} +
- ${this.baseCommit?.repoName || 'Repository'} - / - ${this.baseCommit?.branchName || 'main'} + ${this.repoName || 'Repository'} + ${this.baseCommit?.branchName + ? html`/${this.baseCommit.branchName}` + : ''}
diff --git a/src/webviews/apps/plus/composer/components/composer.css.ts b/src/webviews/apps/plus/composer/components/composer.css.ts index 8011465b1a501..6d943fd238d0a 100644 --- a/src/webviews/apps/plus/composer/components/composer.css.ts +++ b/src/webviews/apps/plus/composer/components/composer.css.ts @@ -148,6 +148,10 @@ export const composerItemCommitStyles = css` height: 50%; } + .composer-item.is-last .composer-item__commit::before { + display: none; + } + .composer-item__commit::after { content: ''; position: absolute; @@ -168,6 +172,11 @@ export const composerItemCommitStyles = css` .composer-item.is-base .composer-item__commit::before { border-left-style: solid; } + + .composer-item__commit.is-empty::before, + .composer-item__commit.is-empty::after { + display: none; + } `; export const composerItemContentStyles = css` diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index bf1ca711e3830..973cc526fd5ad 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -10,6 +10,7 @@ import type { RepositoryFileSystemChangeEvent, } from '../../../git/models/repository'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository'; +import { rootSha } from '../../../git/models/revision'; import { sendFeedbackEvent, showUnhelpfulFeedbackPicker } from '../../../plus/ai/aiFeedbackUtils'; import type { AIModelChangeEvent } from '../../../plus/ai/aiProviderService'; import { getRepositoryPickerTitleAndPlaceholder, showRepositoryPicker } from '../../../quickpicks/repositoryPicker'; @@ -347,30 +348,7 @@ export class ComposerWebviewProvider implements WebviewProvider = { hunks: [], commits: [], - baseCommit: { - sha: '', - message: '', - repoName: '', - branchName: '', - }, + baseCommit: null, selectedCommitId: null, selectedCommitIds: new Set(), selectedUnassignedSection: null, @@ -347,7 +342,7 @@ export interface GenerateWithAIParams { export interface DidChangeComposerDataParams { hunks: ComposerHunk[]; commits: ComposerCommit[]; - baseCommit: ComposerBaseCommit; + baseCommit: ComposerBaseCommit | null; } // IPC Commands and Notifications @@ -437,7 +432,7 @@ export const DidChangeAiModelNotification = new IpcNotification { - if (!headSha) { - throw new Error('Cannot create safety state: no HEAD commit found'); - } - return { repoPath: repo.path, - headSha: headSha, + headSha: headSha ?? null, hashes: { staged: diffs.staged?.contents ? await sha256(diffs.staged.contents) : null, unstaged: diffs.unstaged?.contents ? await sha256(diffs.unstaged.contents) : null, @@ -355,7 +351,7 @@ export async function validateSafetyState( // 2. Check HEAD SHA const currentHeadCommit = await repo.git.commits.getCommit('HEAD'); - const currentHeadSha = currentHeadCommit?.sha ?? 'unknown'; + const currentHeadSha = currentHeadCommit?.sha ?? null; if (currentHeadSha !== safetyState.headSha) { errors.push(`HEAD commit changed from "${safetyState.headSha}" to "${currentHeadSha}"`); } From a820d086c7396292a5c568b2bfd2adf4c1842725 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 12:03:10 -0400 Subject: [PATCH 27/83] Fixes expand/collapse of staged/unstaged groups --- .../apps/commitDetails/components/gl-details-base.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webviews/apps/commitDetails/components/gl-details-base.ts b/src/webviews/apps/commitDetails/components/gl-details-base.ts index f4a2b9aa30294..7c9e6bdd882de 100644 --- a/src/webviews/apps/commitDetails/components/gl-details-base.ts +++ b/src/webviews/apps/commitDetails/components/gl-details-base.ts @@ -152,13 +152,13 @@ export class GlDetailsBase extends LitElement { } } - if (staged.length === 0 && unstaged.length === 0) { + if (!staged.length && !unstaged.length) { children.push(...this.createFileTreeModel(mode, files, isTree, compact)); } else { if (staged.length) { children.push({ label: 'Staged Changes', - path: '', + path: '/:staged:/', level: 1, // isMulti ? 2 : 1, branch: true, checkable: false, @@ -174,7 +174,7 @@ export class GlDetailsBase extends LitElement { if (unstaged.length) { children.push({ label: 'Unstaged Changes', - path: '', + path: '/:unstaged:/', level: 1, // isMulti ? 2 : 1, branch: true, checkable: false, From 784242de3d5de977047e67de45ebf57ba7ca1f50 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 12:24:24 -0400 Subject: [PATCH 28/83] Reverts to previous typescript-eslint https://github.com/typescript-eslint/typescript-eslint/issues/11700 --- package.json | 2 +- pnpm-lock.yaml | 202 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 163 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 7bb073d0f3e20..f1b514a610497 100644 --- a/package.json +++ b/package.json @@ -25101,7 +25101,7 @@ "terser-webpack-plugin": "5.3.14", "ts-loader": "9.5.4", "typescript": "5.9.3", - "typescript-eslint": "8.46.1", + "typescript-eslint": "8.46.0", "webpack": "5.102.1", "webpack-bundle-analyzer": "4.10.2", "webpack-cli": "6.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb780da838d15..01649a4f233fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -311,8 +311,8 @@ importers: specifier: 5.9.3 version: 5.9.3 typescript-eslint: - specifier: 8.46.1 - version: 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + specifier: 8.46.0 + version: 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) webpack: specifier: 5.102.1 version: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) @@ -1653,11 +1653,18 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.46.1': - resolution: {integrity: sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==} + '@typescript-eslint/eslint-plugin@8.46.0': + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.46.0': + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.46.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' @@ -1668,39 +1675,72 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.46.0': + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.46.1': resolution: {integrity: sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@8.46.0': + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.46.1': resolution: {integrity: sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.46.0': + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.46.1': resolution: {integrity: sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.46.1': - resolution: {integrity: sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==} + '@typescript-eslint/type-utils@8.46.0': + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/types@8.46.0': + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.46.1': resolution: {integrity: sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.46.0': + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.46.1': resolution: {integrity: sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.46.0': + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.46.1': resolution: {integrity: sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1708,6 +1748,10 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/visitor-keys@8.46.0': + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.46.1': resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2237,11 +2281,16 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bare-events@2.7.0: - resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==} + bare-events@2.8.0: + resolution: {integrity: sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true - bare-fs@4.4.7: - resolution: {integrity: sha512-huJQxUWc2d1T+6dxnC/FoYpBgEHzJp33mYZqFtQqTTPPyP9xPvmjC16VpR4wTte4ZKd5VxkFAcfDYi51iwWMcg==} + bare-fs@4.4.10: + resolution: {integrity: sha512-arqVF+xX/rJHwrONZaSPhlzleT2gXwVs9rsAe1p1mIVwWZI2A76/raio+KwwxfWMO8oV9Wo90EaUkS2QwVmy4w==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -2273,8 +2322,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.15: - resolution: {integrity: sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q==} + baseline-browser-mapping@2.8.16: + resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} hasBin: true basic-auth@2.0.1: @@ -6057,8 +6106,8 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typescript-eslint@8.46.1: - resolution: {integrity: sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==} + typescript-eslint@8.46.0: + resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -7592,14 +7641,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/type-utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 eslint: 9.37.0(jiti@2.4.0) graphemer: 1.4.0 ignore: 7.0.5 @@ -7609,6 +7658,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.37.0(jiti@2.4.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.1 @@ -7621,6 +7682,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + debug: 4.4.3(supports-color@8.1.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.46.1(typescript@5.9.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) @@ -7630,20 +7700,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/scope-manager@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + '@typescript-eslint/scope-manager@8.46.1': dependencies: '@typescript-eslint/types': 8.46.1 '@typescript-eslint/visitor-keys': 8.46.1 + '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.46.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) eslint: 9.37.0(jiti@2.4.0) ts-api-utils: 2.1.0(typescript@5.9.3) @@ -7651,8 +7730,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@8.46.0': {} + '@typescript-eslint/types@8.46.1': {} + '@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3(supports-color@8.1.1) + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.46.1(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.46.1(typescript@5.9.3) @@ -7669,6 +7766,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.4.0)) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + eslint: 9.37.0(jiti@2.4.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.4.0)) @@ -7679,6 +7787,12 @@ snapshots: typescript: 5.9.3 transitivePeerDependencies: - supports-color + optional: true + + '@typescript-eslint/visitor-keys@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + eslint-visitor-keys: 4.2.1 '@typescript-eslint/visitor-keys@8.46.1': dependencies: @@ -7796,6 +7910,7 @@ snapshots: tinyglobby: 0.2.14 vscode-uri: 3.1.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -8214,16 +8329,17 @@ snapshots: balanced-match@1.0.2: {} - bare-events@2.7.0: {} + bare-events@2.8.0: {} - bare-fs@4.4.7: + bare-fs@4.4.10: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.0 bare-path: 3.0.0 - bare-stream: 2.7.0(bare-events@2.7.0) + bare-stream: 2.7.0(bare-events@2.8.0) bare-url: 2.2.2 fast-fifo: 1.3.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true @@ -8235,12 +8351,13 @@ snapshots: bare-os: 3.6.2 optional: true - bare-stream@2.7.0(bare-events@2.7.0): + bare-stream@2.7.0(bare-events@2.8.0): dependencies: streamx: 2.23.0 optionalDependencies: - bare-events: 2.7.0 + bare-events: 2.8.0 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true @@ -8252,7 +8369,7 @@ snapshots: base64-js@1.5.1: optional: true - baseline-browser-mapping@2.8.15: {} + baseline-browser-mapping@2.8.16: {} basic-auth@2.0.1: dependencies: @@ -8320,7 +8437,7 @@ snapshots: browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.15 + baseline-browser-mapping: 2.8.16 caniuse-lite: 1.0.30001749 electron-to-chromium: 1.5.234 node-releases: 2.0.23 @@ -9433,7 +9550,9 @@ snapshots: events-universal@1.0.1: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.0 + transitivePeerDependencies: + - bare-abort-controller events@3.3.0: {} @@ -12120,6 +12239,7 @@ snapshots: fast-fifo: 1.3.2 text-decoder: 1.2.3 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a string-width@4.2.3: @@ -12272,9 +12392,10 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 4.4.7 + bare-fs: 4.4.10 bare-path: 3.0.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a @@ -12293,6 +12414,7 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.23.0 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a tar@6.2.1: @@ -12492,12 +12614,12 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.7 - typescript-eslint@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3): + typescript-eslint@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3))(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.4.0))(typescript@5.9.3) eslint: 9.37.0(jiti@2.4.0) typescript: 5.9.3 transitivePeerDependencies: From bcde7780dcbe7a0a99017b0290317ba210fae9d4 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Oct 2025 12:24:33 -0400 Subject: [PATCH 29/83] Fixes lint warning --- src/env/node/git/sub-providers/staging.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/env/node/git/sub-providers/staging.ts b/src/env/node/git/sub-providers/staging.ts index b4a8612208ea7..54e76b8fe1e41 100644 --- a/src/env/node/git/sub-providers/staging.ts +++ b/src/env/node/git/sub-providers/staging.ts @@ -2,7 +2,6 @@ import { promises as fs } from 'fs'; import { tmpdir } from 'os'; import type { Uri } from 'vscode'; import type { Container } from '../../../../container'; -import { GitErrorHandling } from '../../../../git/commandOptions'; import type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '../../../../git/gitProvider'; import { splitPath } from '../../../../system/-webview/path'; import { log } from '../../../../system/decorators/log'; From c3bcd30f29627da2ca01f641ba3065f894cfd5e6 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Fri, 17 Oct 2025 12:33:13 -0400 Subject: [PATCH 30/83] Fixes #4703 underlines showing on home branch actions --- CHANGELOG.md | 4 ++++ src/webviews/apps/shared/components/actions/action-item.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9327250072e17..49e326efe56ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Changes the minimum VS Code version to 1.95.0 ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) +### Fixed + +- Fixes underlines showing on home branch actions ([#4703](https://github.com/gitkraken/vscode-gitlens/issues/4703)) + ## [17.6.2] - 2025-10-16 ### Changed diff --git a/src/webviews/apps/shared/components/actions/action-item.ts b/src/webviews/apps/shared/components/actions/action-item.ts index c3ecbd6c3f234..e0392d7f74fd1 100644 --- a/src/webviews/apps/shared/components/actions/action-item.ts +++ b/src/webviews/apps/shared/components/actions/action-item.ts @@ -53,10 +53,14 @@ export class ActionItem extends LitElement { justify-content: center; width: 100%; height: 100%; + text-decoration: none; } a:focus { outline: none; } + a:is(:hover, :focus, :active) { + text-decoration: none; + } `; @property() From 8f9186fad89ac14b375f26c7594d1510733f3a3c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 19 Oct 2025 20:39:47 -0400 Subject: [PATCH 31/83] Fixes intermittent loading spinner --- src/webviews/plus/graph/graphWebview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webviews/plus/graph/graphWebview.ts b/src/webviews/plus/graph/graphWebview.ts index f3c45cd5cd79e..a616cb0627bb8 100644 --- a/src/webviews/plus/graph/graphWebview.ts +++ b/src/webviews/plus/graph/graphWebview.ts @@ -2766,7 +2766,7 @@ export class GraphWebviewProvider implements WebviewProvider Date: Mon, 20 Oct 2025 00:55:40 -0400 Subject: [PATCH 32/83] Avoids extra promise wrapper --- src/git/models/repository.ts | 37 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 4b7afca264f40..d4ab9cb669416 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -776,35 +776,32 @@ export class Repository implements Disposable { } waitForRepoChange(timeoutMs: number): Promise { - return new Promise(resolve => { - let timeoutId: NodeJS.Timeout | undefined; - let listener: Disposable | undefined; - - const cleanup = () => { - if (timeoutId != null) { - clearTimeout(timeoutId); - timeoutId = undefined; - } - listener?.dispose(); - listener = undefined; - }; + let timeoutId: NodeJS.Timeout | undefined; + let listener: Disposable | undefined; + + const cleanup = () => { + if (timeoutId != null) { + clearTimeout(timeoutId); + timeoutId = undefined; + } + listener?.dispose(); + listener = undefined; + }; - const timeoutPromise = new Promise(r => { + return Promise.race([ + new Promise(r => { timeoutId = setTimeout(() => { cleanup(); r(false); }, timeoutMs); - }); - - const changePromise = new Promise(r => { + }), + new Promise(r => { listener = this.onDidChange(() => { cleanup(); r(true); }); - }); - - void Promise.race([timeoutPromise, changePromise]).then(result => resolve(result)); - }); + }), + ]); } private _fsWatcherDisposable: Disposable | undefined; From a51ae57399a735daa6f3133a3ca67d335c69d0b4 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 00:56:51 -0400 Subject: [PATCH 33/83] Adds a timeout to avoid hanging indefinitely --- src/views/nodes/resultsCommitsNode.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/views/nodes/resultsCommitsNode.ts b/src/views/nodes/resultsCommitsNode.ts index 3fe2c9108aa23..13a2e6061fb37 100644 --- a/src/views/nodes/resultsCommitsNode.ts +++ b/src/views/nodes/resultsCommitsNode.ts @@ -9,6 +9,8 @@ import type { AIGenerateChangelogChanges } from '../../plus/ai/aiProviderService import { configuration } from '../../system/-webview/configuration'; import { debug } from '../../system/decorators/log'; import { map } from '../../system/iterable'; +import { getLoggableName, Logger } from '../../system/logger'; +import { getNewLogScope } from '../../system/logger.scope'; import type { Deferred } from '../../system/promise'; import { defer, pauseOnCancelOrTimeout } from '../../system/promise'; import type { ViewsWithCommits } from '../viewBase'; @@ -182,11 +184,24 @@ export class ResultsCommitsNodeBase { + const scope = getNewLogScope(`${getLoggableName(this)}.getTreeItem`, true); try { - await this._onChildrenCompleted?.promise; + if (this._onChildrenCompleted?.promise != null) { + const timeout = new Promise(resolve => { + setTimeout(() => { + Logger.error(undefined, scope, 'onChildrenCompleted promise timed out after 30s'); + resolve(); + }, 30000); // 30 second timeout + }); + + await Promise.race([this._onChildrenCompleted.promise, timeout]); + } + void (await result.value); this.view.triggerNodeChange(this.parent); - } catch {} + } catch (ex) { + Logger.error(ex, scope, 'Failed awaiting children completion'); + } }); // Need to use Collapsed before we have results or the item won't show up in the view until the children are awaited From e8c0f7f41bf3b90b460824859cddadbbf638e2ba Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 00:57:12 -0400 Subject: [PATCH 34/83] Adds more granularity to gating to avoid deadlocks --- src/env/node/git/sub-providers/status.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/env/node/git/sub-providers/status.ts b/src/env/node/git/sub-providers/status.ts index 33aa12e524d3b..f2ede6a9dfb02 100644 --- a/src/env/node/git/sub-providers/status.ts +++ b/src/env/node/git/sub-providers/status.ts @@ -347,7 +347,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { return status; } - @gate(rp => rp ?? '') + @gate((rp, o) => `${rp ?? ''}:${o?.quit ?? false}`) @log() async abortPausedOperation(repoPath: string, options?: { quit?: boolean }): Promise { const status = await this.getPausedOperationStatus(repoPath); @@ -404,7 +404,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { } } - @gate(rp => rp ?? '') + @gate((rp, o) => `${rp ?? ''}:${o?.skip ?? false}`) @log() async continuePausedOperation(repoPath: string, options?: { skip?: boolean }): Promise { const status = await this.getPausedOperationStatus(repoPath); @@ -520,7 +520,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { } } - @gate() + @gate(rp => rp ?? '') @log() async getStatus(repoPath: string | undefined, cancellation?: CancellationToken): Promise { if (repoPath == null) return undefined; @@ -573,7 +573,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { return this.getStatusForPathCore(repoPath, pathOrUri, { ...options, exact: false }, cancellation); } - @gate() + @gate(rp => rp ?? '') private async getStatusForPathCore( repoPath: string, pathOrUri: string | Uri, From 55614a211b002e96e457aa6af6e7c00749098ec6 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 02:20:28 -0400 Subject: [PATCH 35/83] Adds logging/telementry for gate deadlocks Adds logging/telemetry for aborted Git operations --- docs/telemetry-events.md | 21 +++++++++++++++++++++ src/constants.telemetry.ts | 16 ++++++++++++++++ src/container.ts | 2 ++ src/env/browser/providers.ts | 10 ++++++++++ src/env/node/git/git.ts | 22 +++++++++++++++++++++- src/env/node/providers.ts | 10 ++++++++++ src/system/decorators/gate.ts | 15 ++++++++------- 7 files changed, 88 insertions(+), 8 deletions(-) diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index 01c2d66ca83a9..47039a3b70cc3 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -2813,6 +2813,27 @@ void } ``` +### op/gate/deadlock + +```typescript +{ + 'key': string, + 'prop': string, + 'timeout': number +} +``` + +### op/git/aborted + +```typescript +{ + 'duration': number, + 'operation': string, + 'reason': 'unknown' | 'timeout' | 'cancellation', + 'timeout': number +} +``` + ### openReviewMode > Sent when a PR review was started in the inspect overview diff --git a/src/constants.telemetry.ts b/src/constants.telemetry.ts index 1622d10ea6e0a..b772a6db8d739 100644 --- a/src/constants.telemetry.ts +++ b/src/constants.telemetry.ts @@ -258,6 +258,9 @@ export interface TelemetryEvents extends WebviewShowAbortedEvents, WebviewShownE /** Sent when a PR review was started in the inspect overview */ openReviewMode: OpenReviewModeEvent; + 'op/gate/deadlock': OperationGateDeadlockEvent; + 'op/git/aborted': OperationGitAbortedEvent; + /** Sent when fetching the product config fails */ 'productConfig/failed': ProductConfigFailedEvent; @@ -944,6 +947,19 @@ interface OpenReviewModeEvent { source: Sources; } +interface OperationGateDeadlockEvent { + key: string; + prop: string; + timeout: number; +} + +interface OperationGitAbortedEvent { + operation: string; + duration: number; + timeout: number; + reason: 'timeout' | 'cancellation' | 'unknown'; +} + interface ProductConfigFailedEvent { reason: 'fetch' | 'validation'; json: string | undefined; diff --git a/src/container.ts b/src/container.ts index 2d0a6560682b8..95462b620b72b 100644 --- a/src/container.ts +++ b/src/container.ts @@ -7,6 +7,7 @@ import { getSupportedGitProviders, getSupportedRepositoryLocationProvider, getSupportedWorkspacesStorageProvider, + setTelemetryService, } from '@env/providers'; import { FileAnnotationController } from './annotations/fileAnnotationController'; import { LineAnnotationController } from './annotations/lineAnnotationController'; @@ -200,6 +201,7 @@ export class Container { (this._usage = new UsageTracker(this, storage)), configuration.onDidChangeAny(this.onAnyConfigurationChanged, this), ]; + setTelemetryService(this._telemetry); this._urls = new UrlsProvider(this.env); this._disposables.push((this._connection = new ServerConnection(this, this._urls))); diff --git a/src/env/browser/providers.ts b/src/env/browser/providers.ts index b52ceb5739fb3..6997d79598d76 100644 --- a/src/env/browser/providers.ts +++ b/src/env/browser/providers.ts @@ -8,6 +8,7 @@ import type { RepositoryLocationProvider } from '../../git/location/repositorylo import { GitHubGitProvider } from '../../plus/integrations/providers/github/githubGitProvider'; import type { SharedGkStorageLocationProvider } from '../../plus/repos/sharedGkStorageLocationProvider'; import type { GkWorkspacesSharedStorageProvider } from '../../plus/workspaces/workspacesSharedStorageProvider'; +import type { TelemetryService } from '../../telemetry/telemetry'; import type { GitResult } from '../node/git/git'; export function git( @@ -47,3 +48,12 @@ export function getGkCliIntegrationProvider(_container: Container): undefined { export function getMcpProviders(_container: Container): Promise { return Promise.resolve(undefined); } + +let _telemetryService: TelemetryService | undefined; +export function getTelementryService(): TelemetryService | undefined { + return _telemetryService; +} + +export function setTelemetryService(service: TelemetryService): void { + _telemetryService = service; +} diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 63b0c9bcdeee1..33fa49af8b780 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -245,7 +245,7 @@ export class Git implements Disposable { /** Map of running git commands -- avoids running duplicate overlapping commands */ private readonly pendingCommands = new Map>>(); - constructor(container: Container) { + constructor(private readonly container: Container) { this._disposable = container.events.on('git:cache:reset', e => { // Ignore provider resets (e.g. it needs to be git specific) if (e.data.types?.every(t => t === 'providers')) return; @@ -347,6 +347,26 @@ export class Git implements Disposable { exitCode: result.exitCode ?? 0, }; } catch (ex) { + if (ex instanceof CancelledRunError) { + const duration = getDurationMilliseconds(start); + const timeout = runOpts.timeout ?? 0; + const reason = + timeout > 0 && duration >= timeout - 100 + ? 'timeout' + : cancellation?.isCancellationRequested + ? 'cancellation' + : 'unknown'; + Logger.warn( + `${getLoggableScopeBlockOverride('GIT')} ${gitCommand} ${GlyphChars.Dot} ABORTED after ${duration}ms (${reason})`, + ); + this.container.telemetry.sendEvent('op/git/aborted', { + operation: gitCommand, + reason: reason, + duration: duration, + timeout: timeout, + }); + } + if (errorHandling === GitErrorHandling.Ignore) { if (ex instanceof RunError) { return { diff --git a/src/env/node/providers.ts b/src/env/node/providers.ts index 3308dc47d7b9a..2660a779c0802 100644 --- a/src/env/node/providers.ts +++ b/src/env/node/providers.ts @@ -8,6 +8,7 @@ import type { SharedGkStorageLocationProvider } from '../../plus/repos/sharedGkS import type { GkWorkspacesSharedStorageProvider } from '../../plus/workspaces/workspacesSharedStorageProvider'; import { configuration } from '../../system/-webview/configuration'; // import { GitHubGitProvider } from '../../plus/github/githubGitProvider'; +import type { TelemetryService } from '../../telemetry/telemetry'; import type { GitResult } from './git/git'; import { Git } from './git/git'; import { LocalGitProvider } from './git/localGitProvider'; @@ -84,3 +85,12 @@ export async function getMcpProviders( return [new mcpModule.GkMcpProvider(container)]; } + +let _telemetryService: TelemetryService | undefined; +export function getTelementryService(): TelemetryService | undefined { + return _telemetryService; +} + +export function setTelemetryService(service: TelemetryService): void { + _telemetryService = service; +} diff --git a/src/system/decorators/gate.ts b/src/system/decorators/gate.ts index 4cae13c3d1e3d..c5b239ad6c726 100644 --- a/src/system/decorators/gate.ts +++ b/src/system/decorators/gate.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ +import { getTelementryService } from '@env/providers'; +import { Logger } from '../logger'; import { isPromise } from '../promise'; import { resolveProp } from './resolver'; @@ -36,13 +38,12 @@ export function gate any>(resolver?: (...args: Parame this[prop] = promise; void promise.finally(() => (this[prop] = undefined)); - // if (DEBUG) { - // const timeout = setTimeout(() => { - // console.debug(`[gate] ${key} took too long to resolve`, this, ...args); - // debugger; - // }, 60000); - // void promise.finally(() => clearTimeout(timeout)); - // } + // Log if gate takes too long to resolve + const timeout = setTimeout(() => { + Logger.warn(`[gate] ${key} has been pending for 60+ seconds (possible deadlock)`, `prop=${prop}`); + getTelementryService()?.sendEvent('op/gate/deadlock', { key: key, prop: prop, timeout: 60000 }); + }, 60000); + void promise.finally(() => clearTimeout(timeout)); } return promise; From d839ff5c26fac5d7966ea85907c083fc02ae0194 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 11:54:02 -0400 Subject: [PATCH 36/83] Simplifies paused operation error handling - Uses error's operation status directly instead of re-fetching - Avoids stale data caused by repo change events after failed continue --- src/git/actions/pausedOperation.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/git/actions/pausedOperation.ts b/src/git/actions/pausedOperation.ts index 41b539939a20c..be7441585b524 100644 --- a/src/git/actions/pausedOperation.ts +++ b/src/git/actions/pausedOperation.ts @@ -29,17 +29,10 @@ async function continuePausedOperationCore(svc: GitRepositoryService, skip: bool ex instanceof PausedOperationContinueError && ex.reason === PausedOperationContinueErrorReason.EmptyCommit ) { - let operation: GitPausedOperationStatus | undefined; - try { - const repo = svc.getRepository(); - if (repo != null) { - operation = await repo.git.status.getPausedOperationStatus?.(); - operation ??= await repo - .waitForRepoChange(500) - .then(() => repo.git.status.getPausedOperationStatus?.()); - } - } catch {} - operation ??= ex.operation; + // Use the operation status from the error - it's already accurate + // The previous code tried to wait for a repo change, but that would fire on the + // change event from the failed continue (not the skip), resulting in stale data + const operation: GitPausedOperationStatus = ex.operation; const pausedAt = getReferenceLabel(operation.incoming, { icon: false, label: true, quoted: true }); From 9fe3804a49e6e21af248981762b66afac36ef0d0 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 12:21:15 -0400 Subject: [PATCH 37/83] Updates CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e326efe56ae..a00f51b06f7dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Fixed +- Fixes intermittent stuck loading state on the _Commit Graph_ ([#4669](https://github.com/gitkraken/vscode-gitlens/issues/4669)) - Fixes underlines showing on home branch actions ([#4703](https://github.com/gitkraken/vscode-gitlens/issues/4703)) ## [17.6.2] - 2025-10-16 From 8aefd7b6f60032f6fa0f37a4bfe1b5b9d49055f6 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 12:22:23 -0400 Subject: [PATCH 38/83] Closes #4709 use merge target when creating PRs --- CHANGELOG.md | 1 + src/commands/createPullRequestOnRemote.ts | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a00f51b06f7dc..9f697ea75014a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed +- Changes to use the "merge target" when we are creating pull requests ([#4709](https://github.com/gitkraken/vscode-gitlens/issues/4709)) - Changes the minimum VS Code version to 1.95.0 ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) ### Fixed diff --git a/src/commands/createPullRequestOnRemote.ts b/src/commands/createPullRequestOnRemote.ts index ab89e9327c30f..bbd42f734cec1 100644 --- a/src/commands/createPullRequestOnRemote.ts +++ b/src/commands/createPullRequestOnRemote.ts @@ -5,7 +5,8 @@ import type { GitRemote } from '../git/models/remote'; import type { CreatePullRequestRemoteResource } from '../git/models/remoteResource'; import { RemoteResourceType } from '../git/models/remoteResource'; import type { RemoteProvider } from '../git/remotes/remoteProvider'; -import { getRemoteNameFromBranchName } from '../git/utils/branch.utils'; +import { getBranchMergeTargetName } from '../git/utils/-webview/branch.utils'; +import { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from '../git/utils/branch.utils'; import { getRepositoryOrShowPicker } from '../quickpicks/repositoryPicker'; import { command, executeCommand } from '../system/-webview/command'; import { GlCommandBase } from './commandBase'; @@ -67,6 +68,17 @@ export class CreatePullRequestOnRemoteCommand extends GlCommandBase { sort: true, })) as GitRemote[]; + if (args.base == null) { + const branch = await repo.git.branches.getBranch(args.compare); + if (branch != null) { + const mergeTargetResult = await getBranchMergeTargetName(this.container, branch); + if (!mergeTargetResult.paused && mergeTargetResult.value != null) { + // Strip the remote name from the branch name + args.base = getBranchNameWithoutRemote(mergeTargetResult.value); + } + } + } + const resource: CreatePullRequestRemoteResource = { type: RemoteResourceType.CreatePullRequest, repoPath: repo.path, From 1f868fff93585ca157b6063b7a25ebc0242714cd Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 13:04:43 -0400 Subject: [PATCH 39/83] Consolidates remote provider loading --- src/env/node/git/sub-providers/remotes.ts | 7 +++---- src/git/remotes/remoteProviders.ts | 21 +++++++++++-------- .../providers/github/sub-providers/remotes.ts | 5 ++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/env/node/git/sub-providers/remotes.ts b/src/env/node/git/sub-providers/remotes.ts index ec2f2634f755f..615efeccd66b3 100644 --- a/src/env/node/git/sub-providers/remotes.ts +++ b/src/env/node/git/sub-providers/remotes.ts @@ -4,10 +4,9 @@ import type { GitCache } from '../../../../git/cache'; import type { GitRemotesSubProvider } from '../../../../git/gitProvider'; import type { GitRemote } from '../../../../git/models/remote'; import { parseGitRemotes } from '../../../../git/parsers/remoteParser'; -import { getRemoteProviderMatcher, loadRemoteProviders } from '../../../../git/remotes/remoteProviders'; +import { getRemoteProviderMatcher, loadRemoteProvidersFromConfig } from '../../../../git/remotes/remoteProviders'; import { RemotesGitProviderBase } from '../../../../git/sub-providers/remotes'; import { sortRemotes } from '../../../../git/utils/-webview/sorting'; -import { configuration } from '../../../../system/-webview/configuration'; import { gate } from '../../../../system/decorators/gate'; import { log } from '../../../../system/decorators/log'; import { Logger } from '../../../../system/logger'; @@ -36,8 +35,8 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase implements Git const scope = getLogScope(); const remotesPromise = this.cache.remotes?.getOrCreate(repoPath, async cancellable => { - const providers = loadRemoteProviders( - configuration.get('remotes', this.container.git.getRepository(repoPath)?.folder?.uri ?? null), + const providers = loadRemoteProvidersFromConfig( + this.container.git.getRepository(repoPath)?.folder?.uri ?? null, await this.container.integrations.getConfigured(), ); diff --git a/src/git/remotes/remoteProviders.ts b/src/git/remotes/remoteProviders.ts index 3e850608156ca..055b7c5fcc9d4 100644 --- a/src/git/remotes/remoteProviders.ts +++ b/src/git/remotes/remoteProviders.ts @@ -1,3 +1,4 @@ +import type { ConfigurationScope } from 'vscode'; import type { RemotesConfig } from '../../config'; import type { CloudGitSelfManagedHostIntegrationIds } from '../../constants.integrations'; import { GitSelfManagedHostIntegrationId } from '../../constants.integrations'; @@ -102,9 +103,17 @@ function cleanProtocol(scheme: string | undefined): string | undefined { return match?.[1] ?? undefined; } -export function loadRemoteProviders( +export function loadRemoteProvidersFromConfig( + scope: ConfigurationScope | null, + configuredIntegrations: ConfiguredIntegrationDescriptor[] | undefined, +): RemoteProviders { + const configuredRemotes = configuration.get('remotes', scope); + return loadRemoteProviders(configuredRemotes, configuredIntegrations); +} + +function loadRemoteProviders( cfg: RemotesConfig[] | null | undefined, - configuredIntegrations?: ConfiguredIntegrationDescriptor[], + configuredIntegrations: ConfiguredIntegrationDescriptor[] | undefined, ): RemoteProviders { const providers: RemoteProviders = []; @@ -194,13 +203,7 @@ export async function getRemoteProviderMatcher( container: Container, providers?: RemoteProviders, ): Promise<(url: string, domain: string, path: string, sheme: string | undefined) => RemoteProvider | undefined> { - if (providers == null) { - providers = loadRemoteProviders( - configuration.get('remotes', null), - await container.integrations.getConfigured(), - ); - } - + providers ??= loadRemoteProvidersFromConfig(null, await container.integrations.getConfigured()); return (url: string, domain: string, path: string, scheme) => createBestRemoteProvider(container, providers, url, domain, path, scheme); } diff --git a/src/plus/integrations/providers/github/sub-providers/remotes.ts b/src/plus/integrations/providers/github/sub-providers/remotes.ts index 68807042e7471..e72a001fc58b8 100644 --- a/src/plus/integrations/providers/github/sub-providers/remotes.ts +++ b/src/plus/integrations/providers/github/sub-providers/remotes.ts @@ -1,8 +1,7 @@ import { Uri } from 'vscode'; import { GitRemote } from '../../../../../git/models/remote'; -import { getRemoteProviderMatcher, loadRemoteProviders } from '../../../../../git/remotes/remoteProviders'; +import { getRemoteProviderMatcher, loadRemoteProvidersFromConfig } from '../../../../../git/remotes/remoteProviders'; import { RemotesGitProviderBase } from '../../../../../git/sub-providers/remotes'; -import { configuration } from '../../../../../system/-webview/configuration'; import { log } from '../../../../../system/decorators/log'; export class RemotesGitSubProvider extends RemotesGitProviderBase { @@ -13,7 +12,7 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase { ): Promise { if (repoPath == null) return []; - const providers = loadRemoteProviders(configuration.get('remotes', null), undefined); + const providers = loadRemoteProvidersFromConfig(null, undefined); const uri = Uri.parse(repoPath, true); const [, owner, repo] = uri.path.split('/', 3); From 8cf5b188df7da57edbe8ba45c705f9668fe69f11 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 13:58:25 -0400 Subject: [PATCH 40/83] Ensures caches are properly cleared --- src/env/node/git/localGitProvider.ts | 82 ++++++++++++++++------------ 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index cdb2ae59bbad0..4b0c5e06fa40b 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -170,49 +170,59 @@ export class LocalGitProvider implements GitProvider, Disposable { } private onRepositoryChanged(repo: Repository, e: RepositoryChangeEvent) { - if (e.changed(RepositoryChange.Config, RepositoryChangeComparisonMode.Any)) { - this._cache.repoInfo?.delete(repo.path); - } + if (e.changed(RepositoryChange.Unknown, RepositoryChangeComparisonMode.Any)) { + this._cache.clearCaches(repo.path); + } else { + if (e.changed(RepositoryChange.Config, RepositoryChangeComparisonMode.Any)) { + this._cache.repoInfo?.delete(repo.path); + } - if (e.changed(RepositoryChange.Heads, RepositoryChange.Remotes, RepositoryChangeComparisonMode.Any)) { - this._cache.branch?.delete(repo.path); - this._cache.branches?.delete(repo.path); - this._cache.contributors?.delete(repo.path); - this._cache.worktrees?.delete(repo.path); - } + if (e.changed(RepositoryChange.Heads, RepositoryChange.Remotes, RepositoryChangeComparisonMode.Any)) { + this._cache.branch?.delete(repo.path); + this._cache.branches?.delete(repo.path); + this._cache.contributors?.delete(repo.path); + this._cache.worktrees?.delete(repo.path); + } - if (e.changed(RepositoryChange.Remotes, RepositoryChange.RemoteProviders, RepositoryChangeComparisonMode.Any)) { - this._cache.remotes?.delete(repo.path); - this._cache.bestRemotes?.delete(repo.path); - } + if ( + e.changed( + RepositoryChange.Remotes, + RepositoryChange.RemoteProviders, + RepositoryChangeComparisonMode.Any, + ) + ) { + this._cache.remotes?.delete(repo.path); + this._cache.bestRemotes?.delete(repo.path); + } - if (e.changed(RepositoryChange.Index, RepositoryChange.Unknown, RepositoryChangeComparisonMode.Any)) { - this._cache.trackedPaths.clear(); - } + if (e.changed(RepositoryChange.Index, RepositoryChangeComparisonMode.Any)) { + this._cache.trackedPaths.clear(); + } - if ( - e.changed( - RepositoryChange.CherryPick, - RepositoryChange.Merge, - RepositoryChange.Rebase, - RepositoryChange.Revert, - RepositoryChangeComparisonMode.Any, - ) - ) { - this._cache.branch?.delete(repo.path); - this._cache.pausedOperationStatus?.delete(repo.path); - } + if ( + e.changed( + RepositoryChange.CherryPick, + RepositoryChange.Merge, + RepositoryChange.Rebase, + RepositoryChange.Revert, + RepositoryChangeComparisonMode.Any, + ) + ) { + this._cache.branch?.delete(repo.path); + this._cache.pausedOperationStatus?.delete(repo.path); + } - if (e.changed(RepositoryChange.Stash, RepositoryChangeComparisonMode.Any)) { - this._cache.stashes?.delete(repo.path); - } + if (e.changed(RepositoryChange.Stash, RepositoryChangeComparisonMode.Any)) { + this._cache.stashes?.delete(repo.path); + } - if (e.changed(RepositoryChange.Tags, RepositoryChangeComparisonMode.Any)) { - this._cache.tags?.delete(repo.path); - } + if (e.changed(RepositoryChange.Tags, RepositoryChangeComparisonMode.Any)) { + this._cache.tags?.delete(repo.path); + } - if (e.changed(RepositoryChange.Worktrees, RepositoryChangeComparisonMode.Any)) { - this._cache.worktrees?.delete(repo.path); + if (e.changed(RepositoryChange.Worktrees, RepositoryChangeComparisonMode.Any)) { + this._cache.worktrees?.delete(repo.path); + } } this._onWillChangeRepository.fire(e); From 4f0c42439f5f04166d6377ea386cc78f5a9f373d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 15:56:29 -0400 Subject: [PATCH 41/83] Adds additional logging --- src/git/models/repository.ts | 12 +++++++++-- src/system/event.ts | 20 ++++++++++++++++--- .../nodes/abstract/subscribeableViewNode.ts | 20 ++++++++++++++++++- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index d4ab9cb669416..8355bb846ed0f 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -679,18 +679,22 @@ export class Repository implements Disposable { ); } + @debug({ singleLine: true }) resume(): void { if (!this._suspended) return; + const scope = getLogScope(); this._suspended = false; // If we've come back into focus and we are dirty, fire the change events if (this._pendingRepoChange != null) { - this._fireChangeDebounced!(); + Logger.debug(scope, `Firing pending repo changes: ${this._pendingRepoChange.toString(true)}`); + this._fireChangeDebounced?.(); } if (this._pendingFileSystemChange != null) { + Logger.debug(scope, `Firing pending file system changes`); this._fireFileSystemChangeDebounced?.(); } } @@ -705,6 +709,7 @@ export class Repository implements Disposable { return starred != null && starred[this.id] === true; } + @log({ args: { 0: b => b?.name } }) star(branch?: GitBranch): Promise { return this.updateStarred(true, branch); } @@ -743,6 +748,7 @@ export class Repository implements Disposable { return rev != null ? this.git.getBestRevisionUri(path, rev) : undefined; } + @log({ args: { 0: b => b?.name } }) unstar(branch?: GitBranch): Promise { return this.updateStarred(false, branch); } @@ -771,6 +777,7 @@ export class Repository implements Disposable { return this._etagFileSystem; } + @debug({ singleLine: true }) suspend(): void { this._suspended = true; } @@ -808,6 +815,7 @@ export class Repository implements Disposable { private _fsWatchers = new Map(); private _fsChangeDelay: number = defaultFileSystemChangeDelay; + @debug({ singleLine: true }) watchFileSystem(delay: number = defaultFileSystemChangeDelay): Disposable { const id = uuid(); this._fsWatchers.set(id, delay); @@ -867,7 +875,7 @@ export class Repository implements Disposable { this.providerService.onRepositoryChanged(this, this._pendingRepoChange); if (this._suspended) { - Logger.debug(scope, `queueing suspended ${this._pendingRepoChange.toString(true)}`); + Logger.debug(scope, `SUSPENDED: queueing ${this._pendingRepoChange.toString(true)}`); return; } diff --git a/src/system/event.ts b/src/system/event.ts index 8a118be803ae6..c59b71101fb8d 100644 --- a/src/system/event.ts +++ b/src/system/event.ts @@ -1,4 +1,5 @@ import type { Disposable, Event } from 'vscode'; +import { Logger } from './logger'; import type { Deferred } from './promise'; export function once(event: Event): Event { @@ -112,21 +113,34 @@ export function weakEvent( ): Disposable { const ref = new WeakRef(thisArg); + let disposed = false; let disposable: Disposable; const d = event((e: T) => { const obj = ref.deref(); if (obj != null) { listener.call(obj, e); - } else { + } else if (!disposed) { + Logger.warn(`weakEvent GC'd; disposing listener`); disposable.dispose(); } }); if (alsoDisposeOnReleaseOrDispose == null) { - disposable = d; + disposable = { + dispose: () => { + disposed = true; + d.dispose(); + }, + }; } else { - disposable = disposableFrom(d, ...alsoDisposeOnReleaseOrDispose); + const wrapped = disposableFrom(d, ...alsoDisposeOnReleaseOrDispose); + disposable = { + dispose: () => { + disposed = true; + wrapped.dispose(); + }, + }; } return disposable; } diff --git a/src/views/nodes/abstract/subscribeableViewNode.ts b/src/views/nodes/abstract/subscribeableViewNode.ts index 4105e575613a9..4bc819e10f46b 100644 --- a/src/views/nodes/abstract/subscribeableViewNode.ts +++ b/src/views/nodes/abstract/subscribeableViewNode.ts @@ -5,6 +5,7 @@ import type { GitUri } from '../../../git/gitUri'; import { gate } from '../../../system/decorators/gate'; import { debug } from '../../../system/decorators/log'; import { weakEvent } from '../../../system/event'; +import { getLogScope, setLogScopeExit } from '../../../system/logger.scope'; import type { View } from '../../viewBase'; import { CacheableChildrenViewNode } from './cacheableChildrenViewNode'; import type { ViewNode } from './viewNode'; @@ -144,8 +145,20 @@ export abstract class SubscribeableViewNode< @gate() @debug() async ensureSubscription(): Promise { + const scope = getLogScope(); + // We only need to subscribe if we are visible and if auto-refresh enabled (when supported) - if (!this.canSubscribe || !this.view.visible || (canAutoRefreshView(this.view) && !this.view.autoRefresh)) { + const { + canSubscribe, + view: { visible: isVisible }, + } = this; + const canAutoRefresh = canAutoRefreshView(this.view) && this.view.autoRefresh; + + if (!canSubscribe || !isVisible || !canAutoRefresh) { + setLogScopeExit( + scope, + ` \u2022 unsubscribed (subscription=${this.subscription != null}); canSubscribe=${canSubscribe}, viewVisible=${isVisible}, canAutoRefresh=${canAutoRefresh}`, + ); await this.unsubscribe(); return; @@ -154,6 +167,11 @@ export abstract class SubscribeableViewNode< // If we already have a subscription, just kick out if (this.subscription != null) return; + setLogScopeExit( + scope, + ` \u2022 subscribed; canSubscribe=${canSubscribe}, viewVisible=${isVisible}, canAutoRefresh=${canAutoRefresh}`, + ); + this.subscription = Promise.resolve(this.subscribe()); void (await this.subscription); } From efe604a3c2c32db20e661e17154b59b6f3540a8f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 18:11:11 -0400 Subject: [PATCH 42/83] Fixes logic error in subscription Introduced in commit 4f0c42439f5f04166d6377ea386cc78f5a9f373d --- src/views/nodes/abstract/subscribeableViewNode.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/views/nodes/abstract/subscribeableViewNode.ts b/src/views/nodes/abstract/subscribeableViewNode.ts index 4bc819e10f46b..f1e1474b3d0b5 100644 --- a/src/views/nodes/abstract/subscribeableViewNode.ts +++ b/src/views/nodes/abstract/subscribeableViewNode.ts @@ -147,17 +147,17 @@ export abstract class SubscribeableViewNode< async ensureSubscription(): Promise { const scope = getLogScope(); - // We only need to subscribe if we are visible and if auto-refresh enabled (when supported) + // We only need to subscribe if we are visible and if auto-refresh isn't disabled const { canSubscribe, view: { visible: isVisible }, } = this; - const canAutoRefresh = canAutoRefreshView(this.view) && this.view.autoRefresh; + const autoRefreshDisabled = canAutoRefreshView(this.view) && !this.view.autoRefresh; - if (!canSubscribe || !isVisible || !canAutoRefresh) { + if (!canSubscribe || !isVisible || autoRefreshDisabled) { setLogScopeExit( scope, - ` \u2022 unsubscribed (subscription=${this.subscription != null}); canSubscribe=${canSubscribe}, viewVisible=${isVisible}, canAutoRefresh=${canAutoRefresh}`, + ` \u2022 unsubscribed (subscription=${this.subscription != null}); canSubscribe=${canSubscribe}, viewVisible=${isVisible}, autoRefreshDisabled=${autoRefreshDisabled}`, ); await this.unsubscribe(); @@ -169,7 +169,7 @@ export abstract class SubscribeableViewNode< setLogScopeExit( scope, - ` \u2022 subscribed; canSubscribe=${canSubscribe}, viewVisible=${isVisible}, canAutoRefresh=${canAutoRefresh}`, + ` \u2022 subscribed; canSubscribe=${canSubscribe}, viewVisible=${isVisible}, autoRefreshDisabled=${autoRefreshDisabled}`, ); this.subscription = Promise.resolve(this.subscribe()); From f5b69f37b71846b34e2ad948ea90339a649a5a1f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 20 Oct 2025 18:09:58 -0400 Subject: [PATCH 43/83] Simplifies repo open logic and improves logging --- src/env/node/git/localGitProvider.ts | 12 +----- src/env/node/git/vslsGitProvider.ts | 2 +- src/git/gitProvider.ts | 8 +--- src/git/gitProviderService.ts | 2 +- src/git/models/repository.ts | 41 ++++++++++++------- .../providers/github/githubGitProvider.ts | 11 +---- 6 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 4b0c5e06fa40b..060293c01f974 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -429,13 +429,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @debug({ exit: true }) - openRepository( - folder: WorkspaceFolder | undefined, - uri: Uri, - root: boolean, - suspended?: boolean, - closed?: boolean, - ): Repository[] { + openRepository(folder: WorkspaceFolder | undefined, uri: Uri, root: boolean, closed?: boolean): Repository[] { if (!closed) { void this.getOrOpenScmRepository(uri); } @@ -451,7 +445,6 @@ export class LocalGitProvider implements GitProvider, Disposable { folder ?? workspace.getWorkspaceFolder(uri), uri, root, - suspended ?? !window.state.focused, closed, ), ]; @@ -470,7 +463,6 @@ export class LocalGitProvider implements GitProvider, Disposable { folder ?? workspace.getWorkspaceFolder(canonicalUri), canonicalUri, root, - suspended ?? !window.state.focused, true, ), ); @@ -640,7 +632,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } Logger.log(scope, `found ${root ? 'root ' : ''}repository in '${uri.fsPath}'`); - repositories.push(...this.openRepository(folder, uri, root, undefined, silent)); + repositories.push(...this.openRepository(folder, uri, root, silent)); } const uri = await this.findRepositoryUri(rootUri, true); diff --git a/src/env/node/git/vslsGitProvider.ts b/src/env/node/git/vslsGitProvider.ts index f4cf2a68d8b07..6d3773309283b 100644 --- a/src/env/node/git/vslsGitProvider.ts +++ b/src/env/node/git/vslsGitProvider.ts @@ -68,7 +68,7 @@ export class VslsGitProvider extends LocalGitProvider { if (repositories == null || repositories.length === 0) return []; return repositories.flatMap(r => - this.openRepository(undefined, Uri.parse(r.folderUri, true), r.root, undefined, r.closed), + this.openRepository(undefined, Uri.parse(r.folderUri, true), r.root, r.closed), ); } catch (ex) { Logger.error(ex, scope); diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 925d9f9c266f9..ea2bea818f0f5 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -831,13 +831,7 @@ export interface GitProvider extends GitRepositoryProvider, Disposable { options?: { cancellation?: CancellationToken; depth?: number; silent?: boolean }, ): Promise; updateContext?(): void; - openRepository( - folder: WorkspaceFolder | undefined, - uri: Uri, - root: boolean, - suspended?: boolean, - closed?: boolean, - ): Repository[]; + openRepository(folder: WorkspaceFolder | undefined, uri: Uri, root: boolean, closed?: boolean): Repository[]; openRepositoryInitWatcher?(): RepositoryInitWatcher; supports(feature: Features): Promise; diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index a6ee0c872a2f3..2d374bac7f09d 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1612,7 +1612,7 @@ export class GitProviderService implements Disposable { } Logger.log(scope, `Repository found in '${repoUri.toString(true)}'`); - const repositories = provider.openRepository(root?.folder, repoUri, false, undefined, closed); + const repositories = provider.openRepository(root?.folder, repoUri, false, closed); const added: Repository[] = []; diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 8355bb846ed0f..8a44eb4a8e459 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -21,7 +21,7 @@ import type { Deferrable } from '../../system/function/debounce'; import { debounce } from '../../system/function/debounce'; import { filter, groupByMap, join, map, min, some } from '../../system/iterable'; import { getLoggableName, Logger } from '../../system/logger'; -import { getLogScope, startLogScope } from '../../system/logger.scope'; +import { getLogScope, setLogScopeExit, startLogScope } from '../../system/logger.scope'; import { updateRecordValue } from '../../system/object'; import { basename, normalizePath } from '../../system/path'; import type { GitDir, GitProviderDescriptor } from '../gitProvider'; @@ -191,7 +191,6 @@ export class Repository implements Disposable { public readonly folder: WorkspaceFolder | undefined, public readonly uri: Uri, public readonly root: boolean, - suspended: boolean, closed: boolean = false, ) { if (folder != null) { @@ -227,7 +226,7 @@ export class Repository implements Disposable { this.id = asRepoComparisonKey(uri); - this._suspended = suspended; + this._suspended = !window.state.focused; this._closed = closed; this._disposable = Disposable.from( @@ -681,9 +680,13 @@ export class Repository implements Disposable { @debug({ singleLine: true }) resume(): void { - if (!this._suspended) return; - const scope = getLogScope(); + + if (!this._suspended) { + setLogScopeExit(scope, ' \u2022 ignored; not suspended'); + return; + } + this._suspended = false; // If we've come back into focus and we are dirty, fire the change events @@ -875,8 +878,7 @@ export class Repository implements Disposable { this.providerService.onRepositoryChanged(this, this._pendingRepoChange); if (this._suspended) { - Logger.debug(scope, `SUSPENDED: queueing ${this._pendingRepoChange.toString(true)}`); - + Logger.debug(scope, `SUSPENDED: queueing repo changes=${this._pendingRepoChange.toString(true)}`); return; } @@ -884,13 +886,17 @@ export class Repository implements Disposable { } private fireChangeCore() { + using scope = startLogScope(`${getLoggableName(this)}.fireChangeCore`, false); + const e = this._pendingRepoChange; - if (e == null) return; + if (e == null) { + Logger.debug(scope, 'No pending repo changes'); + return; + } this._pendingRepoChange = undefined; - using scope = startLogScope(`${getLoggableName(this)}.fireChangeCore`, false); - Logger.debug(scope, `firing ${e.toString(true)}`); + Logger.debug(scope, `firing repo changes=${e.toString(true)}`); try { this._onDidChange.fire(e); } finally { @@ -913,7 +919,7 @@ export class Repository implements Disposable { if (this._suspended) { Logger.debug( scope, - `queueing suspended fs changes=${join( + `SUSPENDED: queueing fs changes=${join( map(e.uris, u => u.fsPath), ', ', )}`, @@ -925,19 +931,26 @@ export class Repository implements Disposable { } private async fireFileSystemChangeCore() { + using scope = startLogScope(`${getLoggableName(this)}.fireFileSystemChangeCore`, false); + let e = this._pendingFileSystemChange; - if (e == null) return; + if (e == null) { + Logger.debug(scope, 'No pending fs changes'); + return; + } this._pendingFileSystemChange = undefined; const uris = await this.git.excludeIgnoredUris([...e.uris]); - if (!uris.length) return; + if (!uris.length) { + Logger.debug(scope, 'No non-ignored fs changes'); + return; + } if (uris.length !== e.uris.size) { e = { ...e, uris: new UriSet(uris) }; } - using scope = startLogScope(`${getLoggableName(this)}.fireFileSystemChangeCore`, false); Logger.debug( scope, `firing fs changes=${join( diff --git a/src/plus/integrations/providers/github/githubGitProvider.ts b/src/plus/integrations/providers/github/githubGitProvider.ts index 5f27fb718af34..94cc989b7f893 100644 --- a/src/plus/integrations/providers/github/githubGitProvider.ts +++ b/src/plus/integrations/providers/github/githubGitProvider.ts @@ -166,7 +166,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { const workspaceUri = remotehub.getVirtualWorkspaceUri(uri); if (workspaceUri == null) return []; - return this.openRepository(undefined, workspaceUri, true, undefined, options?.silent); + return this.openRepository(undefined, workspaceUri, true, options?.silent); } catch (ex) { if (ex.message.startsWith('No provider registered with')) { Logger.error( @@ -218,13 +218,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { void setContext('gitlens:hasVirtualFolders', this.container.git.hasOpenRepositories(this.descriptor.id)); } - openRepository( - folder: WorkspaceFolder | undefined, - uri: Uri, - root: boolean, - suspended?: boolean, - closed?: boolean, - ): Repository[] { + openRepository(folder: WorkspaceFolder | undefined, uri: Uri, root: boolean, closed?: boolean): Repository[] { return [ new Repository( this.container, @@ -236,7 +230,6 @@ export class GitHubGitProvider implements GitProvider, Disposable { folder ?? workspace.getWorkspaceFolder(uri), uri, root, - suspended ?? !window.state.focused, closed, ), ]; From 62c8dd3411f323c0296d0e553b011f6d338614fb Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 21 Oct 2025 01:18:11 -0400 Subject: [PATCH 44/83] Adds fast checks for working and untracked changes --- src/env/node/git/sub-providers/status.ts | 126 +++++++++++++++++- src/git/gitProvider.ts | 28 ++++ .../providers/github/sub-providers/status.ts | 8 ++ 3 files changed, 161 insertions(+), 1 deletion(-) diff --git a/src/env/node/git/sub-providers/status.ts b/src/env/node/git/sub-providers/status.ts index f2ede6a9dfb02..7300a735c5f33 100644 --- a/src/env/node/git/sub-providers/status.ts +++ b/src/env/node/git/sub-providers/status.ts @@ -1,7 +1,7 @@ import { readdir } from 'fs'; import type { CancellationToken, Uri } from 'vscode'; import type { Container } from '../../../../container'; -import { CancellationError } from '../../../../errors'; +import { CancellationError, isCancellationError } from '../../../../errors'; import type { GitCache } from '../../../../git/cache'; import { GitErrorHandling } from '../../../../git/commandOptions'; import { @@ -606,4 +606,128 @@ export class StatusGitSubProvider implements GitStatusSubProvider { const files = status?.files.filter(f => f.path.startsWith(relativePath)); return files; } + + @gate( + (rp, o) => `${rp ?? ''}:${o?.staged ?? true}:${o?.unstaged ?? true}:${o?.untracked ?? true}`, + ) + @log() + async hasWorkingChanges( + repoPath: string, + options?: { staged?: boolean; unstaged?: boolean; untracked?: boolean }, + cancellation?: CancellationToken, + ): Promise { + const scope = getLogScope(); + + try { + const staged = options?.staged ?? true; + const unstaged = options?.unstaged ?? true; + if (staged || unstaged) { + const result = await this.git.exec( + { + cwd: repoPath, + cancellation: cancellation, + errors: GitErrorHandling.Ignore, + }, + 'diff', + '--quiet', + staged && unstaged ? 'HEAD' : staged ? '--staged' : undefined, + ); + if (result.exitCode === 1) { + if (staged && unstaged) { + setLogScopeExit(scope, ' \u2022 has staged and unstaged changes'); + } else if (staged) { + setLogScopeExit(scope, ' \u2022 has staged changes'); + } else { + setLogScopeExit(scope, ' \u2022 has unstaged changes'); + } + return true; + } + } + + // Check for untracked files + const untracked = options?.untracked ?? true; + if (untracked) { + const hasUntracked = await this.hasUntrackedFiles(repoPath, cancellation); + if (hasUntracked) { + setLogScopeExit(scope, ' \u2022 has untracked files'); + return true; + } + } + + setLogScopeExit(scope, ' \u2022 no working changes'); + return false; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + // Log other errors and return false for graceful degradation + Logger.error(ex, scope); + setLogScopeExit(scope, ' \u2022 error checking for changes'); + return false; + } + } + + private async hasUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { + try { + const stream = this.git.stream( + { + cwd: repoPath, + cancellation: cancellation, + }, + 'ls-files', + '--others', + '--exclude-standard', + ); + + // Early exit on first chunk - breaking causes SIGPIPE, killing git process + for await (const _chunk of stream) { + return true; + } + + return false; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + // Treat other errors as "no untracked files" for graceful degradation + return false; + } + } + + @gate(rp => rp ?? '') + @log() + async getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { + const scope = getLogScope(); + + try { + const result = await this.git.exec( + { + cwd: repoPath, + cancellation: cancellation, + errors: GitErrorHandling.Ignore, + }, + 'ls-files', + '--others', + '--exclude-standard', + ); + + if (!result.stdout) { + setLogScopeExit(scope, ' \u2022 no untracked files'); + return []; + } + + // Split by newlines and filter out empty strings + const files = result.stdout.split('\n').filter(f => f.length > 0); + setLogScopeExit(scope, ` \u2022 ${files.length} untracked file(s)`); + return files; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + // Log other errors and return empty array for graceful degradation + Logger.error(ex, scope); + setLogScopeExit(scope, ' \u2022 error getting untracked files'); + return []; + } + } } diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index ea2bea818f0f5..605839dbe5d81 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -726,6 +726,34 @@ export interface GitStatusSubProvider { ): Promise; abortPausedOperation?(repoPath: string, options?: { quit?: boolean }): Promise; continuePausedOperation?(repoPath: string, options?: { skip?: boolean }): Promise; + + /** + * Quickly check if the repository has any working changes + * @param repoPath Repository path + * @param options Options to control which types of changes to check for + * @param cancellation Cancellation token + * @returns A promise that resolves to true if any of the requested change types exist + */ + hasWorkingChanges( + repoPath: string, + options?: { + /** Check for staged changes (default: true) */ + staged?: boolean; + /** Check for unstaged changes (default: true) */ + unstaged?: boolean; + /** Check for untracked files (default: true) */ + untracked?: boolean; + }, + cancellation?: CancellationToken, + ): Promise; + + /** + * Get all untracked files in the repository + * @param repoPath Repository path + * @param cancellation Cancellation token + * @returns A promise that resolves to an array of untracked file paths (relative to repo root) + */ + getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise; } export interface GitTagsSubProvider { diff --git a/src/plus/integrations/providers/github/sub-providers/status.ts b/src/plus/integrations/providers/github/sub-providers/status.ts index 03df545ce5971..345603312e2af 100644 --- a/src/plus/integrations/providers/github/sub-providers/status.ts +++ b/src/plus/integrations/providers/github/sub-providers/status.ts @@ -35,4 +35,12 @@ export class StatusGitSubProvider implements GitStatusSubProvider { : undefined, ); } + + hasWorkingChanges(): Promise { + return Promise.resolve(false); + } + + getUntrackedFiles(): Promise { + return Promise.resolve([]); + } } From 447d29aeb59d94f995350a8dd08370cc19d6e494 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Tue, 21 Oct 2025 10:58:05 -0400 Subject: [PATCH 45/83] Fixes action color on the merge rebase status component --- src/webviews/apps/plus/shared/components/merge-rebase-status.ts | 2 ++ src/webviews/apps/shared/components/actions/action-item.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/webviews/apps/plus/shared/components/merge-rebase-status.ts b/src/webviews/apps/plus/shared/components/merge-rebase-status.ts index f5de7178996d0..08076a5724169 100644 --- a/src/webviews/apps/plus/shared/components/merge-rebase-status.ts +++ b/src/webviews/apps/plus/shared/components/merge-rebase-status.ts @@ -15,6 +15,7 @@ export class GlMergeConflictWarning extends LitElement { static override styles = [ css` .status { + --action-item-foreground: #000; box-sizing: border-box; display: flex; align-items: center; @@ -29,6 +30,7 @@ export class GlMergeConflictWarning extends LitElement { } :host([conflicts]) .status { + --action-item-foreground: #fff; background-color: var(--vscode-gitlens-decorations\\.statusMergingOrRebasingConflictForegroundColor); color: #fff; } diff --git a/src/webviews/apps/shared/components/actions/action-item.ts b/src/webviews/apps/shared/components/actions/action-item.ts index e0392d7f74fd1..6f6657e585517 100644 --- a/src/webviews/apps/shared/components/actions/action-item.ts +++ b/src/webviews/apps/shared/components/actions/action-item.ts @@ -21,7 +21,7 @@ export class ActionItem extends LitElement { width: 2rem; height: 2rem; border-radius: 0.5rem; - color: var(--vscode-icon-foreground); + color: var(--action-item-foreground, var(--vscode-icon-foreground)); padding: 0.2rem; vertical-align: text-bottom; text-decoration: none; From 18ef0863650d2958c0a7aa3c6cc1714666adb100 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 21 Oct 2025 10:00:12 -0400 Subject: [PATCH 46/83] Adds new optimized `getWorkingChangesState` method - Efficiently check for staged, unstaged, and untracked changes --- src/env/node/git/sub-providers/status.ts | 68 +++++++++++++++---- src/git/gitProvider.ts | 14 ++++ .../providers/github/sub-providers/status.ts | 6 +- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/env/node/git/sub-providers/status.ts b/src/env/node/git/sub-providers/status.ts index 7300a735c5f33..42390a3d81b19 100644 --- a/src/env/node/git/sub-providers/status.ts +++ b/src/env/node/git/sub-providers/status.ts @@ -10,7 +10,7 @@ import { PausedOperationContinueError, PausedOperationContinueErrorReason, } from '../../../../git/errors'; -import type { GitStatusSubProvider } from '../../../../git/gitProvider'; +import type { GitStatusSubProvider, GitWorkingChangesState } from '../../../../git/gitProvider'; import type { GitCherryPickStatus, GitMergeStatus, @@ -623,11 +623,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { const unstaged = options?.unstaged ?? true; if (staged || unstaged) { const result = await this.git.exec( - { - cwd: repoPath, - cancellation: cancellation, - errors: GitErrorHandling.Ignore, - }, + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, 'diff', '--quiet', staged && unstaged ? 'HEAD' : staged ? '--staged' : undefined, @@ -670,10 +666,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { private async hasUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { try { const stream = this.git.stream( - { - cwd: repoPath, - cancellation: cancellation, - }, + { cwd: repoPath, cancellation: cancellation }, 'ls-files', '--others', '--exclude-standard', @@ -694,6 +687,55 @@ export class StatusGitSubProvider implements GitStatusSubProvider { } } + @gate(rp => rp ?? '') + @log() + async getWorkingChangesState(repoPath: string, cancellation?: CancellationToken): Promise { + const scope = getLogScope(); + + try { + const [stagedResult, unstagedResult, untrackedResult] = await Promise.allSettled([ + // Check for staged changes + this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'diff', + '--quiet', + '--staged', + ), + // Check for unstaged changes + this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'diff', + '--quiet', + ), + // Check for untracked files + this.hasUntrackedFiles(repoPath, cancellation), + ]); + + const result = { + staged: Boolean(stagedResult.status === 'fulfilled' && stagedResult.value.exitCode === 1), + unstaged: Boolean(unstagedResult.status === 'fulfilled' && unstagedResult.value.exitCode === 1), + untracked: untrackedResult.status === 'fulfilled' && untrackedResult.value === true, + }; + + setLogScopeExit( + scope, + result.staged || result.unstaged || result.untracked + ? ` \u2022 has ${result.staged ? 'staged' : ''}${result.unstaged ? (result.staged ? ', unstaged' : 'unstaged ') : ''}${ + result.untracked ? (result.staged || result.unstaged ? ', untracked' : 'untracked') : '' + } changes` + : ' \u2022 no working changes', + ); + + return result; + } catch (ex) { + if (isCancellationError(ex)) throw ex; + Logger.error(ex, scope); + setLogScopeExit(scope, ' \u2022 error checking for changes'); + // Return all false on error for graceful degradation + return { staged: false, unstaged: false, untracked: false }; + } + } + @gate(rp => rp ?? '') @log() async getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { @@ -701,11 +743,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { try { const result = await this.git.exec( - { - cwd: repoPath, - cancellation: cancellation, - errors: GitErrorHandling.Ignore, - }, + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, 'ls-files', '--others', '--exclude-standard', diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 605839dbe5d81..8c2281f2edcc9 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -680,6 +680,12 @@ export interface GitStashSubProvider { saveSnapshot(repoPath: string, message?: string): Promise; } +export interface GitWorkingChangesState { + staged: boolean; + unstaged: boolean; + untracked: boolean; +} + export interface GitStatusSubProvider { /** * Get the status of the repository @@ -747,6 +753,14 @@ export interface GitStatusSubProvider { cancellation?: CancellationToken, ): Promise; + /** + * Get detailed information about all types of working changes in a single optimized call + * @param repoPath The repository path + * @param cancellation Cancellation token + * @returns A promise that resolves to an object with boolean flags for each change type + */ + getWorkingChangesState(repoPath: string, cancellation?: CancellationToken): Promise; + /** * Get all untracked files in the repository * @param repoPath Repository path diff --git a/src/plus/integrations/providers/github/sub-providers/status.ts b/src/plus/integrations/providers/github/sub-providers/status.ts index 345603312e2af..e201a57d3f411 100644 --- a/src/plus/integrations/providers/github/sub-providers/status.ts +++ b/src/plus/integrations/providers/github/sub-providers/status.ts @@ -1,6 +1,6 @@ import type { CancellationToken } from 'vscode'; import type { Container } from '../../../../../container'; -import type { GitStatusSubProvider } from '../../../../../git/gitProvider'; +import type { GitStatusSubProvider, GitWorkingChangesState } from '../../../../../git/gitProvider'; import { GitStatus } from '../../../../../git/models/status'; import { gate } from '../../../../../system/decorators/gate'; import { log } from '../../../../../system/decorators/log'; @@ -40,6 +40,10 @@ export class StatusGitSubProvider implements GitStatusSubProvider { return Promise.resolve(false); } + getWorkingChangesState(): Promise { + return Promise.resolve({ staged: false, unstaged: false, untracked: false }); + } + getUntrackedFiles(): Promise { return Promise.resolve([]); } From eaba341ac8b849b8f93dd35ebf2320af68f75e6c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 21 Oct 2025 22:53:08 -0400 Subject: [PATCH 47/83] Updates comment with explanation --- src/env/node/git/git.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 33fa49af8b780..83b827154695e 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -533,7 +533,11 @@ export class Git implements Disposable { } } } finally { - // I have NO idea why this HAS to be in a finally block, but it does + // This await MUST be in this inner finally block to ensure the child process close event completes + // before we call removeAllListeners() in the outer finally. When consumers break early from the + // async generator (e.g., reading only the first chunk), the git process receives SIGPIPE and triggers + // the close handler asynchronously. Without awaiting here, removeAllListeners() would execute before + // the close handler finishes, causing a race condition and potential resource leaks. await promise; } } catch (ex) { From fa9a20049c5944c25829c107b8d9b7f957f1d3c3 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 00:18:59 -0400 Subject: [PATCH 48/83] Adds faster conflict file detection Changes untracked file to use GitFile rather than strings Fixes path issues in untracked files & tree file parsing --- src/env/node/git/sub-providers/revision.ts | 4 +- src/env/node/git/sub-providers/status.ts | 117 ++++++++--- src/git/gitProvider.ts | 19 +- src/git/models/index.ts | 27 +++ src/git/models/tree.ts | 7 - src/git/parsers/indexParser.ts | 186 ++++++++++++++++++ src/git/parsers/treeParser.ts | 56 +----- .../providers/github/sub-providers/status.ts | 12 +- 8 files changed, 334 insertions(+), 94 deletions(-) create mode 100644 src/git/models/index.ts create mode 100644 src/git/parsers/indexParser.ts diff --git a/src/env/node/git/sub-providers/revision.ts b/src/env/node/git/sub-providers/revision.ts index 4d57f530a8fa0..83661f23850f3 100644 --- a/src/env/node/git/sub-providers/revision.ts +++ b/src/env/node/git/sub-providers/revision.ts @@ -6,8 +6,9 @@ import type { GitRevisionSubProvider, ResolvedRevision } from '../../../../git/g import type { GitFileStatus } from '../../../../git/models/fileStatus'; import { deletedOrMissing } from '../../../../git/models/revision'; import type { GitTreeEntry } from '../../../../git/models/tree'; +import { parseGitLsFilesStaged } from '../../../../git/parsers/indexParser'; import { getShaAndFileSummaryLogParser } from '../../../../git/parsers/logParser'; -import { parseGitLsFilesStaged, parseGitTree } from '../../../../git/parsers/treeParser'; +import { parseGitTree } from '../../../../git/parsers/treeParser'; import { isRevisionWithSuffix, isSha, @@ -79,6 +80,7 @@ export class RevisionGitSubProvider implements GitRevisionSubProvider { let result = await this.git.exec( { cwd: root, errors: GitErrorHandling.Ignore }, 'ls-files', + '-z', '--stage', '--', relativePath, diff --git a/src/env/node/git/sub-providers/status.ts b/src/env/node/git/sub-providers/status.ts index 42390a3d81b19..158e699185d7d 100644 --- a/src/env/node/git/sub-providers/status.ts +++ b/src/env/node/git/sub-providers/status.ts @@ -11,6 +11,9 @@ import { PausedOperationContinueErrorReason, } from '../../../../git/errors'; import type { GitStatusSubProvider, GitWorkingChangesState } from '../../../../git/gitProvider'; +import type { GitConflictFile } from '../../../../git/models'; +import type { GitFile } from '../../../../git/models/file'; +import { GitFileWorkingTreeStatus } from '../../../../git/models/fileStatus'; import type { GitCherryPickStatus, GitMergeStatus, @@ -21,6 +24,7 @@ import type { import type { GitBranchReference, GitTagReference } from '../../../../git/models/reference'; import { GitStatus } from '../../../../git/models/status'; import type { GitStatusFile } from '../../../../git/models/statusFile'; +import { parseGitConflictFiles } from '../../../../git/parsers/indexParser'; import { parseGitStatus } from '../../../../git/parsers/statusParser'; import { createReference } from '../../../../git/utils/reference.utils'; import { configuration } from '../../../../system/-webview/configuration'; @@ -31,6 +35,7 @@ import { Logger } from '../../../../system/logger'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; import { stripFolderGlob } from '../../../../system/path'; import { getSettledValue } from '../../../../system/promise'; +import { iterateByDelimiter } from '../../../../system/string'; import type { Git } from '../git'; import { GitErrors } from '../git'; import type { LocalGitProvider } from '../localGitProvider'; @@ -663,30 +668,6 @@ export class StatusGitSubProvider implements GitStatusSubProvider { } } - private async hasUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { - try { - const stream = this.git.stream( - { cwd: repoPath, cancellation: cancellation }, - 'ls-files', - '--others', - '--exclude-standard', - ); - - // Early exit on first chunk - breaking causes SIGPIPE, killing git process - for await (const _chunk of stream) { - return true; - } - - return false; - } catch (ex) { - // Re-throw cancellation errors - if (isCancellationError(ex)) throw ex; - - // Treat other errors as "no untracked files" for graceful degradation - return false; - } - } - @gate(rp => rp ?? '') @log() async getWorkingChangesState(repoPath: string, cancellation?: CancellationToken): Promise { @@ -736,15 +717,91 @@ export class StatusGitSubProvider implements GitStatusSubProvider { } } + async hasConflictingFiles(repoPath: string, cancellation?: CancellationToken): Promise { + try { + const stream = this.git.stream({ cwd: repoPath, cancellation: cancellation }, 'ls-files', '--unmerged'); + + // Early exit on first chunk - breaking causes SIGPIPE, killing git process + for await (const _chunk of stream) { + return true; + } + + return false; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + return false; + } + } + + @gate(rp => rp ?? '') + @log() + async getConflictingFiles(repoPath: string, cancellation?: CancellationToken): Promise { + const scope = getLogScope(); + + try { + const result = await this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'ls-files', + '-z', + '--unmerged', + ); + + if (!result.stdout) { + setLogScopeExit(scope, ' \u2022 no conflicting files'); + return []; + } + + const files = parseGitConflictFiles(result.stdout, repoPath); + setLogScopeExit(scope, ` \u2022 ${files.length} conflicting file(s)`); + return files; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + // Log other errors and return empty array for graceful degradation + Logger.error(ex, scope); + setLogScopeExit(scope, ' \u2022 error getting conflicting files'); + return []; + } + } + + private async hasUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { + try { + const stream = this.git.stream( + { cwd: repoPath, cancellation: cancellation }, + 'ls-files', + // '-z', // Unneeded since we are only looking for presence + '--others', + '--exclude-standard', + ); + + // Early exit on first chunk - breaking causes SIGPIPE, killing git process + for await (const _chunk of stream) { + return true; + } + + return false; + } catch (ex) { + // Re-throw cancellation errors + if (isCancellationError(ex)) throw ex; + + // Treat other errors as "no untracked files" for graceful degradation + return false; + } + } + @gate(rp => rp ?? '') @log() - async getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { + async getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise { const scope = getLogScope(); try { const result = await this.git.exec( { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, 'ls-files', + '-z', '--others', '--exclude-standard', ); @@ -754,8 +811,14 @@ export class StatusGitSubProvider implements GitStatusSubProvider { return []; } - // Split by newlines and filter out empty strings - const files = result.stdout.split('\n').filter(f => f.length > 0); + const files: GitFile[] = []; + + for (const line of iterateByDelimiter(result.stdout, '\0')) { + if (!line.length) continue; + + files.push({ path: line, repoPath: repoPath, status: GitFileWorkingTreeStatus.Untracked }); + } + setLogScopeExit(scope, ` \u2022 ${files.length} untracked file(s)`); return files; } catch (ex) { diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 8c2281f2edcc9..0ccc2d225dba0 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -8,6 +8,7 @@ import type { Features } from '../features'; import type { GitHostIntegration } from '../plus/integrations/models/gitHostIntegration'; import type { UnifiedAsyncDisposable } from '../system/unifiedDisposable'; import type { GitUri } from './gitUri'; +import type { GitConflictFile } from './models'; import type { GitBlame, GitBlameLine } from './models/blame'; import type { GitBranch } from './models/branch'; import type { GitCommit, GitCommitStats, GitStashCommit } from './models/commit'; @@ -752,7 +753,6 @@ export interface GitStatusSubProvider { }, cancellation?: CancellationToken, ): Promise; - /** * Get detailed information about all types of working changes in a single optimized call * @param repoPath The repository path @@ -760,14 +760,27 @@ export interface GitStatusSubProvider { * @returns A promise that resolves to an object with boolean flags for each change type */ getWorkingChangesState(repoPath: string, cancellation?: CancellationToken): Promise; - + /** + * Quickly check if the repository has any conflicting files + * @param repoPath Repository path + * @param cancellation Cancellation token + * @returns A promise that resolves to true if there are any unmerged files + */ + hasConflictingFiles(repoPath: string, cancellation?: CancellationToken): Promise; + /** + * Get all conflicting files in the repository with detailed stage information + * @param repoPath Repository path + * @param cancellation Cancellation token + * @returns A promise that resolves to an array of conflicting files with stage information + */ + getConflictingFiles(repoPath: string, cancellation?: CancellationToken): Promise; /** * Get all untracked files in the repository * @param repoPath Repository path * @param cancellation Cancellation token * @returns A promise that resolves to an array of untracked file paths (relative to repo root) */ - getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise; + getUntrackedFiles(repoPath: string, cancellation?: CancellationToken): Promise; } export interface GitTagsSubProvider { diff --git a/src/git/models/index.ts b/src/git/models/index.ts new file mode 100644 index 0000000000000..2cee564cd622b --- /dev/null +++ b/src/git/models/index.ts @@ -0,0 +1,27 @@ +import type { GitFile } from './file'; +import type { GitFileConflictStatus } from './fileStatus'; + +export type GitIndexVersion = 'normal' | 'base' | 'current' | 'incoming'; +export interface GitIndexFile { + mode: string; + oid: string; + path: string; + version: GitIndexVersion | undefined; +} + +export interface GitConflictRevision { + readonly mode: string; + readonly oid: string; + readonly version: GitIndexVersion | undefined; +} + +export interface GitConflictFile extends GitFile { + readonly path: string; + readonly repoPath: string; + readonly status: GitFileConflictStatus; + readonly conflictStatus: GitFileConflictStatus; + + readonly base?: GitConflictRevision; + readonly current?: GitConflictRevision; + readonly incoming?: GitConflictRevision; +} diff --git a/src/git/models/tree.ts b/src/git/models/tree.ts index ec2f2ad4a3f51..5fab6814809ff 100644 --- a/src/git/models/tree.ts +++ b/src/git/models/tree.ts @@ -5,10 +5,3 @@ export interface GitTreeEntry { size: number; type: 'blob' | 'tree'; } - -export interface GitLsFilesEntry { - mode: string; - oid: string; - path: string; - stage: number; -} diff --git a/src/git/parsers/indexParser.ts b/src/git/parsers/indexParser.ts new file mode 100644 index 0000000000000..16e66c0f5912a --- /dev/null +++ b/src/git/parsers/indexParser.ts @@ -0,0 +1,186 @@ +import { maybeStopWatch } from '../../system/stopwatch'; +import { iterateByDelimiter } from '../../system/string'; +import type { GitConflictFile, GitConflictRevision, GitIndexFile, GitIndexVersion } from '../models'; +import { GitFileConflictStatus } from '../models/fileStatus'; + +export function parseGitLsFilesStaged(data: string | undefined, singleEntry: boolean): GitIndexFile[] { + using sw = maybeStopWatch(`Git.parseLsFiles`, { log: false, logLevel: 'debug' }); + + const files: GitIndexFile[] = []; + if (!data) { + sw?.stop({ suffix: ` no data` }); + return files; + } + + // Format: \t\0 + // Using -z flag ensures filenames are NUL-delimited and not quoted + + let metadata: string; + let mode: string; + let oid: string; + let stage: number; + let path: string; + + let startIndex = 0; + let endIndex = 0; + let tabIndex = 0; + + // Avoid generator if we are only parsing a single entry + for (const line of singleEntry ? data.split('\0') : iterateByDelimiter(data, '\0')) { + if (!line) continue; + + // Split on tab to separate metadata from path + tabIndex = line.indexOf('\t'); + if (tabIndex === -1) continue; + + metadata = line.substring(0, tabIndex); + path = line.substring(tabIndex + 1); + + // Parse mode + startIndex = 0; + endIndex = metadata.indexOf(' ', startIndex); + if (endIndex === -1) continue; + + mode = metadata.substring(startIndex, endIndex); + + // Parse oid + startIndex = endIndex + 1; + endIndex = metadata.indexOf(' ', startIndex); + if (endIndex === -1) continue; + + oid = metadata.substring(startIndex, endIndex); + + // Parse stage + startIndex = endIndex + 1; + + stage = parseInt(metadata.substring(startIndex), 10); + + files.push({ mode: mode, oid: oid, path: path, version: convertStageToVersion(isNaN(stage) ? 0 : stage) }); + } + + sw?.stop({ suffix: ` parsed ${files.length} files` }); + + return files; +} + +export function parseGitConflictFiles(data: string | undefined, repoPath: string): GitConflictFile[] { + using sw = maybeStopWatch(`Git.parseConflictFiles`, { log: false, logLevel: 'debug' }); + + if (!data) { + sw?.stop({ suffix: ` no data` }); + return []; + } + + // Format: \t\0 + // Using -z flag ensures filenames are NUL-delimited and not quoted + + const files = new Map>(); + + let metadata: string; + let mode: string; + let oid: string; + let stage: number; + let path: string; + let revision: GitConflictRevision; + + let startIndex = 0; + let endIndex = 0; + let tabIndex = 0; + + for (const line of iterateByDelimiter(data, '\0')) { + if (!line) continue; + + tabIndex = line.indexOf('\t'); + if (tabIndex === -1) continue; + + metadata = line.substring(0, tabIndex); + path = line.substring(tabIndex + 1); + + // Parse mode + startIndex = 0; + endIndex = metadata.indexOf(' ', startIndex); + if (endIndex === -1) continue; + + mode = metadata.substring(startIndex, endIndex); + + // Parse oid + startIndex = endIndex + 1; + endIndex = metadata.indexOf(' ', startIndex); + if (endIndex === -1) continue; + + oid = metadata.substring(startIndex, endIndex); + + // Parse stage + startIndex = endIndex + 1; + + stage = parseInt(metadata.substring(startIndex), 10); + + revision = { mode: mode, oid: oid, version: convertStageToVersion(stage) }; + + // Get or create file entry + let file = files.get(path); + if (!file) { + file = { + path: path, + repoPath: repoPath, + get status(): GitFileConflictStatus { + const pattern = + (this.base != null ? 4 : 0) | (this.current != null ? 2 : 0) | (this.incoming != null ? 1 : 0); + + switch (pattern) { + case 0b001: + return GitFileConflictStatus.AddedByThem; // UA + case 0b010: + return GitFileConflictStatus.AddedByUs; // AU + case 0b011: + return GitFileConflictStatus.AddedByBoth; // AA + case 0b101: + return GitFileConflictStatus.DeletedByUs; // DU + case 0b110: + return GitFileConflictStatus.DeletedByThem; // UD + case 0b111: + return GitFileConflictStatus.ModifiedByBoth; // UU + default: + return GitFileConflictStatus.DeletedByBoth; // DD (0b000, 0b100) + } + }, + get conflictStatus(): GitFileConflictStatus { + return this.status; + }, + }; + files.set(path, file); + } + + // Assign revision appropriate version (stage) + switch (stage) { + case 1: + file.base = revision; + break; + case 2: + file.current = revision; + break; + case 3: + file.incoming = revision; + break; + } + } + + sw?.stop({ suffix: ` parsed ${files.size} conflict files` }); + + return [...files.values()]; +} + +function convertStageToVersion(stage: number): GitIndexVersion | undefined { + switch (stage) { + case 0: + return 'normal'; + case 1: + return 'base'; + case 2: + return 'current'; + case 3: + return 'incoming'; + default: + return undefined; + } +} diff --git a/src/git/parsers/treeParser.ts b/src/git/parsers/treeParser.ts index 47eda824e19a3..58a7561a11305 100644 --- a/src/git/parsers/treeParser.ts +++ b/src/git/parsers/treeParser.ts @@ -1,6 +1,6 @@ import { maybeStopWatch } from '../../system/stopwatch'; import { iterateByDelimiter } from '../../system/string'; -import type { GitLsFilesEntry, GitTreeEntry } from '../models/tree'; +import type { GitTreeEntry } from '../models/tree'; export function parseGitTree(data: string | undefined, ref: string, singleEntry: boolean): GitTreeEntry[] { using sw = maybeStopWatch(`Git.parseTree`, { log: false, logLevel: 'debug' }); @@ -59,57 +59,3 @@ export function parseGitTree(data: string | undefined, ref: string, singleEntry: return trees; } - -export function parseGitLsFilesStaged(data: string | undefined, singleEntry: boolean): GitLsFilesEntry[] { - using sw = maybeStopWatch(`Git.parseLsFiles`, { log: false, logLevel: 'debug' }); - - const files: GitLsFilesEntry[] = []; - if (!data) { - sw?.stop({ suffix: ` no data` }); - return files; - } - - // Format: \t - - let metadata: string; - let mode: string; - let oid: string; - let stage: number; - let path: string; - - let startIndex = 0; - let endIndex = 0; - - // Avoid generator if we are only parsing a single entry - for (let line of singleEntry ? data.split('\n') : iterateByDelimiter(data, '\n')) { - line = line.trim(); - if (!line) continue; - - [metadata, path] = line.split(/\t/); - - // Parse mode - startIndex = 0; - endIndex = metadata.indexOf(' ', startIndex); - if (endIndex === -1) continue; - - mode = metadata.substring(startIndex, endIndex); - - // Parse oid - startIndex = endIndex + 1; - endIndex = metadata.indexOf(' ', startIndex); - if (endIndex === -1) continue; - - oid = metadata.substring(startIndex, endIndex); - - // Parse stage - startIndex = endIndex + 1; - - stage = parseInt(metadata.substring(startIndex), 10); - - files.push({ mode: mode, oid: oid, path: path, stage: isNaN(stage) ? 0 : stage }); - } - - sw?.stop({ suffix: ` parsed ${files.length} files` }); - - return files; -} diff --git a/src/plus/integrations/providers/github/sub-providers/status.ts b/src/plus/integrations/providers/github/sub-providers/status.ts index e201a57d3f411..9d95ba9ef5ad4 100644 --- a/src/plus/integrations/providers/github/sub-providers/status.ts +++ b/src/plus/integrations/providers/github/sub-providers/status.ts @@ -1,6 +1,8 @@ import type { CancellationToken } from 'vscode'; import type { Container } from '../../../../../container'; import type { GitStatusSubProvider, GitWorkingChangesState } from '../../../../../git/gitProvider'; +import type { GitConflictFile } from '../../../../../git/models'; +import type { GitFile } from '../../../../../git/models/file'; import { GitStatus } from '../../../../../git/models/status'; import { gate } from '../../../../../system/decorators/gate'; import { log } from '../../../../../system/decorators/log'; @@ -44,7 +46,15 @@ export class StatusGitSubProvider implements GitStatusSubProvider { return Promise.resolve({ staged: false, unstaged: false, untracked: false }); } - getUntrackedFiles(): Promise { + hasConflictingFiles(): Promise { + return Promise.resolve(false); + } + + getConflictingFiles(): Promise { + return Promise.resolve([]); + } + + getUntrackedFiles(): Promise { return Promise.resolve([]); } } From d7ac16e10e3465e1cf99c0d365ae377d97b0e067 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 00:24:06 -0400 Subject: [PATCH 49/83] Refactors status checks to use new optimized calls --- src/commands/generateRebase.ts | 4 ++-- src/commands/git/worktree.ts | 4 +--- src/commands/patches.ts | 4 +--- src/env/node/git/sub-providers/patch.ts | 4 ++-- src/git/actions/commit.ts | 5 +++-- src/webviews/plus/composer/composerWebview.ts | 6 ++---- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/commands/generateRebase.ts b/src/commands/generateRebase.ts index 8bb21fb1a3cbe..67361230bc2a8 100644 --- a/src/commands/generateRebase.ts +++ b/src/commands/generateRebase.ts @@ -243,8 +243,8 @@ export class UndoGenerateRebaseCommand extends GlCommandBase { if (result !== confirm) return; // Check if there are working tree changes and stash them - const status = await svc.status.getStatus(); - if (status?.files && status.files.length > 0) { + const hasChanges = await svc.status.hasWorkingChanges(); + if (hasChanges) { await svc.stash?.saveStash(undefined, undefined, { includeUntracked: true }); } diff --git a/src/commands/git/worktree.ts b/src/commands/git/worktree.ts index 4ba507e65f611..998ca16e3667e 100644 --- a/src/commands/git/worktree.ts +++ b/src/commands/git/worktree.ts @@ -1201,9 +1201,7 @@ export class WorktreeGitCommand extends QuickCommand { try { if (state.changes.type !== 'index') { // stage any untracked files to include them in the diff - const status = await sourceSvc.status.getStatus(); - - untrackedPaths = status?.untrackedChanges.map(f => f.path); + untrackedPaths = (await sourceSvc.status?.getUntrackedFiles())?.map(f => f.path); if (untrackedPaths?.length) { try { await sourceSvc.staging?.stageFiles(untrackedPaths); diff --git a/src/commands/patches.ts b/src/commands/patches.ts index 62ea6e626d221..d9c262e37efce 100644 --- a/src/commands/patches.ts +++ b/src/commands/patches.ts @@ -171,9 +171,7 @@ abstract class CreatePatchCommandBase extends GlCommandBase { try { if (args?.to === uncommitted) { // stage any untracked files to include them in the diff - const status = await repo.git.status?.getStatus(); - - untrackedPaths = status?.untrackedChanges.map(f => f.path); + untrackedPaths = (await repo.git.status?.getUntrackedFiles())?.map(f => f.path); if (untrackedPaths?.length) { try { await repo.git.staging?.stageFiles(untrackedPaths); diff --git a/src/env/node/git/sub-providers/patch.ts b/src/env/node/git/sub-providers/patch.ts index f731e7d7adddc..4578a05af6acc 100644 --- a/src/env/node/git/sub-providers/patch.ts +++ b/src/env/node/git/sub-providers/patch.ts @@ -40,8 +40,8 @@ export class PatchGitSubProvider implements GitPatchSubProvider { if (options?.stash) { // Stash any changes first - const status = await this.provider.status?.getStatus(repoPath); - if (status?.files?.length) { + const hasChanges = await this.provider.status?.hasWorkingChanges(repoPath); + if (hasChanges) { if (options.stash === 'prompt') { const confirm = { title: 'Stash Changes' }; const cancel = { title: 'Cancel', isCloseAffordance: true }; diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index d4cf35fe1c2de..67ce99ce49b79 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -801,8 +801,9 @@ export async function undoCommit(container: Container, commit: GitRevisionRefere return; } - const status = await svc.status.getStatus(); - if (status?.files.length) { + // Check for uncommitted changes before prompting + const hasChanges = await svc.status.hasWorkingChanges(); + if (hasChanges) { const confirm = { title: 'Undo Commit' }; const cancel = { title: 'Cancel', isCloseAffordance: true }; const result = await window.showWarningMessage( diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index 973cc526fd5ad..dc0d37776ffdd 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -306,8 +306,7 @@ export class ComposerWebviewProvider implements WebviewProvider { // Stop repo change subscription so we can deal with untracked files this._repositorySubscription?.dispose(); - const status = await repo.git.status?.getStatus(); - const untrackedPaths = status?.untrackedChanges.map(f => f.path); + const untrackedPaths = (await repo.git.status?.getUntrackedFiles())?.map(f => f.path); if (untrackedPaths?.length) { try { await repo.git.staging?.stageFiles(untrackedPaths, { intentToAdd: true }); @@ -1096,8 +1095,7 @@ export class ComposerWebviewProvider implements WebviewProvider f.path); + const untrackedPaths = (await repo.git.status?.getUntrackedFiles())?.map(f => f.path); if (untrackedPaths?.length) { try { workingTreeDiffs = await getWorkingTreeDiffs(repo); From e1cd489fef3a9a2fd75699668be4f10e3bf35c11 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 00:33:31 -0400 Subject: [PATCH 50/83] Adds batching to stage/unstage for large file sets --- src/env/node/git/sub-providers/staging.ts | 35 ++++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/env/node/git/sub-providers/staging.ts b/src/env/node/git/sub-providers/staging.ts index 54e76b8fe1e41..a5e4b7b95550e 100644 --- a/src/env/node/git/sub-providers/staging.ts +++ b/src/env/node/git/sub-providers/staging.ts @@ -4,12 +4,14 @@ import type { Uri } from 'vscode'; import type { Container } from '../../../../container'; import type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '../../../../git/gitProvider'; import { splitPath } from '../../../../system/-webview/path'; +import { chunk, countStringLength } from '../../../../system/array'; import { log } from '../../../../system/decorators/log'; import { Logger } from '../../../../system/logger'; import { joinPaths } from '../../../../system/path'; import { mixinAsyncDisposable } from '../../../../system/unifiedDisposable'; import { scope } from '../../../../webviews/commitDetails/protocol'; import type { Git } from '../git'; +import { maxGitCliLength } from '../git'; export class StagingGitSubProvider implements GitStagingSubProvider { constructor( @@ -86,13 +88,17 @@ export class StagingGitSubProvider implements GitStagingSubProvider { pathOrUri: string[] | Uri[], options?: { intentToAdd?: boolean }, ): Promise { - await this.git.exec( - { cwd: repoPath }, - 'add', - options?.intentToAdd ? '-N' : '-A', - '--', - ...pathOrUri.map(p => (typeof p === 'string' ? p : splitPath(p, repoPath)[0])), - ); + const pathspecs = pathOrUri.map(p => (typeof p === 'string' ? p : splitPath(p, repoPath)[0])); + + // Calculate a safe batch size based on average path length + const avgPathLength = countStringLength(pathspecs) / pathspecs.length; + const batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength)); + + // Process files in batches (will be a single batch if under the limit) + const batches = chunk(pathspecs, batchSize); + for (const batch of batches) { + await this.git.exec({ cwd: repoPath }, 'add', options?.intentToAdd ? '-N' : '-A', '--', ...batch); + } } @log() @@ -113,10 +119,17 @@ export class StagingGitSubProvider implements GitStagingSubProvider { @log() async unstageFiles(repoPath: string, pathOrUri: string[] | Uri[]): Promise { - await this.git.reset( - repoPath, - pathOrUri.map(p => (typeof p === 'string' ? p : splitPath(p, repoPath)[0])), - ); + const pathspecs = pathOrUri.map(p => (typeof p === 'string' ? p : splitPath(p, repoPath)[0])); + + // Calculate a safe batch size based on average path length + const avgPathLength = countStringLength(pathspecs) / pathspecs.length; + const batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength)); + + // Process files in batches (will be a single batch if under the limit) + const batches = chunk(pathspecs, batchSize); + for (const batch of batches) { + await this.git.reset(repoPath, batch); + } } @log() From ef538ea6fd9a7910964681d7d9b1ce1bdefea4b9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Oct 2025 20:10:43 -0400 Subject: [PATCH 51/83] Optimizes IPC with compression and tagged types - Adds deflate compression for IPC messages over 1KB - Adds IPC tagged types for serialization of Dates, URIs, & Promises - Adds vscode-uri for reliable URI serialization to webviews - Improves commit/graph details by using promises for enriched state - Removes `Serialized` type in favor of new `IpcSerialized` type --- ThirdPartyNotices.txt | 17 +- package.json | 3 +- pnpm-lock.yaml | 3 + src/env/browser/json.ts | 100 +++++++- src/env/node/json.ts | 123 ++++++++-- src/system/ipcSerialize.ts | 53 +++++ .../apps/commitDetails/commitDetails.ts | 8 +- .../components/gl-commit-details.ts | 74 ++++-- src/webviews/apps/commitDetails/context.ts | 4 +- .../apps/commitDetails/stateProvider.ts | 49 +--- .../apps/shared/__tests__/ipc.test.ts | 223 ++++++++++++++++++ src/webviews/apps/shared/appHost.ts | 3 +- .../components/converters/date-converter.ts | 3 + .../apps/shared/components/formatted-date.ts | 2 +- src/webviews/apps/shared/ipc.ts | 43 ++-- .../commitDetails/commitDetailsWebview.ts | 184 ++++++--------- src/webviews/commitDetails/protocol.ts | 16 +- src/webviews/commitDetails/registration.ts | 19 +- src/webviews/ipc.ts | 66 +++++- src/webviews/plus/graph/protocol.ts | 9 +- src/webviews/protocol.ts | 14 +- src/webviews/webviewController.ts | 138 +++++------ 22 files changed, 822 insertions(+), 332 deletions(-) create mode 100644 src/system/ipcSerialize.ts create mode 100644 src/webviews/apps/shared/__tests__/ipc.test.ts diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index da8ac242d51db..d0495a83c30e6 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -37,6 +37,7 @@ This project incorporates components from the projects listed below. 32. signal-utils version 0.21.1 (https://github.com/proposal-signals/signal-utils) 33. slug version 11.0.0 (https://github.com/Trott/slug) 34. sortablejs version 1.15.6 (https://github.com/SortableJS/Sortable) +35. vscode-uri version 3.1.0 (https://github.com/microsoft/vscode-uri) %% @gk-nzaytsev/fast-string-truncated-width NOTICES AND INFORMATION BEGIN HERE ========================================= @@ -2354,4 +2355,18 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========================================= -END OF sortablejs NOTICES AND INFORMATION \ No newline at end of file +END OF sortablejs NOTICES AND INFORMATION + +%% vscode-uri NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF vscode-uri NOTICES AND INFORMATION \ No newline at end of file diff --git a/package.json b/package.json index f1b514a610497..d82639761acbf 100644 --- a/package.json +++ b/package.json @@ -25036,7 +25036,8 @@ "react-dom": "19.0.0", "signal-utils": "0.21.1", "slug": "11.0.0", - "sortablejs": "1.15.6" + "sortablejs": "1.15.6", + "vscode-uri": "3.1.0" }, "devDependencies": { "@custom-elements-manifest/analyzer": "0.10.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01649a4f233fb..2476092e03def 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -123,6 +123,9 @@ importers: sortablejs: specifier: 1.15.6 version: 1.15.6 + vscode-uri: + specifier: 3.1.0 + version: 3.1.0 devDependencies: '@custom-elements-manifest/analyzer': specifier: 0.10.10 diff --git a/src/env/browser/json.ts b/src/env/browser/json.ts index 0e68de716527b..817e1505e59ae 100644 --- a/src/env/browser/json.ts +++ b/src/env/browser/json.ts @@ -1,5 +1,11 @@ +import { URI } from 'vscode-uri'; +import type { IpcDate, IpcPromise } from '../../webviews/ipc'; +import { getIpcTaggedType, isIpcPromise } from '../../webviews/ipc'; +import { IpcPromiseSettled } from '../../webviews/protocol'; + export function loggingJsonReplacer(key: string, value: unknown): unknown { if (key === '' || value == null || typeof value !== 'object') return value; + if (key.charCodeAt(0) === 95) return undefined; // '_' = 95 if (value instanceof Error) return String(value); @@ -7,11 +13,95 @@ export function loggingJsonReplacer(key: string, value: unknown): unknown { } export function serializeJsonReplacer(this: any, key: string, value: unknown): unknown { - if (value instanceof Date) return value.getTime(); - if (value instanceof Map || value instanceof Set) return [...value.entries()]; - if (value instanceof Function || value instanceof Error) return undefined; - if (value instanceof RegExp) return value.toString(); + if (typeof value === 'object' && value != null) { + // Dates and Uris are automatically converted by JSON.stringify, so we check the original below + // if (value instanceof Date) return value.getTime(); + // if (value instanceof RegExp) return value.toString(); + if (value instanceof Map || value instanceof Set) return [...value.entries()]; + if (value instanceof Function || value instanceof Error) return undefined; + } + + const original = this[key]; + if (original !== value && typeof original === 'object' && original != null) { + if (original instanceof Date) return original.getTime(); + } + return value; +} + +export function serializeIpcJsonReplacer( + this: any, + key: string, + value: unknown, + nextIpcId: () => string, + pendingPromises: IpcPromise[], +): unknown { + // Filter out __promise property from IpcPromise objects to avoid circular references + if (key === '__promise') return undefined; + + if (typeof value === 'object' && value != null) { + if ('__ipc' in value) { + if (isIpcPromise(value)) { + value.value.id = nextIpcId(); + pendingPromises.push(value); + } + return value; + } + + // Dates and Uris are automatically converted by JSON.stringify, so we check the original below + // if (value instanceof Date) { + // return { __ipc: 'date', value: value.getTime() } satisfies IpcDate; + // } + // if (value instanceof Uri) { + // return { __ipc: 'uri', value: value.toJSON() } satisfies IpcUri; + // } + if (value instanceof Promise) { + const ipcPromise: IpcPromise = { + __ipc: 'promise', + __promise: value, + value: { + id: nextIpcId(), + method: IpcPromiseSettled.method, + }, + }; + pendingPromises.push(ipcPromise); + return ipcPromise; + } + + if (value instanceof RegExp) return value.toString(); + if (value instanceof Map || value instanceof Set) return [...value.entries()]; + if (value instanceof Error || value instanceof Function) return undefined; + // if (isContainer(value)) return undefined; + } + + if (!key) return value; const original = this[key]; - return original instanceof Date ? original.getTime() : value; + if (original !== value && typeof original === 'object' && original != null) { + if (original instanceof Date) { + return { __ipc: 'date', value: original.getTime() } satisfies IpcDate; + } + // if (original instanceof Uri) { + // return { __ipc: 'uri', value: original.toJSON() } satisfies IpcUri; + // } + } + return value; +} + +export function deserializeIpcJsonReviver( + this: any, + _key: string, + value: unknown, + promiseFactory: (value: IpcPromise['value']) => Promise, +): unknown { + const tagged = getIpcTaggedType(value); + if (tagged == null) return value; + + switch (tagged.__ipc) { + case 'date': + return new Date(tagged.value); + case 'promise': + return promiseFactory(tagged.value); + case 'uri': + return URI.revive(tagged.value); + } } diff --git a/src/env/node/json.ts b/src/env/node/json.ts index 5b50b7ac0b9ee..216e94005bdb2 100644 --- a/src/env/node/json.ts +++ b/src/env/node/json.ts @@ -7,26 +7,33 @@ import { isRepository } from '../../git/models/repository'; import { isTag } from '../../git/models/tag'; import { isWorktree } from '../../git/models/worktree'; import { isViewNode } from '../../views/nodes/utils/-webview/node.utils'; +import type { IpcDate, IpcPromise, IpcUri } from '../../webviews/ipc'; +import { getIpcTaggedType, isIpcPromise } from '../../webviews/ipc'; +import { IpcPromiseSettled } from '../../webviews/protocol'; export function loggingJsonReplacer(key: string, value: unknown): unknown { if (key === '' || value == null || typeof value !== 'object') return value; - if (key.startsWith('_')) return undefined; + if (key.charCodeAt(0) === 95) return undefined; // '_' = 95 - if (value instanceof Error) return String(value); if (value instanceof Uri) { if ('sha' in value && typeof value.sha === 'string' && value.sha) { return `${value.sha}:${value.toString()}`; } return value.toString(); } + if (value instanceof Error) return String(value); + + // Checks for toString first to avoid function calls if possible if ( - isRepository(value) || - isBranch(value) || - isCommit(value) || - isRemote(value) || - isTag(value) || - isWorktree(value) || - isViewNode(value) + 'toString' in value && + typeof value.toString === 'function' && + (isRepository(value) || + isBranch(value) || + isCommit(value) || + isRemote(value) || + isTag(value) || + isWorktree(value) || + isViewNode(value)) ) { return value.toString(); } @@ -36,13 +43,97 @@ export function loggingJsonReplacer(key: string, value: unknown): unknown { } export function serializeJsonReplacer(this: any, key: string, value: unknown): unknown { - if (value instanceof Date) return value.getTime(); - if (value instanceof Map || value instanceof Set) return [...value.entries()]; - if (value instanceof Function || value instanceof Error) return undefined; - if (value instanceof RegExp) return value.toString(); - if (value instanceof Uri) return value.toString(); - if (isContainer(value)) return undefined; + if (typeof value === 'object' && value != null) { + // Dates and Uris are automatically converted by JSON.stringify, so we check the original below + // if (value instanceof Date) return value.getTime(); + // if (value instanceof Uri) return value.toString(); + if (value instanceof RegExp) return value.toString(); + if (value instanceof Map || value instanceof Set) return [...value.entries()]; + if (value instanceof Error || value instanceof Function) return undefined; + if (isContainer(value)) return undefined; + } const original = this[key]; - return original instanceof Date ? original.getTime() : original instanceof Uri ? original.toString() : value; + if (original !== value && typeof original === 'object' && original != null) { + if (original instanceof Date) return original.getTime(); + if (original instanceof Uri) return original.toString(); + } + return value; +} + +export function serializeIpcJsonReplacer( + this: any, + key: string, + value: unknown, + nextIpcId: () => string, + pendingPromises: IpcPromise[], +): unknown { + // Filter out __promise property from IpcPromise objects to avoid circular references + if (key === '__promise') return undefined; + + if (typeof value === 'object' && value != null) { + if ('__ipc' in value) { + if (isIpcPromise(value)) { + value.value.id = nextIpcId(); + pendingPromises.push(value); + } + return value; + } + + // Dates and Uris are automatically converted by JSON.stringify, so we check the original below + // if (value instanceof Date) { + // return { __ipc: 'date', value: value.getTime() } satisfies IpcDate; + // } + // if (value instanceof Uri) { + // return { __ipc: 'uri', value: value.toJSON() } satisfies IpcUri; + // } + if (value instanceof Promise) { + const ipcPromise: IpcPromise = { + __ipc: 'promise', + __promise: value, + value: { + id: nextIpcId(), + method: IpcPromiseSettled.method, + }, + }; + pendingPromises.push(ipcPromise); + return ipcPromise; + } + + if (value instanceof RegExp) return value.toString(); + if (value instanceof Map || value instanceof Set) return [...value.entries()]; + if (value instanceof Error || value instanceof Function) return undefined; + if (isContainer(value)) return undefined; + } + + if (!key) return value; + + const original = this[key]; + if (original !== value && typeof original === 'object' && original != null) { + if (original instanceof Date) { + return { __ipc: 'date', value: original.getTime() } satisfies IpcDate; + } + if (original instanceof Uri) { + return { __ipc: 'uri', value: original.toJSON() } satisfies IpcUri; + } + } + return value; +} + +export function deserializeIpcJsonReviver( + _key: string, + value: unknown, + promiseFactory: (value: IpcPromise['value']) => Promise, +): unknown { + const tagged = getIpcTaggedType(value); + if (tagged == null) return value; + + switch (tagged.__ipc) { + case 'date': + return new Date(tagged.value); + case 'promise': + return promiseFactory(tagged.value); + case 'uri': + return Uri.from(tagged.value); + } } diff --git a/src/system/ipcSerialize.ts b/src/system/ipcSerialize.ts new file mode 100644 index 0000000000000..03de80d8a83d5 --- /dev/null +++ b/src/system/ipcSerialize.ts @@ -0,0 +1,53 @@ +import type { Uri } from 'vscode'; +import { deserializeIpcJsonReviver, serializeIpcJsonReplacer } from '@env/json'; +import type { Container } from '../container'; +import type { IpcPromise } from '../webviews/ipc'; +import type { Branded } from './brand'; + +// prettier-ignore +export type IpcSerialized = + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + T extends Error | Function | RegExp | Container + ? never + : T extends Date + ? Date + : T extends Uri + ? Uri + : T extends Promise + ? Promise> + : T extends Map + ? [IpcSerialized, IpcSerialized][] + : T extends Set + ? IpcSerialized[] + : T extends Branded + ? U + : T extends any[] + ? IpcSerialized[] + : T extends object + ? { [K in keyof T]: T[K] extends Date ? Date : IpcSerialized } + : T; + +export function serializeIpcData(obj: T, nextIpcId: () => string, pendingPromises: IpcPromise[]): string; +export function serializeIpcData( + obj: T | undefined, + nextIpcId: () => string, + pendingPromises: IpcPromise[], +): string | undefined; +export function serializeIpcData( + obj: T | undefined, + nextIpcId: () => string, + pendingPromises: IpcPromise[], +): string | undefined { + if (obj == null) return undefined; + + return JSON.stringify(obj, function (this: any, key: string, value: unknown) { + return serializeIpcJsonReplacer.call(this, key, value, nextIpcId, pendingPromises); + }); +} + +export function deserializeIpcData( + data: string, + promiseFactory: (value: IpcPromise['value']) => Promise, +): T { + return JSON.parse(data, (k, v) => deserializeIpcJsonReviver(k, v, promiseFactory)) as T; +} diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index 68631efdf7969..37d41ae021797 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -3,7 +3,7 @@ import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import type { ViewFilesLayout } from '../../../config'; import type { GlCommands } from '../../../constants.commands'; -import type { Serialized } from '../../../system/serialize'; +import type { IpcSerialized } from '../../../system/ipcSerialize'; import { pluralize } from '../../../system/string'; import type { DraftState, ExecuteCommitActionsParams, Mode, State } from '../../commitDetails/protocol'; import { @@ -67,16 +67,16 @@ interface ExplainState { } @customElement('gl-commit-details-app') -export class GlCommitDetailsApp extends GlAppHost> { +export class GlCommitDetailsApp extends GlAppHost> { protected override createRenderRoot(): HTMLElement { return this; } - protected override createStateProvider(state: Serialized, ipc: HostIpc): CommitDetailsStateProvider { + protected override createStateProvider(state: IpcSerialized, ipc: HostIpc): CommitDetailsStateProvider { return new CommitDetailsStateProvider(this, state, ipc); } - protected override onPersistState(state: Serialized): void { + protected override onPersistState(state: IpcSerialized): void { this._ipc.setPersistedState({ mode: state.mode, pinned: state.pinned, preferences: state.preferences }); } diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index 387321d381947..b3aecffaf85f5 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -7,8 +7,8 @@ import type { ConnectCloudIntegrationsCommandArgs } from '../../../../commands/c import type { IssueOrPullRequest } from '../../../../git/models/issueOrPullRequest'; import type { PullRequestShape } from '../../../../git/models/pullRequest'; import { createCommandLink } from '../../../../system/commands'; -import type { Serialized } from '../../../../system/serialize'; -import type { State } from '../../../commitDetails/protocol'; +import type { IpcSerialized } from '../../../../system/ipcSerialize'; +import type { State as _State } from '../../../commitDetails/protocol'; import { messageHeadlineSplitterToken } from '../../../commitDetails/protocol'; import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; import { uncommittedSha } from '../commitDetails'; @@ -25,6 +25,7 @@ import '../../shared/components/markdown/markdown'; import '../../shared/components/panes/pane-group'; import '../../shared/components/rich/issue-pull-request'; +type State = IpcSerialized<_State>; interface ExplainState { cancelled?: boolean; error?: { message: string }; @@ -36,7 +37,7 @@ export class GlCommitDetails extends GlDetailsBase { override readonly tab = 'commit'; @property({ type: Object }) - state?: Serialized; + state?: State; @state() get isStash(): boolean { @@ -54,6 +55,36 @@ export class GlCommitDetails extends GlDetailsBase { @property({ type: Object }) explain?: ExplainState; + private _commit: State['commit']; + get commit(): State['commit'] { + return this._commit; + } + // @property({ type: Object }) + set commit(value: State['commit']) { + this._commit = value; + this.enrichedPromise = value?.enriched; + } + + @state() + private _enriched!: Awaited['enriched']>; + get enriched(): Awaited['enriched']> { + return this._enriched; + } + + private _enrichedPromise!: NonNullable['enriched']; + get enrichedPromise(): NonNullable['enriched'] { + return this._enrichedPromise; + } + set enrichedPromise(value: NonNullable['enriched']) { + if (this._enrichedPromise === value) return; + + this._enrichedPromise = value; + void this._enrichedPromise?.then( + r => (this._enriched = r), + () => (this._enriched = undefined), + ); + } + get navigation() { if (this.state?.navigationStack == null) { return { @@ -86,6 +117,10 @@ export class GlCommitDetails extends GlDetailsBase { this.explainBusy = false; this.querySelector('[data-region="commit-explanation"]')?.scrollIntoView(); } + + if (changedProperties.has('state')) { + this.commit = this.state?.commit; + } } private renderEmptyContent() { @@ -145,7 +180,8 @@ export class GlCommitDetails extends GlDetailsBase { const details = this.state?.commit; if (details == null) return undefined; - const message = details.message; + // Use formatted message from promise if available, otherwise use basic message + const message = this._enriched?.formattedMessage ?? details.message; const index = message.indexOf(messageHeadlineSplitterToken); return html`
@@ -185,7 +221,7 @@ export class GlCommitDetails extends GlDetailsBase { !this.isStash, () => html` } - | { type: 'issue'; value: Serialized } - | { type: 'pr'; value: Serialized } + | { type: 'autolink'; value: Autolink } + | { type: 'issue'; value: IssueOrPullRequest } + | { type: 'pr'; value: PullRequestShape } >(); const autolinkIdsByUrl = new Map(); @@ -217,8 +253,10 @@ export class GlCommitDetails extends GlDetailsBase { } } - if (this.state?.autolinkedIssues != null) { - for (const issue of this.state.autolinkedIssues) { + // Use resolved enriched autolinks from promise + const enrichedAutolinks = this._enriched?.autolinkedIssues ?? this.state?.autolinkedIssues; + if (enrichedAutolinks != null) { + for (const issue of enrichedAutolinks) { if (issue.url != null) { const autoLinkId = autolinkIdsByUrl.get(issue.url); if (autoLinkId != null) { @@ -229,19 +267,21 @@ export class GlCommitDetails extends GlDetailsBase { } } - if (this.state?.pullRequest != null) { - if (this.state.pullRequest.url != null) { - const autoLinkId = autolinkIdsByUrl.get(this.state.pullRequest.url); + // Use resolved pull request from promise + const pullRequest = this._enriched?.associatedPullRequest ?? this.state?.pullRequest; + if (pullRequest != null) { + if (pullRequest.url != null) { + const autoLinkId = autolinkIdsByUrl.get(pullRequest.url); if (autoLinkId != null) { deduped.delete(autoLinkId); } } - deduped.set(this.state.pullRequest.id, { type: 'pr', value: this.state.pullRequest }); + deduped.set(pullRequest.id, { type: 'pr', value: pullRequest }); } - const autolinks: Serialized[] = []; - const issues: Serialized[] = []; - const prs: Serialized[] = []; + const autolinks: Autolink[] = []; + const issues: IssueOrPullRequest[] = []; + const prs: PullRequestShape[] = []; for (const item of deduped.values()) { switch (item.type) { diff --git a/src/webviews/apps/commitDetails/context.ts b/src/webviews/apps/commitDetails/context.ts index d96e0238a3946..45b7c04cbf400 100644 --- a/src/webviews/apps/commitDetails/context.ts +++ b/src/webviews/apps/commitDetails/context.ts @@ -1,5 +1,5 @@ import { createContext } from '@lit/context'; -import type { Serialized } from '../../../system/serialize'; +import type { IpcSerialized } from '../../../system/ipcSerialize'; import type { State } from '../../commitDetails/protocol'; -export const stateContext = createContext>('state'); +export const stateContext = createContext>('state'); diff --git a/src/webviews/apps/commitDetails/stateProvider.ts b/src/webviews/apps/commitDetails/stateProvider.ts index a89599b3e1554..2fb474887c842 100644 --- a/src/webviews/apps/commitDetails/stateProvider.ts +++ b/src/webviews/apps/commitDetails/stateProvider.ts @@ -1,6 +1,6 @@ import { ContextProvider } from '@lit/context'; -import type { Serialized } from '../../../system/serialize'; -import type { State, UpdateablePreferences } from '../../commitDetails/protocol'; +import type { IpcSerialized } from '../../../system/ipcSerialize'; +import type { State as _State, UpdateablePreferences } from '../../commitDetails/protocol'; import { ChangeReviewModeCommand, DidChangeDraftStateNotification, @@ -14,15 +14,15 @@ import { import type { ReactiveElementHost, StateProvider } from '../shared/appHost'; import type { Disposable } from '../shared/events'; import type { HostIpc } from '../shared/ipc'; -import { assertsSerialized } from '../shared/ipc'; import { stateContext } from './context'; -export class CommitDetailsStateProvider implements StateProvider> { +type State = IpcSerialized<_State>; +export class CommitDetailsStateProvider implements StateProvider { private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: Serialized }, ReactiveElementHost>; + private readonly provider: ContextProvider<{ __context__: State }, ReactiveElementHost>; - private _state: Serialized; - get state(): Serialized { + private _state: State; + get state(): State { return this._state; } @@ -30,43 +30,20 @@ export class CommitDetailsStateProvider implements StateProvider, + state: State, private readonly _ipc: HostIpc, ) { this._host = host; this._state = state; - this.provider = new ContextProvider(host, { context: stateContext, initialValue: state }); + this.provider = new ContextProvider(host, { + context: stateContext, + initialValue: state, + }); this.disposable = this._ipc.onReceiveMessage(msg => { switch (true) { - // case DidChangeRichStateNotificationType.method: - // onIpc(DidChangeRichStateNotificationType, msg, params => { - // if (this._state.selected == null) return; - - // assertsSerialized(params); - - // const newState = { ...this._state }; - // if (params.formattedMessage != null) { - // newState.selected!.message = params.formattedMessage; - // } - // // if (params.pullRequest != null) { - // newState.pullRequest = params.pullRequest; - // // } - // // if (params.formattedMessage != null) { - // newState.autolinkedIssues = params.autolinkedIssues; - // // } - - // this._state = newState; - // this.provider.setValue(this._state, true); - - // this.renderRichContent(); - // }); - // break; - case DidChangeNotification.is(msg): - assertsSerialized(msg.params.state); - - this._state = { ...msg.params.state, timestamp: Date.now() }; + this._state = { ...(msg.params.state as State), timestamp: Date.now() }; this.provider.setValue(this._state, true); host.requestUpdate(); break; diff --git a/src/webviews/apps/shared/__tests__/ipc.test.ts b/src/webviews/apps/shared/__tests__/ipc.test.ts new file mode 100644 index 0000000000000..4080587f7e232 --- /dev/null +++ b/src/webviews/apps/shared/__tests__/ipc.test.ts @@ -0,0 +1,223 @@ +import * as assert from 'assert'; +import { URI } from 'vscode-uri'; +import { deserializeIpcData } from '../../../../system/ipcSerialize'; +import type { IpcPromise } from '../../../ipc'; + +suite('IPC Deserialization Test Suite', () => { + suite('deserializeIpcData (pure function)', () => { + const mockPromiseFactory = (_value: IpcPromise['value']): Promise => Promise.resolve(); + + test('should be exported and callable', () => { + assert.strictEqual(typeof deserializeIpcData, 'function'); + }); + + suite('IpcDate deserialization', () => { + test('should deserialize IpcDate to Date', () => { + const timestamp = new Date('2024-01-15T10:30:00.000Z').getTime(); + const input = { + date: { __ipc: 'date', value: timestamp }, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(result.date instanceof Date); + assert.strictEqual(result.date.getTime(), timestamp); + }); + + test('should deserialize nested IpcDate objects', () => { + const timestamp1 = new Date('2024-01-15T10:30:00.000Z').getTime(); + const timestamp2 = new Date('2024-01-16T14:45:00.000Z').getTime(); + const input = { + commit: { + author: { + name: 'John Doe', + date: { __ipc: 'date', value: timestamp1 }, + }, + committer: { + name: 'Jane Doe', + date: { __ipc: 'date', value: timestamp2 }, + }, + }, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(result.commit.author.date instanceof Date); + assert.strictEqual(result.commit.author.date.getTime(), timestamp1); + assert.ok(result.commit.committer.date instanceof Date); + assert.strictEqual(result.commit.committer.date.getTime(), timestamp2); + }); + + test('should deserialize array of IpcDate objects', () => { + const timestamps = [ + new Date('2024-01-15T10:30:00.000Z').getTime(), + new Date('2024-01-16T14:45:00.000Z').getTime(), + new Date('2024-01-17T08:15:00.000Z').getTime(), + ]; + const input = { + dates: timestamps.map(t => ({ __ipc: 'date', value: t })), + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.strictEqual(result.dates.length, 3); + result.dates.forEach((date: Date, index: number) => { + assert.ok(date instanceof Date); + assert.strictEqual(date.getTime(), timestamps[index]); + }); + }); + }); + + suite('IpcUri deserialization', () => { + test('should deserialize IpcUri to URI', () => { + const input = { + uri: { + __ipc: 'uri', + value: { + scheme: 'file', + authority: '', + path: '/path/to/file.ts', + query: '', + fragment: '', + }, + }, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(URI.isUri(result.uri)); + assert.strictEqual(result.uri.scheme, 'file'); + assert.strictEqual(result.uri.path, '/path/to/file.ts'); + }); + + test('should deserialize IpcUri with all components', () => { + const input = { + uri: { + __ipc: 'uri', + value: { + scheme: 'https', + authority: 'example.com:8080', + path: '/path/to/file', + query: 'query=value', + fragment: 'fragment', + }, + }, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(URI.isUri(result.uri)); + assert.strictEqual(result.uri.scheme, 'https'); + assert.strictEqual(result.uri.authority, 'example.com:8080'); + assert.strictEqual(result.uri.path, '/path/to/file'); + assert.strictEqual(result.uri.query, 'query=value'); + assert.strictEqual(result.uri.fragment, 'fragment'); + }); + }); + + suite('IpcPromise deserialization', () => { + test('should deserialize IpcPromise to Promise', () => { + const input = { + promise: { + __ipc: 'promise', + value: { + id: 'test-id-1', + method: 'core/ipc/promise/settled', + }, + }, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(result.promise instanceof Promise); + }); + }); + + suite('Mixed types deserialization', () => { + test('should deserialize object with multiple IPC types', () => { + const timestamp = new Date('2024-01-15T10:30:00.000Z').getTime(); + const input = { + date: { __ipc: 'date', value: timestamp }, + uri: { + __ipc: 'uri', + value: { + scheme: 'file', + authority: '', + path: '/path/to/file.ts', + query: '', + fragment: '', + }, + }, + promise: { + __ipc: 'promise', + value: { + id: 'test-id-1', + method: 'core/ipc/promise/settled', + }, + }, + normal: 'string', + number: 42, + boolean: true, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(result.date instanceof Date); + assert.ok(URI.isUri(result.uri)); + assert.ok(result.promise instanceof Promise); + assert.strictEqual(result.normal, 'string'); + assert.strictEqual(result.number, 42); + assert.strictEqual(result.boolean, true); + }); + }); + + suite('Edge cases', () => { + test('should handle empty object', () => { + const input = {}; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.deepStrictEqual(result, {}); + }); + + test('should handle primitive values', () => { + const input = { + string: 'test', + number: 42, + boolean: true, + null: null, + }; + const jsonString = JSON.stringify(input); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.strictEqual(result.string, 'test'); + assert.strictEqual(result.number, 42); + assert.strictEqual(result.boolean, true); + assert.strictEqual(result.null, null); + }); + + test('should handle JSON string input', () => { + const timestamp = new Date('2024-01-15T10:30:00.000Z').getTime(); + const jsonString = JSON.stringify({ + date: { __ipc: 'date', value: timestamp }, + value: 'test', + }); + + const result: any = deserializeIpcData(jsonString, mockPromiseFactory); + + assert.ok(result.date instanceof Date); + assert.strictEqual(result.date.getTime(), timestamp); + assert.strictEqual(result.value, 'test'); + }); + }); + }); +}); diff --git a/src/webviews/apps/shared/appHost.ts b/src/webviews/apps/shared/appHost.ts index 67afba8676ab9..d6ffaf8fd5948 100644 --- a/src/webviews/apps/shared/appHost.ts +++ b/src/webviews/apps/shared/appHost.ts @@ -84,9 +84,8 @@ export abstract class GlAppHost< this._ipc = new HostIpc(this.name); this._ipc.sendCommand(WebviewReadyCommand, undefined); - const state: State = JSON.parse(fromBase64ToString(this.bootstrap)); + const state = this._ipc.deserializeIpcData(fromBase64ToString(this.bootstrap)); this.bootstrap = undefined!; - this._ipc.replaceIpcPromisesWithPromises(state); this._logger.log(`bootstrap duration=${Date.now() - state.timestamp}ms`); diff --git a/src/webviews/apps/shared/components/converters/date-converter.ts b/src/webviews/apps/shared/components/converters/date-converter.ts index c5f742936df65..7badc4ed73baa 100644 --- a/src/webviews/apps/shared/components/converters/date-converter.ts +++ b/src/webviews/apps/shared/components/converters/date-converter.ts @@ -6,6 +6,9 @@ export const dateConverter = (): ComplexAttributeConverter => { return date.getTime(); }, fromAttribute: (value: string, _type?: number) => { + const date = new Date(value); + if (!isNaN(date.getTime())) return date; + return new Date(parseInt(value, 10)); }, }; diff --git a/src/webviews/apps/shared/components/formatted-date.ts b/src/webviews/apps/shared/components/formatted-date.ts index 2e730e420f4e9..9a5b87606e9d5 100644 --- a/src/webviews/apps/shared/components/formatted-date.ts +++ b/src/webviews/apps/shared/components/formatted-date.ts @@ -12,7 +12,7 @@ export class FormattedDate extends LitElement { @property({ attribute: 'date-style' }) dateStyle: 'relative' | 'absolute' = 'relative'; - @property({ converter: dateConverter(), reflect: true }) + @property({ converter: dateConverter(), reflect: true, attribute: false }) date = new Date(); @property() diff --git a/src/webviews/apps/shared/ipc.ts b/src/webviews/apps/shared/ipc.ts index bf88e0157e394..8abec1ba37027 100644 --- a/src/webviews/apps/shared/ipc.ts +++ b/src/webviews/apps/shared/ipc.ts @@ -1,11 +1,12 @@ /*global window */ +import { inflateSync, strFromU8 } from 'fflate'; import { getScopedCounter } from '../../../system/counter'; import { debug, logName } from '../../../system/decorators/log'; +import { deserializeIpcData } from '../../../system/ipcSerialize'; import { Logger } from '../../../system/logger'; import { getLogScope, getNewLogScope, setLogScopeExit } from '../../../system/logger.scope'; import type { Serialized } from '../../../system/serialize'; import { maybeStopWatch } from '../../../system/stopwatch'; -import { isIpcPromise } from '../../ipc'; import type { IpcCallParamsType, IpcCallResponseParamsType, IpcCommand, IpcMessage, IpcRequest } from '../../protocol'; import { IpcPromiseSettled } from '../../protocol'; import { DOM } from './dom'; @@ -42,7 +43,6 @@ export class HostIpc implements Disposable { private readonly _api: HostIpcApi; private readonly _disposable: Disposable; private _pendingHandlers = new Map(); - private _textDecoder: TextDecoder | undefined; constructor(private readonly appName: string) { this._api = getHostIpcApi(); @@ -64,13 +64,29 @@ export class HostIpc implements Disposable { }); if (msg.compressed && msg.params instanceof Uint8Array) { - this._textDecoder ??= new TextDecoder(); - msg.params = JSON.parse(this._textDecoder.decode(msg.params)); - sw?.restart({ message: `\u2022 decoded (${msg.compressed}) serialized params` }); + if (msg.compressed === 'deflate') { + try { + msg.params = strFromU8(inflateSync(msg.params)); + } catch (ex) { + debugger; + console.warn('IPC deflate decompression failed, assuming uncompressed', ex); + msg.params = strFromU8(msg.params as Uint8Array); + } + } else { + msg.params = strFromU8(msg.params); + } + sw?.restart({ message: `\u2022 decompressed (${msg.compressed}) serialized params` }); } - this.replaceIpcPromisesWithPromises(msg.params); - sw?.stop({ message: `\u2022 replaced ipc tagged types with params` }); + if (typeof msg.params === 'string') { + msg.params = deserializeIpcData(msg.params, v => this.getResponsePromise(v.method, v.id)); + sw?.stop({ message: `\u2022 deserialized params` }); + } else if (msg.params == null) { + sw?.stop({ message: `\u2022 no params` }); + } else { + sw?.stop({ message: `\u2022 invalid params` }); + debugger; + } setLogScopeExit(scope, ` \u2022 ipc (host -> webview) duration=${Date.now() - msg.timestamp}ms`); @@ -85,17 +101,8 @@ export class HostIpc implements Disposable { this._onReceiveMessage.fire(msg); } - replaceIpcPromisesWithPromises(data: unknown): void { - if (data == null || typeof data !== 'object') return; - - for (const key in data) { - const value = (data as Record)[key]; - if (isIpcPromise(value)) { - (data as Record)[key] = this.getResponsePromise(value.value.method, value.value.id); - } else { - this.replaceIpcPromisesWithPromises(value); - } - } + deserializeIpcData(data: string): T { + return deserializeIpcData(data, v => this.getResponsePromise(v.method, v.id)); } sendCommand(commandType: T, params?: never): void; diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index d5d13ef81d2b9..ca36a416bd694 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -1,5 +1,5 @@ import { EntityIdentifierUtils } from '@gitkraken/provider-apis/entity-identifiers'; -import type { CancellationToken, ConfigurationChangeEvent, TextDocumentShowOptions } from 'vscode'; +import type { ConfigurationChangeEvent, TextDocumentShowOptions } from 'vscode'; import { CancellationTokenSource, Disposable, env, Uri, window } from 'vscode'; import type { MaybeEnrichedAutolink } from '../../autolinks/models/autolinks'; import { serializeAutolink } from '../../autolinks/utils/-webview/autolinks.utils'; @@ -37,6 +37,7 @@ import type { GitRemote } from '../../git/models/remote'; import type { Repository } from '../../git/models/repository'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../../git/models/repository'; import { uncommitted, uncommittedStaged } from '../../git/models/revision'; +import type { RemoteProvider } from '../../git/remotes/remoteProvider'; import { getReferenceFromRevision } from '../../git/utils/-webview/reference.utils'; import { serializeIssueOrPullRequest } from '../../git/utils/issueOrPullRequest.utils'; import { getComparisonRefsForPullRequest, serializePullRequest } from '../../git/utils/pullRequest.utils'; @@ -67,8 +68,6 @@ import { Logger } from '../../system/logger'; import { getLogScope } from '../../system/logger.scope'; import { MRU } from '../../system/mru'; import { getSettledValue, pauseOnCancelOrTimeoutMapTuplePromise } from '../../system/promise'; -import type { Serialized } from '../../system/serialize'; -import { serialize } from '../../system/serialize'; import type { LinesChangeEvent } from '../../trackers/lineTracker'; import type { ShowInCommitGraphCommandArgs } from '../plus/graph/registration'; import type { Change } from '../plus/patchDetails/protocol'; @@ -80,7 +79,6 @@ import { isSerializedState } from '../webviewsController'; import type { CommitDetails, CreatePatchFromWipParams, - DidChangeWipStateParams, DidExplainParams, DidGenerateParams, ExecuteFileActionParams, @@ -159,7 +157,6 @@ interface Context { commit: GitCommit | undefined; autolinksEnabled: boolean; experimentalComposerEnabled: boolean; - richStateLoaded: boolean; formattedMessage: string | undefined; autolinkedIssues: IssueOrPullRequest[] | undefined; pullRequest: PullRequest | undefined; @@ -171,9 +168,7 @@ interface Context { hasIntegrationsConnected: boolean | undefined; } -export class CommitDetailsWebviewProvider - implements WebviewProvider, CommitDetailsWebviewShowingArgs> -{ +export class CommitDetailsWebviewProvider implements WebviewProvider { private _bootstraping = true; /** The context the webview has */ private _context: Context; @@ -202,7 +197,6 @@ export class CommitDetailsWebviewProvider commit: undefined, autolinksEnabled: configuration.get('views.commitDetails.autolinks.enabled'), experimentalComposerEnabled: configuration.get('ai.experimental.composer.enabled', undefined, false), - richStateLoaded: false, formattedMessage: undefined, autolinkedIssues: undefined, pullRequest: undefined, @@ -268,7 +262,7 @@ export class CommitDetailsWebviewProvider async onShowing( _loading: boolean, options?: WebviewShowOptions, - ...args: WebviewShowingArgs> + ...args: WebviewShowingArgs ): Promise<[boolean, InspectTelemetryContext]> { const [arg] = args; if ((arg as ShowWipArgs)?.type === 'wip') { @@ -316,7 +310,7 @@ export class CommitDetailsWebviewProvider ): Promise { let data: Partial | undefined; - if (isSerializedState>(arg)) { + if (isSerializedState(arg)) { const { commit: selected } = arg.state; if (selected?.repoPath != null && selected?.sha != null) { if (selected.stashNumber != null) { @@ -390,7 +384,7 @@ export class CommitDetailsWebviewProvider }); } - includeBootstrap(): Promise> { + includeBootstrap(): Promise { this._bootstraping = true; this._context = { ...this._context, ...this._pendingContext }; @@ -1211,7 +1205,7 @@ export class CommitDetailsWebviewProvider private _cancellationTokenSource: CancellationTokenSource | undefined = undefined; @debug({ args: false }) - protected async getState(current: Context): Promise> { + protected async getState(current: Context): Promise { if (this._cancellationTokenSource != null) { this._cancellationTokenSource.cancel(); this._cancellationTokenSource = undefined; @@ -1220,16 +1214,6 @@ export class CommitDetailsWebviewProvider let details; if (current.commit != null) { details = await this.getDetailsModel(current.commit, current.formattedMessage); - - if (!current.richStateLoaded) { - this._cancellationTokenSource = new CancellationTokenSource(); - - const cancellation = this._cancellationTokenSource.token; - setTimeout(() => { - if (cancellation.isCancellationRequested) return; - void this.updateRichState(current, cancellation); - }, 100); - } } const wip = current.wip; @@ -1252,24 +1236,23 @@ export class CommitDetailsWebviewProvider current.hasIntegrationsConnected = await this.getHasIntegrationsConnected(); } - const state = serialize({ + const state: State = { ...this.host.baseWebviewState, mode: current.mode, commit: details, navigationStack: current.navigationStack, pinned: current.pinned, preferences: current.preferences, - includeRichContent: current.richStateLoaded, autolinksEnabled: current.autolinksEnabled, experimentalComposerEnabled: current.experimentalComposerEnabled, - autolinkedIssues: current.autolinkedIssues?.map(serializeIssueOrPullRequest), - pullRequest: current.pullRequest != null ? serializePullRequest(current.pullRequest) : undefined, + autolinkedIssues: current.autolinkedIssues, //?.map(serializeIssueOrPullRequest), + pullRequest: current.pullRequest, // != null ? serializePullRequest(current.pullRequest) : undefined, wip: serializeWipContext(wip), orgSettings: current.orgSettings, inReview: current.inReview, hasAccount: current.hasAccount, hasIntegrationsConnected: current.hasIntegrationsConnected, - }); + }; return state; } @@ -1325,13 +1308,10 @@ export class CommitDetailsWebviewProvider } if (this._pendingContext == null) { - const success = await this.host.notify( - DidChangeWipStateNotification, - serialize({ - wip: serializeWipContext(wip), - inReview: inReview, - }) as DidChangeWipStateParams, - ); + const success = await this.host.notify(DidChangeWipStateNotification, { + wip: serializeWipContext(wip), + inReview: inReview, + }); if (success) { this._context.wip = wip; this._context.inReview = inReview; @@ -1418,12 +1398,9 @@ export class CommitDetailsWebviewProvider : []; if (this._pendingContext == null) { - const success = await this.host.notify( - DidChangeWipStateNotification, - serialize({ - wip: serializeWipContext(wip), - }) as DidChangeWipStateParams, - ); + const success = await this.host.notify(DidChangeWipStateNotification, { + wip: serializeWipContext(wip), + }); if (success) { this._context.wip = wip; return; @@ -1434,60 +1411,6 @@ export class CommitDetailsWebviewProvider this.updateState(true); } - @debug({ args: false }) - private async updateRichState(current: Context, cancellation: CancellationToken): Promise { - const { commit } = current; - if (commit == null) return; - - const remote = await this.container.git - .getRepositoryService(commit.repoPath) - .remotes.getBestRemoteWithIntegration(); - - if (cancellation.isCancellationRequested) return; - - const [enrichedAutolinksResult, prResult] = - remote?.provider != null && current.autolinksEnabled - ? await Promise.allSettled([ - configuration.get('views.commitDetails.autolinks.enhanced') - ? pauseOnCancelOrTimeoutMapTuplePromise(commit.getEnrichedAutolinks(remote)) - : undefined, - configuration.get('views.commitDetails.pullRequests.enabled') - ? commit.getAssociatedPullRequest(remote) - : undefined, - ]) - : []; - - if (cancellation.isCancellationRequested) return; - - const enrichedAutolinks = getSettledValue(enrichedAutolinksResult)?.value; - const pr = getSettledValue(prResult); - - const formattedMessage = this.getFormattedMessage(commit, remote, enrichedAutolinks); - - this.updatePendingContext({ - autolinksEnabled: current.autolinksEnabled, - experimentalComposerEnabled: current.experimentalComposerEnabled, - richStateLoaded: true, - formattedMessage: formattedMessage, - autolinkedIssues: - enrichedAutolinks != null - ? [...filterMap(enrichedAutolinks.values(), ([issueOrPullRequest]) => issueOrPullRequest?.value)] - : undefined, - pullRequest: pr, - }); - - this.updateState(); - - // return { - // formattedMessage: formattedMessage, - // pullRequest: pr, - // autolinkedIssues: - // autolinkedIssuesAndPullRequests != null - // ? [...autolinkedIssuesAndPullRequests.values()].filter((i: T | undefined): i is T => i != null) - // : undefined, - // }; - } - private _repositorySubscription: RepositorySubscription | undefined; private async updateCommit( @@ -1540,11 +1463,6 @@ export class CommitDetailsWebviewProvider commit: commit, autolinksEnabled: configuration.get('views.commitDetails.autolinks.enabled'), experimentalComposerEnabled: configuration.get('ai.experimental.composer.enabled', undefined, false), - richStateLoaded: - Boolean(commit?.isUncommitted) || - (commit != null - ? !getContext('gitlens:repos:withHostingIntegrationsConnected')?.includes(commit.repoPath) - : !getContext('gitlens:repos:withHostingIntegrationsConnected')), formattedMessage: undefined, autolinkedIssues: undefined, pullRequest: undefined, @@ -1694,10 +1612,7 @@ export class CommitDetailsWebviewProvider return; } - if (this._notifyDidChangeStateDebounced == null) { - this._notifyDidChangeStateDebounced = debounce(this.notifyDidChangeState.bind(this), 500); - } - + this._notifyDidChangeStateDebounced ??= debounce(this.notifyDidChangeState.bind(this), 500); this._notifyDidChangeStateDebounced(); } @@ -1795,10 +1710,7 @@ export class CommitDetailsWebviewProvider commit = getSettledValue(commitResult, commit); const avatarUri = getSettledValue(avatarUriResult); const remote = getSettledValue(remoteResult); - - if (formattedMessage == null) { - formattedMessage = this.getFormattedMessage(commit, remote); - } + formattedMessage ??= this.getFormattedMessage(commit, remote); const autolinks = commit.message != null ? await this.container.autolinks.getAutolinks(commit.message, remote) : undefined; @@ -1815,6 +1727,49 @@ export class CommitDetailsWebviewProvider files: commit.fileset?.files, stats: commit.stats, autolinks: autolinks != null ? [...map(autolinks.values(), serializeAutolink)] : undefined, + + enriched: this.getEnrichedState(commit, remote), + }; + } + + @debug({ args: false }) + private async getEnrichedState( + commit: GitCommit, + remote: GitRemote | undefined, + ): Promise['enriched']>>> { + const [enrichedAutolinksResult, prResult] = + remote?.provider != null + ? await Promise.allSettled([ + configuration.get('views.commitDetails.autolinks.enabled') && + configuration.get('views.commitDetails.autolinks.enhanced') + ? pauseOnCancelOrTimeoutMapTuplePromise( + commit.getEnrichedAutolinks(remote as GitRemote), + ) + : undefined, + configuration.get('views.commitDetails.pullRequests.enabled') + ? commit.getAssociatedPullRequest(remote as GitRemote) + : undefined, + ]) + : []; + + const enrichedAutolinks = getSettledValue(enrichedAutolinksResult)?.value; + const pr = getSettledValue(prResult); + + const issues = + enrichedAutolinks != null + ? [ + ...filterMap(enrichedAutolinks.values(), ([issueOrPullRequest]) => + issueOrPullRequest?.value != null + ? serializeIssueOrPullRequest(issueOrPullRequest.value) + : undefined, + ), + ] + : []; + + return { + formattedMessage: this.getFormattedMessage(commit, remote, enrichedAutolinks), + associatedPullRequest: pr != null ? serializePullRequest(pr) : undefined, + autolinkedIssues: issues, }; } @@ -2034,14 +1989,9 @@ function serializeWipContext(wip?: WipContext): Wip | undefined { // type: wip.repo.provider.name, }, pullRequest: wip.pullRequest != null ? serializePullRequest(wip.pullRequest) : undefined, - codeSuggestions: wip.codeSuggestions?.map(draft => serializeDraft(draft)), + codeSuggestions: wip.codeSuggestions?.map(draft => ({ + ...draft, + changesets: undefined, // Inspect doesn't need changesets for the draft list + })), }; } - -function serializeDraft(draft: Draft): Serialized { - // Inspect doesn't need changesets for the draft list - return serialize({ - ...draft, - changesets: undefined, - }); -} diff --git a/src/webviews/commitDetails/protocol.ts b/src/webviews/commitDetails/protocol.ts index 6df244858d7d2..1cbfd9e14015f 100644 --- a/src/webviews/commitDetails/protocol.ts +++ b/src/webviews/commitDetails/protocol.ts @@ -9,7 +9,6 @@ import type { PullRequestShape } from '../../git/models/pullRequest'; import type { Repository } from '../../git/models/repository'; import type { Draft, DraftVisibility } from '../../plus/drafts/models/drafts'; import type { DateTimeFormat } from '../../system/date'; -import type { Serialized } from '../../system/serialize'; import type { Change, DraftUserSelection } from '../plus/patchDetails/protocol'; import type { IpcScope, WebviewState } from '../protocol'; import { IpcCommand, IpcNotification, IpcRequest } from '../protocol'; @@ -36,6 +35,12 @@ export interface CommitDetails extends CommitSummary { autolinks?: Autolink[]; files?: readonly GitFileChangeShape[]; stats?: GitCommitStats; + + enriched?: Promise<{ + formattedMessage: string; + associatedPullRequest: PullRequestShape | undefined; + autolinkedIssues: IssueOrPullRequest[]; + }>; } export interface Preferences { @@ -73,7 +78,7 @@ export interface Wip { repositoryCount: number; branch?: GitBranchShape; pullRequest?: PullRequestShape; - codeSuggestions?: Serialized[]; + codeSuggestions?: Omit[]; repo: { uri: string; name: string; @@ -99,7 +104,6 @@ export interface State extends WebviewState { ai: boolean; drafts: boolean; }; - includeRichContent?: boolean; commit?: CommitDetails; autolinksEnabled: boolean; @@ -223,14 +227,14 @@ export const GenerateRequest = new IpcRequest(scope, 'g // NOTIFICATIONS export interface DidChangeParams { - state: Serialized; + state: State; } export const DidChangeNotification = new IpcNotification(scope, 'didChange', true); -export type DidChangeWipStateParams = Pick, 'wip' | 'inReview'>; +export type DidChangeWipStateParams = Pick; export const DidChangeWipStateNotification = new IpcNotification(scope, 'didChange/wip'); -export type DidChangeOrgSettings = Pick, 'orgSettings'>; +export type DidChangeOrgSettings = Pick; export const DidChangeOrgSettingsNotification = new IpcNotification( scope, 'org/settings/didChange', diff --git a/src/webviews/commitDetails/registration.ts b/src/webviews/commitDetails/registration.ts index 98e0bdc6e8705..77c34ec643db0 100644 --- a/src/webviews/commitDetails/registration.ts +++ b/src/webviews/commitDetails/registration.ts @@ -1,5 +1,4 @@ import type { CommitSelectedEvent } from '../../eventBus'; -import type { Serialized } from '../../system/serialize'; import type { WebviewsController, WebviewViewProxy } from '../webviewsController'; import type { ShowWipArgs, State } from './protocol'; @@ -7,13 +6,8 @@ export type CommitDetailsWebviewShowingArgs = [Partial> { - return controller.registerWebviewView< - 'gitlens.views.commitDetails', - State, - Serialized, - CommitDetailsWebviewShowingArgs - >( +): WebviewViewProxy<'gitlens.views.commitDetails', CommitDetailsWebviewShowingArgs, State> { + return controller.registerWebviewView<'gitlens.views.commitDetails', State, State, CommitDetailsWebviewShowingArgs>( { id: 'gitlens.views.commitDetails', fileName: 'commitDetails.html', @@ -37,13 +31,8 @@ export function registerCommitDetailsWebviewView( export function registerGraphDetailsWebviewView( controller: WebviewsController, -): WebviewViewProxy<'gitlens.views.graphDetails', CommitDetailsWebviewShowingArgs, Serialized> { - return controller.registerWebviewView< - 'gitlens.views.graphDetails', - State, - Serialized, - CommitDetailsWebviewShowingArgs - >( +): WebviewViewProxy<'gitlens.views.graphDetails', CommitDetailsWebviewShowingArgs, State> { + return controller.registerWebviewView<'gitlens.views.graphDetails', State, State, CommitDetailsWebviewShowingArgs>( { id: 'gitlens.views.graphDetails', fileName: 'commitDetails.html', diff --git a/src/webviews/ipc.ts b/src/webviews/ipc.ts index 52c69e61dac79..a215113c33741 100644 --- a/src/webviews/ipc.ts +++ b/src/webviews/ipc.ts @@ -1,3 +1,13 @@ +import type { UriComponents } from '../system/uri'; + +// Unified IPC Tagged Types System - allows transparent serialization/deserialization of special types across the IPC boundary + +/** Tagged type for Dates that get serialized as timestamps */ +export interface IpcDate { + __ipc: 'date'; + value: number; +} + /** Tagged type for Promises that get resolved asynchronously over IPC */ export interface IpcPromise { __ipc: 'promise'; @@ -8,12 +18,54 @@ export interface IpcPromise { __promise: Promise; } +/** Tagged type for Uris that get serialized as UriComponents */ +export interface IpcUri { + __ipc: 'uri'; + value: UriComponents; +} + +export type IpcTaggedType = IpcPromise | IpcDate | IpcUri; + +/** + * @returns the IPC tagged type if the value is one, otherwise undefined + * More efficient than calling multiple isIpc* functions when you need to handle different types + */ +export function getIpcTaggedType(value: unknown): IpcTaggedType | undefined { + if (typeof value !== 'object' || value == null) return undefined; + + const ipc = (value as any).__ipc; + if (ipc == null) return undefined; + + switch (ipc) { + case 'date': + return typeof (value as IpcDate).value === 'number' ? (value as IpcDate) : undefined; + case 'promise': + return typeof (value as IpcPromise).value === 'object' && + typeof (value as IpcPromise).value.id === 'string' && + typeof (value as IpcPromise).value.method === 'string' + ? (value as IpcPromise) + : undefined; + case 'uri': + return typeof (value as IpcUri).value === 'object' && typeof (value as IpcUri).value?.scheme === 'string' + ? (value as IpcUri) + : undefined; + default: + return undefined; + } +} + +export function isIpcTaggedType(value: unknown): value is IpcTaggedType { + return getIpcTaggedType(value) != null; +} + +export function isIpcDate(value: unknown): value is IpcDate { + return getIpcTaggedType(value)?.__ipc === 'date'; +} + export function isIpcPromise(value: unknown): value is IpcPromise { - return ( - typeof value === 'object' && - value != null && - (value as IpcPromise).__ipc === 'promise' && - typeof (value as IpcPromise).value.id === 'string' && - typeof (value as IpcPromise).value.method === 'string' - ); + return getIpcTaggedType(value)?.__ipc === 'promise'; +} + +export function isIpcUri(value: unknown): value is IpcUri { + return getIpcTaggedType(value)?.__ipc === 'uri'; } diff --git a/src/webviews/plus/graph/protocol.ts b/src/webviews/plus/graph/protocol.ts index 1ced0b0d3ecff..f198814570120 100644 --- a/src/webviews/plus/graph/protocol.ts +++ b/src/webviews/plus/graph/protocol.ts @@ -383,7 +383,7 @@ export const DidChangeRepoConnectionNotification = new IpcNotification(scope, 'didChange', true, 'utf8'); +export const DidChangeNotification = new IpcNotification(scope, 'didChange', true); export interface DidChangeGraphConfigurationParams { config: GraphComponentConfig; @@ -467,12 +467,7 @@ export interface DidChangeRowsParams { searchResults?: GraphSearchResults; selectedRows?: GraphSelectedRows; } -export const DidChangeRowsNotification = new IpcNotification( - scope, - 'rows/didChange', - undefined, - 'utf8', -); +export const DidChangeRowsNotification = new IpcNotification(scope, 'rows/didChange'); export interface DidChangeRowsStatsParams { rowsStats: Record; diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts index 1afe4b5f0950f..bff9a651b5e30 100644 --- a/src/webviews/protocol.ts +++ b/src/webviews/protocol.ts @@ -15,7 +15,7 @@ import type { ConfigPath, ConfigPathValue, Path, PathValue } from '../system/-we export type IpcScope = 'core' | CustomEditorTypes | WebviewTypes | WebviewViewTypes; -type IpcCompression = 'utf8' | false; +type IpcCompression = 'deflate' | 'utf8' | false; export interface IpcMessage { id: string; scope: IpcScope; @@ -34,7 +34,6 @@ abstract class IpcCall { public readonly scope: IpcScope, method: string, public readonly reset: boolean = false, - public readonly compressed: IpcCompression = false, ) { this.method = `${scope}/${method}`; } @@ -61,15 +60,10 @@ export class IpcCommand extends IpcCall {} export class IpcRequest extends IpcCall { public readonly response: IpcNotification; - constructor(scope: IpcScope, method: string, reset?: boolean, compressed?: IpcCompression) { - super(scope, method, reset, compressed); + constructor(scope: IpcScope, method: string, reset?: boolean) { + super(scope, method, reset); - this.response = new IpcNotification( - this.scope, - `${method}/completion`, - this.reset, - this.compressed, - ); + this.response = new IpcNotification(this.scope, `${method}/completion`, this.reset); } } diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 3b4a6ba991d61..f33d9a7e9a717 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -1,3 +1,4 @@ +import { deflateSync, strFromU8, strToU8 } from 'fflate'; import type { Event, ViewBadge, Webview, WebviewPanel, WebviewView, WindowState } from 'vscode'; import { CancellationTokenSource, Disposable, EventEmitter, Uri, ViewColumn, window, workspace } from 'vscode'; import { base64 } from '@env/base64'; @@ -14,13 +15,13 @@ import { getViewFocusCommand } from '../system/-webview/vscode/views'; import { getScopedCounter } from '../system/counter'; import { debug, logName } from '../system/decorators/log'; import { sequentialize } from '../system/decorators/serialize'; +import { serializeIpcData } from '../system/ipcSerialize'; import { getLoggableName, Logger } from '../system/logger'; import { getLogScope, getNewLogScope, setLogScopeExit } from '../system/logger.scope'; import { pauseOnCancelOrTimeout } from '../system/promise'; import { maybeStopWatch, Stopwatch } from '../system/stopwatch'; import type { WebviewContext } from '../system/webview'; import type { IpcPromise } from './ipc'; -import { isIpcPromise } from './ipc'; import type { IpcCallMessageType, IpcCallParamsType, @@ -47,8 +48,6 @@ import type { WebviewHost, WebviewProvider, WebviewShowingArgs } from './webview import type { WebviewPanelDescriptor, WebviewShowOptions, WebviewViewDescriptor } from './webviewsController'; const ipcSequencer = getScopedCounter(); -const utf8TextDecoder = new TextDecoder('utf8'); -const utf8TextEncoder = new TextEncoder(); type GetWebviewDescriptor = T extends WebviewIds ? WebviewPanelDescriptor @@ -625,11 +624,11 @@ export class WebviewController< ]); const sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); - this.replacePromisesWithIpcPromises(bootstrap); - sw?.stop({ message: `\u2022 replaced tagged ipc types in bootstrap` }); + const serialized = this.serializeIpcData(bootstrap); + sw?.stop({ message: `\u2022 serialized bootstrap; length=${serialized.length}` }); const html = replaceWebviewHtmlTokens( - utf8TextDecoder.decode(bytes), + strFromU8(bytes), this.id, this.instanceId, webview.cspSource, @@ -637,7 +636,7 @@ export class WebviewController< this.asWebviewUri(this.getRootUri()).toString(), this.getWebRoot(), this.is('editor') ? 'editor' : 'view', - bootstrap, + serialized, head, body, endOfBody, @@ -660,22 +659,41 @@ export class WebviewController< const scope = getNewLogScope(`${getLoggableName(this)}.notify(${id}|${notificationType.method})`, true); const sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); - this.replacePromisesWithIpcPromises(params); + const serializedParams = this.serializeIpcData(params); - sw?.restart({ message: `\u2022 replaced tagged ipc types in params` }); + sw?.restart({ message: `\u2022 serialized params; length=${serializedParams.length}` }); let bytes: Uint8Array | undefined; let compression: IpcMessage['compressed'] = false; - if (notificationType.compressed && params != null) { - bytes = utf8TextEncoder.encode(JSON.stringify(params)); + if (serializedParams != null && serializedParams.length > 1024) { + bytes = strToU8(serializedParams); compression = 'utf8'; + + const originalSize = bytes.byteLength; + + try { + bytes = deflateSync(bytes, { level: 1 }); + compression = 'deflate'; + + sw?.stop({ + message: `\u2022 compressed (${compression}) serialized params (${Math.round((1 - bytes.byteLength / originalSize) * 100)}% reduction) ${originalSize} → ${bytes.byteLength} bytes`, + }); + } catch (ex) { + debugger; + // Compression failed, keep uncompressed data + Logger.error(ex, scope, 'IPC deflate compression failed'); + sw?.stop({ + message: `\u2022 failed deflate compression, using uncompressed data`, + suffix: `failed`, + }); + } } const msg: IpcMessage | Uint8Array> = { id: id, scope: notificationType.scope, method: notificationType.method, - params: bytes ?? params, + params: bytes ?? serializedParams, compressed: compression, timestamp: timestamp, completionId: completionId, @@ -700,59 +718,43 @@ export class WebviewController< return this.notify(requestType.response, params, msg.completionId); } - private replacePromisesWithIpcPromises(data: unknown) { + private serializeIpcData(data: unknown): string { const pendingPromises: IpcPromise[] = []; - this.replacePromisesWithIpcPromisesCore(data, pendingPromises); - if (!pendingPromises.length) return; - - const cancellation = this.cancellation?.token; - queueMicrotask(() => { - for (const ipcPromise of pendingPromises) { - ipcPromise.__promise.then( - r => { - if (cancellation?.isCancellationRequested) { - debugger; - return; - } - return this.notify(IpcPromiseSettled, { status: 'fulfilled', value: r }, ipcPromise.value.id); - }, - (ex: unknown) => { - if (cancellation?.isCancellationRequested) { - debugger; - return; - } - return this.notify(IpcPromiseSettled, { status: 'rejected', reason: ex }, ipcPromise.value.id); - }, - ); - } - }); - } - - private replacePromisesWithIpcPromisesCore(data: unknown, pendingPromises: IpcPromise[]) { - if (data == null || typeof data !== 'object') return; - - for (const key in data) { - if (key === '__promise') continue; - - const value = (data as Record)[key]; - if (value instanceof Promise) { - const ipcPromise: IpcPromise = { - __ipc: 'promise', - __promise: value, - value: { - id: this.nextIpcId(), - method: IpcPromiseSettled.method, - }, - }; - (data as Record)[key] = ipcPromise; - pendingPromises.push(ipcPromise); - } else if (isIpcPromise(value)) { - value.value.id = this.nextIpcId(); - pendingPromises.push(value); - } else { - this.replacePromisesWithIpcPromisesCore(value, pendingPromises); - } + const serialized = serializeIpcData(data, () => this.nextIpcId(), pendingPromises); + + if (pendingPromises.length) { + const cancellation = this.cancellation?.token; + queueMicrotask(() => { + for (const ipcPromise of pendingPromises) { + ipcPromise.__promise.then( + r => { + if (cancellation?.isCancellationRequested) { + debugger; + return; + } + return this.notify( + IpcPromiseSettled, + { status: 'fulfilled', value: r }, + ipcPromise.value.id, + ); + }, + (ex: unknown) => { + if (cancellation?.isCancellationRequested) { + debugger; + return; + } + return this.notify( + IpcPromiseSettled, + { status: 'rejected', reason: ex }, + ipcPromise.value.id, + ); + }, + ); + } + }); } + + return serialized; } @sequentialize() @@ -885,13 +887,15 @@ export function replaceWebviewHtmlTokens( case 'body': return body ?? ''; case 'state': - return bootstrap != null ? base64(JSON.stringify(bootstrap)) : ''; + return bootstrap != null + ? base64(typeof bootstrap === 'string' ? bootstrap : JSON.stringify(bootstrap)) + : ''; case 'endOfBody': return `${ bootstrap != null - ? `` + ? `` : '' }${endOfBody ?? ''}`; case 'webviewId': From cdf7cd3fc2f9246c10081b0b038b68328981d413 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 19 Oct 2025 18:46:49 -0400 Subject: [PATCH 52/83] Refactors state providers for deferrable bootstrap - Unifies common state provider behavior and bootstrap handling Reworks state handling of commit/graph details view - Simplifies state handling - Removes pending context pattern in favor of direct state updates --- src/eventBus.ts | 27 +- .../apps/commitDetails/commitDetails.ts | 13 +- .../components/gl-commit-details.ts | 1 - .../apps/commitDetails/stateProvider.ts | 98 ++-- src/webviews/apps/home/home.ts | 5 +- src/webviews/apps/home/stateProvider.ts | 173 +++---- src/webviews/apps/plus/composer/composer.ts | 11 +- .../apps/plus/composer/stateProvider.ts | 461 ++++++++--------- src/webviews/apps/plus/graph/graph.ts | 4 +- src/webviews/apps/plus/graph/stateProvider.ts | 472 +++++++++--------- .../apps/plus/timeline/stateProvider.ts | 45 +- src/webviews/apps/plus/timeline/timeline.ts | 13 +- src/webviews/apps/shared/appBase.ts | 4 +- src/webviews/apps/shared/appHost.ts | 14 +- src/webviews/apps/shared/stateProviderBase.ts | 85 ++++ .../commitDetails/commitDetailsWebview.ts | 238 ++++----- src/webviews/home/homeWebview.ts | 2 +- src/webviews/plus/composer/composerWebview.ts | 2 +- src/webviews/plus/graph/graphWebview.ts | 27 +- .../plus/patchDetails/patchDetailsWebview.ts | 2 +- src/webviews/plus/timeline/timelineWebview.ts | 2 +- src/webviews/protocol.ts | 10 +- src/webviews/settings/settingsWebview.ts | 2 +- src/webviews/webviewController.ts | 9 +- src/webviews/webviewProvider.ts | 2 +- 25 files changed, 861 insertions(+), 861 deletions(-) create mode 100644 src/webviews/apps/shared/stateProviderBase.ts diff --git a/src/eventBus.ts b/src/eventBus.ts index fb47ef3069094..d2abe7663bb83 100644 --- a/src/eventBus.ts +++ b/src/eventBus.ts @@ -83,6 +83,11 @@ const _cacheableEventNames = new Set([ 'file:selected', ]); const _cachedEventArgs = new Map(); +// Cache events by source to avoid stale data from different contexts (e.g., graph vs commitDetails) +const _cachedEventArgsBySource = new Map< + string, + Map +>(); export class EventBus implements Disposable { private readonly _emitter = new EventEmitter(); @@ -94,12 +99,17 @@ export class EventBus implements Disposable { fire(name: T, data: EventsMapping[T], options?: EventBusOptions): void { if (canCacheEventArgs(name)) { _cachedEventArgs.set(name, data as CacheableEventsMapping[typeof name]); + // Also cache by source to avoid stale data from different contexts + if (options?.source != null) { + let sourceCache = _cachedEventArgsBySource.get(options.source); + if (sourceCache == null) { + sourceCache = new Map(); + _cachedEventArgsBySource.set(options.source, sourceCache); + } + sourceCache.set(name, data as CacheableEventsMapping[typeof name]); + } } - this._emitter.fire({ - name: name, - data: data, - source: options?.source, - }); + this._emitter.fire({ name: name, data: data, source: options?.source }); } fireAsync(name: T, data: EventsMapping[T], options?: EventBusOptions): void { @@ -110,6 +120,13 @@ export class EventBus implements Disposable { return _cachedEventArgs.get(name) as CacheableEventsMapping[T] | undefined; } + getCachedEventArgsBySource( + name: T, + source: EventBusSource, + ): CacheableEventsMapping[T] | undefined { + return _cachedEventArgsBySource.get(source)?.get(name) as CacheableEventsMapping[T] | undefined; + } + on(name: T, handler: (e: EventBusEvent) => void, thisArgs?: unknown): Disposable { return this._emitter.event( // eslint-disable-next-line prefer-arrow-callback diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index 37d41ae021797..5b68717fe5cb1 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -40,6 +40,7 @@ import type { CreatePatchMetadataEventDetail } from '../plus/patchDetails/compon import { GlAppHost } from '../shared/appHost'; import type { IssuePullRequest } from '../shared/components/rich/issue-pull-request'; import type { WebviewPane, WebviewPaneExpandedChangeEventDetail } from '../shared/components/webview-pane'; +import type { LoggerContext } from '../shared/contexts/logger'; import { DOM } from '../shared/dom'; import type { HostIpc } from '../shared/ipc'; import type { GlCommitDetails } from './components/gl-commit-details'; @@ -72,12 +73,12 @@ export class GlCommitDetailsApp extends GlAppHost> { return this; } - protected override createStateProvider(state: IpcSerialized, ipc: HostIpc): CommitDetailsStateProvider { - return new CommitDetailsStateProvider(this, state, ipc); - } - - protected override onPersistState(state: IpcSerialized): void { - this._ipc.setPersistedState({ mode: state.mode, pinned: state.pinned, preferences: state.preferences }); + protected override createStateProvider( + bootstrap: string, + ipc: HostIpc, + logger: LoggerContext, + ): CommitDetailsStateProvider { + return new CommitDetailsStateProvider(this, bootstrap, ipc, logger); } @state() diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index b3aecffaf85f5..612ecbcc1575c 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -59,7 +59,6 @@ export class GlCommitDetails extends GlDetailsBase { get commit(): State['commit'] { return this._commit; } - // @property({ type: Object }) set commit(value: State['commit']) { this._commit = value; this.enrichedPromise = value?.enriched; diff --git a/src/webviews/apps/commitDetails/stateProvider.ts b/src/webviews/apps/commitDetails/stateProvider.ts index 2fb474887c842..075a73b343f08 100644 --- a/src/webviews/apps/commitDetails/stateProvider.ts +++ b/src/webviews/apps/commitDetails/stateProvider.ts @@ -11,70 +11,52 @@ import { SwitchModeCommand, UpdatePreferencesCommand, } from '../../commitDetails/protocol'; -import type { ReactiveElementHost, StateProvider } from '../shared/appHost'; -import type { Disposable } from '../shared/events'; -import type { HostIpc } from '../shared/ipc'; +import type { IpcMessage } from '../../protocol'; +import type { ReactiveElementHost } from '../shared/appHost'; +import { StateProviderBase } from '../shared/stateProviderBase'; import { stateContext } from './context'; type State = IpcSerialized<_State>; -export class CommitDetailsStateProvider implements StateProvider { - private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: State }, ReactiveElementHost>; - private _state: State; - get state(): State { - return this._state; +export class CommitDetailsStateProvider extends StateProviderBase { + protected override get deferBootstrap(): boolean { + return true; } - private _host: ReactiveElementHost; - - constructor( - host: ReactiveElementHost, - state: State, - private readonly _ipc: HostIpc, - ) { - this._host = host; - this._state = state; - this.provider = new ContextProvider(host, { - context: stateContext, - initialValue: state, - }); + protected override createContextProvider(state: State): ContextProvider { + return new ContextProvider(this.host, { context: stateContext, initialValue: state }); + } - this.disposable = this._ipc.onReceiveMessage(msg => { - switch (true) { - case DidChangeNotification.is(msg): - this._state = { ...(msg.params.state as State), timestamp: Date.now() }; - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; + protected override onMessageReceived(msg: IpcMessage): void { + switch (true) { + case DidChangeNotification.is(msg): + this._state = { ...(msg.params.state as State), timestamp: Date.now() }; + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; - case DidChangeWipStateNotification.is(msg): - this._state = { ...this._state, wip: msg.params.wip, inReview: msg.params.inReview }; - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; + case DidChangeWipStateNotification.is(msg): + this._state = { ...this._state, wip: msg.params.wip, inReview: msg.params.inReview }; + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; - case DidChangeDraftStateNotification.is(msg): - this.onDraftStateChanged(host, msg.params.inReview, true); - break; + case DidChangeDraftStateNotification.is(msg): + this.onDraftStateChanged(this.host, msg.params.inReview, true); + break; - case DidChangeHasAccountNotification.is(msg): - this._state = { ...this._state, hasAccount: msg.params.hasAccount }; - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; + case DidChangeHasAccountNotification.is(msg): + this._state = { ...this._state, hasAccount: msg.params.hasAccount }; + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; - case DidChangeIntegrationsNotification.is(msg): - this._state = { ...this._state, hasIntegrationsConnected: msg.params.hasIntegrationsConnected }; - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; - } - }); - } - - dispose(): void { - this.disposable.dispose(); + case DidChangeIntegrationsNotification.is(msg): + this._state = { ...this._state, hasIntegrationsConnected: msg.params.hasIntegrationsConnected }; + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; + } } private onDraftStateChanged(host: ReactiveElementHost, inReview: boolean, silent = false) { @@ -83,23 +65,23 @@ export class CommitDetailsStateProvider implements StateProvider { this.provider.setValue(this._state, true); host.requestUpdate(); if (!silent) { - this._ipc.sendCommand(ChangeReviewModeCommand, { inReview: inReview }); + this.ipc.sendCommand(ChangeReviewModeCommand, { inReview: inReview }); } } switchMode(mode: State['mode']) { this._state = { ...this._state, mode: mode }; this.provider.setValue(this._state, true); - this._host.requestUpdate(); + this.host.requestUpdate(); - this._ipc.sendCommand(SwitchModeCommand, { mode: mode, repoPath: this._state.commit?.repoPath }); + this.ipc.sendCommand(SwitchModeCommand, { mode: mode, repoPath: this._state.commit?.repoPath }); } updatePreferences(preferenceChange: UpdateablePreferences) { this._state = { ...this._state, preferences: { ...this._state.preferences, ...preferenceChange } }; this.provider.setValue(this._state, true); - this._host.requestUpdate(); + this.host.requestUpdate(); - this._ipc.sendCommand(UpdatePreferencesCommand, preferenceChange); + this.ipc.sendCommand(UpdatePreferencesCommand, preferenceChange); } } diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index bef74b1937f62..24060a3f93fc8 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -15,6 +15,7 @@ import { import type { GlHomeHeader } from '../plus/shared/components/home-header'; import { GlAppHost } from '../shared/appHost'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; +import type { LoggerContext } from '../shared/contexts/logger'; import type { HostIpc } from '../shared/ipc'; import type { GlAiAllAccessBanner } from './components/ai-all-access-banner'; import { homeBaseStyles, homeStyles } from './home.css'; @@ -50,11 +51,11 @@ export class GlHomeApp extends GlAppHost { private badgeSource = { source: 'home', detail: 'badge' }; - protected override createStateProvider(state: State, ipc: HostIpc): HomeStateProvider { + protected override createStateProvider(bootstrap: string, ipc: HostIpc, logger: LoggerContext): HomeStateProvider { this.disposables.push((this._activeOverviewState = new ActiveOverviewState(ipc))); this.disposables.push((this._inactiveOverviewState = new InactiveOverviewState(ipc))); - return new HomeStateProvider(this, state, ipc); + return new HomeStateProvider(this, bootstrap, ipc, logger); } override connectedCallback(): void { diff --git a/src/webviews/apps/home/stateProvider.ts b/src/webviews/apps/home/stateProvider.ts index 75a96ddef68d1..a5d5118fe6c1b 100644 --- a/src/webviews/apps/home/stateProvider.ts +++ b/src/webviews/apps/home/stateProvider.ts @@ -11,104 +11,87 @@ import { DidChangeWalkthroughProgress, DidCompleteDiscoveringRepositories, } from '../../home/protocol'; -import type { ReactiveElementHost, StateProvider } from '../shared/appHost'; -import type { Disposable } from '../shared/events'; -import type { HostIpc } from '../shared/ipc'; +import type { IpcMessage } from '../../protocol'; +import type { ReactiveElementHost } from '../shared/appHost'; +import { StateProviderBase } from '../shared/stateProviderBase'; import { stateContext } from './context'; -export class HomeStateProvider implements StateProvider { - private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: State }, ReactiveElementHost>; - - private readonly _state: State; - get state(): State { - return this._state; - } - - constructor( - host: ReactiveElementHost, - state: State, - private readonly _ipc: HostIpc, - ) { - this._state = state; - this.provider = new ContextProvider(host, { context: stateContext, initialValue: state }); - - this.disposable = this._ipc.onReceiveMessage(msg => { - switch (true) { - case DidChangeRepositories.is(msg): - this._state.repositories = msg.params; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - case DidCompleteDiscoveringRepositories.is(msg): - this._state.repositories = msg.params.repositories; - this._state.discovering = msg.params.discovering; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - case DidChangeWalkthroughProgress.is(msg): - this._state.walkthroughProgress = msg.params; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - case DidChangeSubscription.is(msg): - this._state.subscription = msg.params.subscription; - this._state.avatar = msg.params.avatar; - this._state.organizationsCount = msg.params.organizationsCount; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - case DidChangeOrgSettings.is(msg): - this._state.orgSettings = msg.params.orgSettings; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - - case DidChangeIntegrationsConnections.is(msg): - this._state.hasAnyIntegrationConnected = msg.params.hasAnyIntegrationConnected; - this._state.integrations = msg.params.integrations; - this._state.ai = msg.params.ai; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - break; - - case DidChangePreviewEnabled.is(msg): - this._state.previewEnabled = msg.params.previewEnabled; - this._state.previewCollapsed = msg.params.previewCollapsed; - this._state.aiEnabled = msg.params.aiEnabled; - this._state.experimentalComposerEnabled = msg.params.experimentalComposerEnabled; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; - - case DidChangeAiAllAccessBanner.is(msg): - this._state.aiAllAccessBannerCollapsed = msg.params; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; - case DidChangeMcpBanner.is(msg): - this._state.mcpBannerCollapsed = msg.params.mcpBannerCollapsed; - this._state.mcpCanAutoRegister = msg.params.mcpCanAutoRegister; - this._state.timestamp = Date.now(); - - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; - } - }); +export class HomeStateProvider extends StateProviderBase { + protected override createContextProvider(state: State): ContextProvider { + return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } - dispose(): void { - this.disposable.dispose(); + protected override onMessageReceived(msg: IpcMessage): void { + switch (true) { + case DidChangeRepositories.is(msg): + this._state.repositories = msg.params; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + case DidCompleteDiscoveringRepositories.is(msg): + this._state.repositories = msg.params.repositories; + this._state.discovering = msg.params.discovering; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + case DidChangeWalkthroughProgress.is(msg): + this._state.walkthroughProgress = msg.params; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + case DidChangeSubscription.is(msg): + this._state.subscription = msg.params.subscription; + this._state.avatar = msg.params.avatar; + this._state.organizationsCount = msg.params.organizationsCount; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + case DidChangeOrgSettings.is(msg): + this._state.orgSettings = msg.params.orgSettings; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + + case DidChangeIntegrationsConnections.is(msg): + this._state.hasAnyIntegrationConnected = msg.params.hasAnyIntegrationConnected; + this._state.integrations = msg.params.integrations; + this._state.ai = msg.params.ai; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + break; + + case DidChangePreviewEnabled.is(msg): + this._state.previewEnabled = msg.params.previewEnabled; + this._state.previewCollapsed = msg.params.previewCollapsed; + this._state.aiEnabled = msg.params.aiEnabled; + this._state.experimentalComposerEnabled = msg.params.experimentalComposerEnabled; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; + + case DidChangeAiAllAccessBanner.is(msg): + this._state.aiAllAccessBannerCollapsed = msg.params; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; + case DidChangeMcpBanner.is(msg): + this._state.mcpBannerCollapsed = msg.params.mcpBannerCollapsed; + this._state.mcpCanAutoRegister = msg.params.mcpCanAutoRegister; + this._state.timestamp = Date.now(); + + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; + } } } diff --git a/src/webviews/apps/plus/composer/composer.ts b/src/webviews/apps/plus/composer/composer.ts index d5ab11acb5999..df2e3be7c8ab5 100644 --- a/src/webviews/apps/plus/composer/composer.ts +++ b/src/webviews/apps/plus/composer/composer.ts @@ -2,15 +2,20 @@ import { html } from 'lit'; import { customElement } from 'lit/decorators.js'; import type { State } from '../../../plus/composer/protocol'; import { GlAppHost } from '../../shared/appHost'; +import type { LoggerContext } from '../../shared/contexts/logger'; import type { HostIpc } from '../../shared/ipc'; +import { ComposerStateProvider } from './stateProvider'; import './components/app'; import './composer.scss'; -import { ComposerStateProvider } from './stateProvider'; @customElement('gl-composer-apphost') export class ComposerAppHost extends GlAppHost { - protected override createStateProvider(state: State, ipc: HostIpc): ComposerStateProvider { - return new ComposerStateProvider(this, state, ipc); + protected override createStateProvider( + bootstrap: string, + ipc: HostIpc, + logger: LoggerContext, + ): ComposerStateProvider { + return new ComposerStateProvider(this, bootstrap, ipc, logger); } override render() { diff --git a/src/webviews/apps/plus/composer/stateProvider.ts b/src/webviews/apps/plus/composer/stateProvider.ts index 6f37a2b8d6f8a..ca12fd10815cc 100644 --- a/src/webviews/apps/plus/composer/stateProvider.ts +++ b/src/webviews/apps/plus/composer/stateProvider.ts @@ -19,267 +19,250 @@ import { DidStartGeneratingNotification, DidWorkingDirectoryChangeNotification, } from '../../../plus/composer/protocol'; -import type { ReactiveElementHost, StateProvider } from '../../shared/appHost'; -import type { Disposable } from '../../shared/events'; -import type { HostIpc } from '../../shared/ipc'; +import type { IpcMessage } from '../../../protocol'; +import type { ReactiveElementHost } from '../../shared/appHost'; +import { StateProviderBase } from '../../shared/stateProviderBase'; import { stateContext } from './context'; -export class ComposerStateProvider implements StateProvider { - private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: State }, ReactiveElementHost>; - - private readonly _state: State; - get state(): State { - return this._state; +export class ComposerStateProvider extends StateProviderBase { + protected override createContextProvider(state: State): ContextProvider { + return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } - constructor( - host: ReactiveElementHost, - state: State, - private readonly _ipc: HostIpc, - ) { - this._state = state; - this.provider = new ContextProvider(host, { context: stateContext, initialValue: this._state }); - - this.disposable = this._ipc.onReceiveMessage(msg => { - switch (true) { - case DidStartGeneratingNotification.is(msg): { - const updatedState = { - ...this._state, - generatingCommits: true, - timestamp: Date.now(), - }; - - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidStartGeneratingCommitMessageNotification.is(msg): { - const updatedState = { - ...this._state, - generatingCommitMessage: msg.params.commitId, - timestamp: Date.now(), - }; + protected override onMessageReceived(msg: IpcMessage): void { + switch (true) { + case DidStartGeneratingNotification.is(msg): { + const updatedState = { + ...this._state, + generatingCommits: true, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidGenerateCommitsNotification.is(msg): { - const updatedState = { - ...this._state, - generatingCommits: false, - commits: msg.params.commits, - hunks: this._state.hunks.map(hunk => ({ - ...hunk, - assigned: true, - })), - hasUsedAutoCompose: true, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidStartGeneratingCommitMessageNotification.is(msg): { + const updatedState = { + ...this._state, + generatingCommitMessage: msg.params.commitId, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidGenerateCommitMessageNotification.is(msg): { - const updatedCommits = this._state.commits.map(commit => - commit.id === msg.params.commitId ? { ...commit, message: msg.params.message } : commit, - ); + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidGenerateCommitsNotification.is(msg): { + const updatedState = { + ...this._state, + generatingCommits: false, + commits: msg.params.commits, + hunks: this._state.hunks.map(hunk => ({ + ...hunk, + assigned: true, + })), + hasUsedAutoCompose: true, + timestamp: Date.now(), + }; - const updatedState = { - ...this._state, - generatingCommitMessage: null, - commits: updatedCommits, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidGenerateCommitMessageNotification.is(msg): { + const updatedCommits = this._state.commits.map(commit => + commit.id === msg.params.commitId ? { ...commit, message: msg.params.message } : commit, + ); - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidStartCommittingNotification.is(msg): { - const updatedState = { - ...this._state, - committing: true, - timestamp: Date.now(), - }; + const updatedState = { + ...this._state, + generatingCommitMessage: null, + commits: updatedCommits, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidFinishCommittingNotification.is(msg): { - const updatedState = { - ...this._state, - committing: false, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidStartCommittingNotification.is(msg): { + const updatedState = { + ...this._state, + committing: true, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidSafetyErrorNotification.is(msg): { - const updatedState = { - ...this._state, - safetyError: msg.params.error, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidFinishCommittingNotification.is(msg): { + const updatedState = { + ...this._state, + committing: false, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidReloadComposerNotification.is(msg): { - const updatedState = { - ...this._state, - hunks: msg.params.hunks, - commits: msg.params.commits, - baseCommit: msg.params.baseCommit, - loadingError: msg.params.loadingError, - hasChanges: msg.params.hasChanges, - safetyError: null, // Clear any existing safety errors - // Reset UI state to defaults - selectedCommitId: null, - selectedCommitIds: new Set(), - selectedUnassignedSection: null, - selectedHunkIds: new Set(), - // Clear any ongoing operations - generatingCommits: false, - generatingCommitMessage: null, - committing: false, - // Reset working directory change flag on reload - workingDirectoryHasChanged: false, - indexHasChanged: false, - timestamp: Date.now(), - hasUsedAutoCompose: false, - repositoryState: msg.params.repositoryState, - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidSafetyErrorNotification.is(msg): { + const updatedState = { + ...this._state, + safetyError: msg.params.error, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidWorkingDirectoryChangeNotification.is(msg): { - const updatedState = { - ...this._state, - workingDirectoryHasChanged: true, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidReloadComposerNotification.is(msg): { + const updatedState = { + ...this._state, + hunks: msg.params.hunks, + commits: msg.params.commits, + baseCommit: msg.params.baseCommit, + loadingError: msg.params.loadingError, + hasChanges: msg.params.hasChanges, + safetyError: null, // Clear any existing safety errors + // Reset UI state to defaults + selectedCommitId: null, + selectedCommitIds: new Set(), + selectedUnassignedSection: null, + selectedHunkIds: new Set(), + // Clear any ongoing operations + generatingCommits: false, + generatingCommitMessage: null, + committing: false, + // Reset working directory change flag on reload + workingDirectoryHasChanged: false, + indexHasChanged: false, + timestamp: Date.now(), + hasUsedAutoCompose: false, + repositoryState: msg.params.repositoryState, + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidIndexChangeNotification.is(msg): { - const updatedState = { - ...this._state, - indexHasChanged: true, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidWorkingDirectoryChangeNotification.is(msg): { + const updatedState = { + ...this._state, + workingDirectoryHasChanged: true, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidLoadingErrorNotification.is(msg): { - const updatedState = { - ...this._state, - loadingError: msg.params.error, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidIndexChangeNotification.is(msg): { + const updatedState = { + ...this._state, + indexHasChanged: true, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidErrorAIOperationNotification.is(msg): { - const updatedState = { - ...this._state, - aiOperationError: { - operation: msg.params.operation, - error: msg.params.error, - }, - // Clear any loading states since the operation failed - generatingCommits: false, - generatingCommitMessage: null, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidLoadingErrorNotification.is(msg): { + const updatedState = { + ...this._state, + loadingError: msg.params.error, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidClearAIOperationErrorNotification.is(msg): { - const updatedState = { - ...this._state, - aiOperationError: null, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidErrorAIOperationNotification.is(msg): { + const updatedState = { + ...this._state, + aiOperationError: { + operation: msg.params.operation, + error: msg.params.error, + }, + // Clear any loading states since the operation failed + generatingCommits: false, + generatingCommitMessage: null, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidCancelGenerateCommitsNotification.is(msg): { - // Clear loading state and reset to pre-generation state - const updatedState = { - ...this._state, - generatingCommits: false, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidClearAIOperationErrorNotification.is(msg): { + const updatedState = { + ...this._state, + aiOperationError: null, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidCancelGenerateCommitMessageNotification.is(msg): { - // Clear loading state for commit message generation - const updatedState = { - ...this._state, - generatingCommitMessage: null, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidCancelGenerateCommitsNotification.is(msg): { + // Clear loading state and reset to pre-generation state + const updatedState = { + ...this._state, + generatingCommits: false, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidChangeAiEnabledNotification.is(msg): { - const updatedState = { - ...this._state, - aiEnabled: { - ...this._state.aiEnabled, - ...(msg.params.org !== undefined && { org: msg.params.org }), - ...(msg.params.config !== undefined && { config: msg.params.config }), - }, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidCancelGenerateCommitMessageNotification.is(msg): { + // Clear loading state for commit message generation + const updatedState = { + ...this._state, + generatingCommitMessage: null, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } - case DidChangeAiModelNotification.is(msg): { - const updatedState = { - ...this._state, - ai: { - ...this._state.ai, - model: msg.params.model, - }, - timestamp: Date.now(), - }; + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + case DidChangeAiEnabledNotification.is(msg): { + const updatedState = { + ...this._state, + aiEnabled: { + ...this._state.aiEnabled, + ...(msg.params.org !== undefined && { org: msg.params.org }), + ...(msg.params.config !== undefined && { config: msg.params.config }), + }, + timestamp: Date.now(), + }; - (this as any)._state = updatedState; - this.provider.setValue(this._state, true); - break; - } + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; } - }); - } + case DidChangeAiModelNotification.is(msg): { + const updatedState = { + ...this._state, + ai: { + ...this._state.ai, + model: msg.params.model, + }, + timestamp: Date.now(), + }; - dispose(): void { - this.disposable.dispose(); + (this as any)._state = updatedState; + this.provider.setValue(this._state, true); + break; + } + } } } diff --git a/src/webviews/apps/plus/graph/graph.ts b/src/webviews/apps/plus/graph/graph.ts index a65dca0ad2bb5..8a92a82e10602 100644 --- a/src/webviews/apps/plus/graph/graph.ts +++ b/src/webviews/apps/plus/graph/graph.ts @@ -33,8 +33,8 @@ export class GraphAppHost extends GlAppHost { return html``; } - protected override createStateProvider(state: State, ipc: HostIpc): GraphStateProvider { - return new GraphStateProvider(this, state, ipc, this._logger, { + protected override createStateProvider(bootstrap: string, ipc: HostIpc): GraphStateProvider { + return new GraphStateProvider(this, bootstrap, ipc, this._logger, { onStateUpdate: partial => { if ('rows' in partial) { this.appElement.resetHover(); diff --git a/src/webviews/apps/plus/graph/stateProvider.ts b/src/webviews/apps/plus/graph/stateProvider.ts index 29d87d8bdd288..b57c88621a1e2 100644 --- a/src/webviews/apps/plus/graph/stateProvider.ts +++ b/src/webviews/apps/plus/graph/stateProvider.ts @@ -1,5 +1,4 @@ import { ContextProvider, createContext } from '@lit/context'; -import type { ReactiveControllerHost } from 'lit'; import type { SearchQuery } from '../../../../constants.search'; import { debounce } from '../../../../system/function/debounce'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; @@ -30,14 +29,19 @@ import { DidSearchNotification, DidStartFeaturePreviewNotification, } from '../../../plus/graph/protocol'; +import type { IpcMessage, WebviewState } from '../../../protocol'; import { DidChangeHostWindowFocusNotification } from '../../../protocol'; -import type { StateProvider } from '../../shared/appHost'; +import type { ReactiveElementHost } from '../../shared/appHost'; import { signalObjectState, signalState } from '../../shared/components/signal-utils'; import type { LoggerContext } from '../../shared/contexts/logger'; -import type { Disposable } from '../../shared/events'; import type { HostIpc } from '../../shared/ipc'; +import { StateProviderBase } from '../../shared/stateProviderBase'; -type ReactiveElementHost = Partial & HTMLElement; +const BaseWebviewStateKeys = [ + 'timestamp', + 'webviewId', + 'webviewInstanceId', +] as const satisfies readonly (keyof WebviewState)[] as readonly string[]; interface AppState { activeDay?: number; @@ -63,27 +67,7 @@ function getSearchResultModel(searchResults: State['searchResults']): { export const graphStateContext = createContext('graph-state-context'); -export class GraphStateProvider implements StateProvider, State, AppState { - private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: GraphStateProvider }, ReactiveElementHost>; - - private readonly _state: State; - get state() { - return this._state; - } - - get webviewId() { - return this._state.webviewId; - } - - get webviewInstanceId() { - return this._state.webviewInstanceId; - } - - get timestamp() { - return this._state.timestamp; - } - +export class GraphStateProvider extends StateProviderBase { // App state members moved from GraphAppState @signalState() accessor activeDay: number | undefined; @@ -226,254 +210,250 @@ export class GraphStateProvider implements StateProvider, State, AppState return this.loading || this.searching || this.rowsStatsLoading || false; } - private updateState(partial: Partial, silent?: boolean) { - for (const key in partial) { - const value = partial[key as keyof State]; - // @ts-expect-error key is a key of State - this._state[key] = value; - - if (['timestamp', 'webviewId', 'webviewInstanceId'].includes(key)) continue; - - // Update corresponding accessors - switch (key) { - case 'allowed': - this.allowed = partial.allowed ?? false; - break; - case 'loading': - this.loading = partial.loading ?? false; - break; - default: - // @ts-expect-error key is a key of State - this[key as keyof Omit] = value; - break; - } - } - - if (silent) return; - - this.options.onStateUpdate?.(partial); - this.fireProviderUpdate(); - } - - private fireProviderUpdate = debounce(() => this.provider.setValue(this, true), 100); - constructor( host: ReactiveElementHost, - state: State, - private readonly _ipc: HostIpc, - private readonly _logger: LoggerContext, + bootstrap: string, + ipc: HostIpc, + logger: LoggerContext, private readonly options: { onStateUpdate?: (partial: Partial) => void } = {}, ) { - this._state = state; - this.provider = new ContextProvider(host, { context: graphStateContext, initialValue: this }); - this.updateState(state, true); - - this.disposable = this._ipc.onReceiveMessage(msg => { - const scope = getLogScope(); - - const updates: Partial = {}; - switch (true) { - case DidChangeNotification.is(msg): - this.updateState(msg.params.state); - break; - - case DidFetchNotification.is(msg): - this._state.lastFetched = msg.params.lastFetched; - this.updateState({ lastFetched: msg.params.lastFetched }); - break; - - case DidChangeAvatarsNotification.is(msg): - this.updateState({ avatars: msg.params.avatars }); - break; - case DidStartFeaturePreviewNotification.is(msg): - this._state.featurePreview = msg.params.featurePreview; - this._state.allowed = msg.params.allowed; - this.updateState({ - featurePreview: msg.params.featurePreview, - allowed: msg.params.allowed, - }); - break; - case DidChangeBranchStateNotification.is(msg): - this.updateState({ - branchState: msg.params.branchState, - }); - break; - - case DidChangeHostWindowFocusNotification.is(msg): - this.updateState({ - windowFocused: msg.params.focused, - }); - break; + super(host, bootstrap, ipc, logger); + } - case DidChangeColumnsNotification.is(msg): - this.updateState({ - columns: msg.params.columns, - context: { - ...this._state.context, - header: msg.params.context, - settings: msg.params.settingsContext, - }, - }); - break; + protected override createContextProvider( + _state: State, + ): ContextProvider { + return new ContextProvider(this.host, { context: graphStateContext, initialValue: this }); + } - case DidChangeRefsVisibilityNotification.is(msg): - this.updateState({ - branchesVisibility: msg.params.branchesVisibility, - excludeRefs: msg.params.excludeRefs, - excludeTypes: msg.params.excludeTypes, - includeOnlyRefs: msg.params.includeOnlyRefs, - }); - break; + protected override async initializeState(): Promise { + await super.initializeState(); - case DidChangeRefsMetadataNotification.is(msg): - this.updateState({ - refsMetadata: msg.params.metadata, - }); - break; + this.updateState(this._state, true); + } - case DidChangeRowsNotification.is(msg): { - let rows; - if ( - msg.params.rows.length && - msg.params.paging?.startingCursor != null && - this._state.rows != null - ) { - const previousRows = this._state.rows; - const lastId = previousRows[previousRows.length - 1]?.sha; - - let previousRowsLength = previousRows.length; - const newRowsLength = msg.params.rows.length; - - this._logger.log( - scope, - `paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${msg.params.paging.startingCursor} (last existing row: ${lastId})`, - ); - - rows = []; - // Preallocate the array to avoid reallocations - rows.length = previousRowsLength + newRowsLength; - - if (msg.params.paging.startingCursor !== lastId) { - this._logger.log( - scope, - `searching for ${msg.params.paging.startingCursor} in existing rows`, - ); - - let i = 0; - let row; - for (row of previousRows) { - rows[i++] = row; - if (row.sha === msg.params.paging.startingCursor) { - this._logger.log( - scope, - `found ${msg.params.paging.startingCursor} in existing rows`, - ); - - previousRowsLength = i; - - if (previousRowsLength !== previousRows.length) { - // If we stopped before the end of the array, we need to trim it - rows.length = previousRowsLength + newRowsLength; - } - - break; + protected onMessageReceived(msg: IpcMessage): void { + const scope = getLogScope(); + + const updates: Partial = {}; + switch (true) { + case DidChangeNotification.is(msg): + this.updateState(msg.params.state); + break; + + case DidFetchNotification.is(msg): + this._state.lastFetched = msg.params.lastFetched; + this.updateState({ lastFetched: msg.params.lastFetched }); + break; + + case DidChangeAvatarsNotification.is(msg): + this.updateState({ avatars: msg.params.avatars }); + break; + case DidStartFeaturePreviewNotification.is(msg): + this._state.featurePreview = msg.params.featurePreview; + this._state.allowed = msg.params.allowed; + this.updateState({ + featurePreview: msg.params.featurePreview, + allowed: msg.params.allowed, + }); + break; + case DidChangeBranchStateNotification.is(msg): + this.updateState({ + branchState: msg.params.branchState, + }); + break; + + case DidChangeHostWindowFocusNotification.is(msg): + this.updateState({ + windowFocused: msg.params.focused, + }); + break; + + case DidChangeColumnsNotification.is(msg): + this.updateState({ + columns: msg.params.columns, + context: { + ...this._state.context, + header: msg.params.context, + settings: msg.params.settingsContext, + }, + }); + break; + + case DidChangeRefsVisibilityNotification.is(msg): + this.updateState({ + branchesVisibility: msg.params.branchesVisibility, + excludeRefs: msg.params.excludeRefs, + excludeTypes: msg.params.excludeTypes, + includeOnlyRefs: msg.params.includeOnlyRefs, + }); + break; + + case DidChangeRefsMetadataNotification.is(msg): + this.updateState({ + refsMetadata: msg.params.metadata, + }); + break; + + case DidChangeRowsNotification.is(msg): { + let rows; + if (msg.params.rows.length && msg.params.paging?.startingCursor != null && this._state.rows != null) { + const previousRows = this._state.rows; + const lastId = previousRows[previousRows.length - 1]?.sha; + + let previousRowsLength = previousRows.length; + const newRowsLength = msg.params.rows.length; + + this.logger.log( + scope, + `paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${msg.params.paging.startingCursor} (last existing row: ${lastId})`, + ); + + rows = []; + // Preallocate the array to avoid reallocations + rows.length = previousRowsLength + newRowsLength; + + if (msg.params.paging.startingCursor !== lastId) { + this.logger.log(scope, `searching for ${msg.params.paging.startingCursor} in existing rows`); + + let i = 0; + let row; + for (row of previousRows) { + rows[i++] = row; + if (row.sha === msg.params.paging.startingCursor) { + this.logger.log(scope, `found ${msg.params.paging.startingCursor} in existing rows`); + + previousRowsLength = i; + + if (previousRowsLength !== previousRows.length) { + // If we stopped before the end of the array, we need to trim it + rows.length = previousRowsLength + newRowsLength; } - } - } else { - for (let i = 0; i < previousRowsLength; i++) { - rows[i] = previousRows[i]; - } - } - for (let i = 0; i < newRowsLength; i++) { - rows[previousRowsLength + i] = msg.params.rows[i]; + break; + } } } else { - this._logger.log(scope, `setting to ${msg.params.rows.length} rows`); - - if (msg.params.rows.length === 0) { - rows = this._state.rows; - } else { - rows = msg.params.rows; + for (let i = 0; i < previousRowsLength; i++) { + rows[i] = previousRows[i]; } } - updates.avatars = msg.params.avatars; - updates.downstreams = msg.params.downstreams; - if (msg.params.refsMetadata !== undefined) { - updates.refsMetadata = msg.params.refsMetadata; + for (let i = 0; i < newRowsLength; i++) { + rows[previousRowsLength + i] = msg.params.rows[i]; } - updates.rows = rows; - updates.paging = msg.params.paging; - if (msg.params.rowsStats != null) { - updates.rowsStats = { ...this._state.rowsStats, ...msg.params.rowsStats }; - } - updates.rowsStatsLoading = msg.params.rowsStatsLoading; - if (msg.params.searchResults != null) { - updates.searchResults = msg.params.searchResults; - } - if (msg.params.selectedRows != null) { - updates.selectedRows = msg.params.selectedRows; - } - updates.loading = false; - this.updateState(updates); - setLogScopeExit(scope, ` \u2022 rows=${this._state.rows?.length ?? 0}`); - break; - } - case DidChangeRowsStatsNotification.is(msg): - this.updateState({ - rowsStats: { ...this._state.rowsStats, ...msg.params.rowsStats }, - rowsStatsLoading: msg.params.rowsStatsLoading, - }); - break; + } else { + this.logger.log(scope, `setting to ${msg.params.rows.length} rows`); - case DidChangeScrollMarkersNotification.is(msg): - this.updateState({ context: { ...this._state.context, settings: msg.params.context } }); - break; - - case DidSearchNotification.is(msg): - if (msg.params.selectedRows != null) { - updates.selectedRows = msg.params.selectedRows; + if (msg.params.rows.length === 0) { + rows = this._state.rows; + } else { + rows = msg.params.rows; } - updates.searchResults = msg.params.results; - this.updateState(updates); - break; + } - case DidChangeSelectionNotification.is(msg): - this.updateState({ selectedRows: msg.params.selection }); - break; + updates.avatars = msg.params.avatars; + updates.downstreams = msg.params.downstreams; + if (msg.params.refsMetadata !== undefined) { + updates.refsMetadata = msg.params.refsMetadata; + } + updates.rows = rows; + updates.paging = msg.params.paging; + if (msg.params.rowsStats != null) { + updates.rowsStats = { ...this._state.rowsStats, ...msg.params.rowsStats }; + } + updates.rowsStatsLoading = msg.params.rowsStatsLoading; + if (msg.params.searchResults != null) { + updates.searchResults = msg.params.searchResults; + } + if (msg.params.selectedRows != null) { + updates.selectedRows = msg.params.selectedRows; + } + updates.loading = false; + this.updateState(updates); + setLogScopeExit(scope, ` \u2022 rows=${this._state.rows?.length ?? 0}`); + break; + } + case DidChangeRowsStatsNotification.is(msg): + this.updateState({ + rowsStats: { ...this._state.rowsStats, ...msg.params.rowsStats }, + rowsStatsLoading: msg.params.rowsStatsLoading, + }); + break; + + case DidChangeScrollMarkersNotification.is(msg): + this.updateState({ context: { ...this._state.context, settings: msg.params.context } }); + break; + + case DidSearchNotification.is(msg): + if (msg.params.selectedRows != null) { + updates.selectedRows = msg.params.selectedRows; + } + updates.searchResults = msg.params.results; + this.updateState(updates); + break; + + case DidChangeSelectionNotification.is(msg): + this.updateState({ selectedRows: msg.params.selection }); + break; + + case DidChangeGraphConfigurationNotification.is(msg): + this.updateState({ config: msg.params.config }); + break; + + case DidChangeSubscriptionNotification.is(msg): + this.updateState({ + subscription: msg.params.subscription, + allowed: msg.params.allowed, + }); + break; + + case DidChangeOrgSettings.is(msg): + this.updateState({ orgSettings: msg.params.orgSettings }); + break; + + case DidChangeMcpBanner.is(msg): + this.updateState({ mcpBannerCollapsed: msg.params }); + break; + + case DidChangeWorkingTreeNotification.is(msg): + this.updateState({ workingTreeStats: msg.params.stats }); + break; + + case DidChangeRepoConnectionNotification.is(msg): + this.updateState({ repositories: msg.params.repositories }); + break; + } + } - case DidChangeGraphConfigurationNotification.is(msg): - this.updateState({ config: msg.params.config }); - break; + private fireProviderUpdate = debounce(() => this.provider.setValue(this, true), 100); - case DidChangeSubscriptionNotification.is(msg): - this.updateState({ - subscription: msg.params.subscription, - allowed: msg.params.allowed, - }); - break; + protected updateState(partial: Partial, silent?: boolean) { + for (const key in partial) { + const value = partial[key as keyof State]; + // @ts-expect-error key is a key of State + this._state[key] = value; - case DidChangeOrgSettings.is(msg): - this.updateState({ orgSettings: msg.params.orgSettings }); - break; + if (BaseWebviewStateKeys.includes(key)) continue; - case DidChangeMcpBanner.is(msg): - this.updateState({ mcpBannerCollapsed: msg.params }); + // Update corresponding accessors + switch (key) { + case 'allowed': + this.allowed = partial.allowed ?? false; break; - - case DidChangeWorkingTreeNotification.is(msg): - this.updateState({ workingTreeStats: msg.params.stats }); + case 'loading': + this.loading = partial.loading ?? false; break; - - case DidChangeRepoConnectionNotification.is(msg): - this.updateState({ repositories: msg.params.repositories }); + default: + // @ts-expect-error key is a key of State + this[key as keyof Omit] = value; break; } - }); - } + } + + if (silent) return; - dispose(): void { - this.disposable.dispose(); + this.options.onStateUpdate?.(partial); + this.fireProviderUpdate(); } } diff --git a/src/webviews/apps/plus/timeline/stateProvider.ts b/src/webviews/apps/plus/timeline/stateProvider.ts index d58e5addcc977..e2daddf987efa 100644 --- a/src/webviews/apps/plus/timeline/stateProvider.ts +++ b/src/webviews/apps/plus/timeline/stateProvider.ts @@ -1,41 +1,28 @@ import { ContextProvider } from '@lit/context'; import type { State } from '../../../plus/timeline/protocol'; import { DidChangeNotification } from '../../../plus/timeline/protocol'; -import type { ReactiveElementHost, StateProvider } from '../../shared/appHost'; -import type { Disposable } from '../../shared/events'; -import type { HostIpc } from '../../shared/ipc'; +import type { IpcMessage } from '../../../protocol'; +import type { ReactiveElementHost } from '../../shared/appHost'; +import { StateProviderBase } from '../../shared/stateProviderBase'; import { stateContext } from './context'; -export class TimelineStateProvider implements StateProvider { - private readonly disposable: Disposable; - private readonly provider: ContextProvider<{ __context__: State }, ReactiveElementHost>; - - private _state: State; - get state(): State { - return this._state; +export class TimelineStateProvider extends StateProviderBase { + protected override createContextProvider(state: State): ContextProvider { + return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } - constructor( - host: ReactiveElementHost, - state: State, - private readonly _ipc: HostIpc, - ) { - this._state = state; - this.provider = new ContextProvider(host, { context: stateContext, initialValue: state }); - - this.disposable = this._ipc.onReceiveMessage(msg => { - switch (true) { - case DidChangeNotification.is(msg): - this._state = { ...msg.params.state, timestamp: Date.now() }; + protected override onMessageReceived(msg: IpcMessage): void { + switch (true) { + case DidChangeNotification.is(msg): + this._state = { ...msg.params.state, timestamp: Date.now() }; - this.provider.setValue(this._state, true); - host.requestUpdate(); - break; - } - }); + this.provider.setValue(this._state, true); + this.host.requestUpdate(); + break; + } } - dispose(): void { - this.disposable.dispose(); + protected override onPersistState(state: State): void { + this.ipc.setPersistedState({ config: state.config, scope: state.scope }); } } diff --git a/src/webviews/apps/plus/timeline/timeline.ts b/src/webviews/apps/plus/timeline/timeline.ts index 8cb1b47ade7c6..4ea1145892ae7 100644 --- a/src/webviews/apps/plus/timeline/timeline.ts +++ b/src/webviews/apps/plus/timeline/timeline.ts @@ -19,6 +19,7 @@ import { import { GlAppHost } from '../../shared/appHost'; import type { Checkbox } from '../../shared/components/checkbox/checkbox'; import type { GlRefButton } from '../../shared/components/ref-button'; +import type { LoggerContext } from '../../shared/contexts/logger'; import type { HostIpc } from '../../shared/ipc'; import { linkStyles, ruleStyles } from '../shared/components/vscode.css'; import type { CommitEventDetail, GlTimelineChart } from './components/chart'; @@ -51,12 +52,12 @@ export class GlTimelineApp extends GlAppHost { @query('#chart') private _chart?: GlTimelineChart; - protected override createStateProvider(state: State, ipc: HostIpc): TimelineStateProvider { - return new TimelineStateProvider(this, state, ipc); - } - - protected override onPersistState(state: State): void { - this._ipc.setPersistedState({ config: state.config, scope: state.scope }); + protected override createStateProvider( + bootstrap: string, + ipc: HostIpc, + logger: LoggerContext, + ): TimelineStateProvider { + return new TimelineStateProvider(this, bootstrap, ipc, logger); } override connectedCallback(): void { diff --git a/src/webviews/apps/shared/appBase.ts b/src/webviews/apps/shared/appBase.ts index 9b948275ec997..92c8e191558d7 100644 --- a/src/webviews/apps/shared/appBase.ts +++ b/src/webviews/apps/shared/appBase.ts @@ -15,7 +15,7 @@ import { DidChangeWebviewFocusNotification, DidChangeWebviewVisibilityNotification, WebviewFocusChangedCommand, - WebviewReadyCommand, + WebviewReadyRequest, } from '../../protocol'; import { ipcContext } from './contexts/ipc'; import { loggerContext, LoggerContext } from './contexts/logger'; @@ -126,7 +126,7 @@ export abstract class App< ); } - this.sendCommand(WebviewReadyCommand, undefined); + void this.sendRequest(WebviewReadyRequest, { bootstrap: false }); this.onInitialized?.(); } finally { diff --git a/src/webviews/apps/shared/appHost.ts b/src/webviews/apps/shared/appHost.ts index d6ffaf8fd5948..4ad886e2d48b4 100644 --- a/src/webviews/apps/shared/appHost.ts +++ b/src/webviews/apps/shared/appHost.ts @@ -2,7 +2,6 @@ import { provide } from '@lit/context'; import type { ReactiveControllerHost } from 'lit'; import { html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; -import { fromBase64ToString } from '@env/base64'; import type { CustomEditorIds, WebviewIds, WebviewViewIds } from '../../../constants.views'; import type { Deferrable } from '../../../system/function/debounce'; import { debounce } from '../../../system/function/debounce'; @@ -11,7 +10,6 @@ import { DidChangeWebviewFocusNotification, DidChangeWebviewVisibilityNotification, WebviewFocusChangedCommand, - WebviewReadyCommand, } from '../../protocol'; import { GlElement } from './components/element'; import { ipcContext } from './contexts/ipc'; @@ -70,8 +68,7 @@ export abstract class GlAppHost< private _sendWebviewFocusChangedCommandDebounced!: Deferrable<(params: WebviewFocusChangedParams) => void>; protected _stateProvider!: Provider; - protected abstract createStateProvider(state: State, ipc: HostIpc): Provider; - protected onPersistState?(state: State): void; + protected abstract createStateProvider(bootstrap: string, ipc: HostIpc, logger: LoggerContext): Provider; protected onWebviewFocusChanged?(focused: boolean): void; protected onWebviewVisibilityChanged?(visible: boolean): void; @@ -82,14 +79,11 @@ export abstract class GlAppHost< this._logger.log('connected'); this._ipc = new HostIpc(this.name); - this._ipc.sendCommand(WebviewReadyCommand, undefined); - const state = this._ipc.deserializeIpcData(fromBase64ToString(this.bootstrap)); + const bootstrap = this.bootstrap; this.bootstrap = undefined!; - this._logger.log(`bootstrap duration=${Date.now() - state.timestamp}ms`); - - this.onPersistState?.(state); + this._stateProvider = this.createStateProvider(bootstrap, this._ipc, this._logger); const themeEvent = computeThemeColors(); if (this.onThemeUpdated != null) { @@ -99,7 +93,7 @@ export abstract class GlAppHost< } this.disposables.push( - (this._stateProvider = this.createStateProvider(state, this._ipc)), + this._stateProvider, this._ipc.onReceiveMessage(msg => { switch (true) { case DidChangeWebviewFocusNotification.is(msg): diff --git a/src/webviews/apps/shared/stateProviderBase.ts b/src/webviews/apps/shared/stateProviderBase.ts new file mode 100644 index 0000000000000..7332e6e679a47 --- /dev/null +++ b/src/webviews/apps/shared/stateProviderBase.ts @@ -0,0 +1,85 @@ +import type { Context, ContextProvider, ContextType } from '@lit/context'; +import { fromBase64ToString } from '@env/base64'; +import { isPromise } from '../../../system/promise'; +import type { IpcMessage, WebviewState } from '../../protocol'; +import { WebviewReadyRequest } from '../../protocol'; +import type { ReactiveElementHost } from './appHost'; +import type { LoggerContext } from './contexts/logger'; +import type { Disposable } from './events'; +import type { HostIpc } from './ipc'; + +/** + * Base class for webview state providers that handles bootstrap initialization. + * + * Subclasses declare their bootstrap strategy ('sync' or 'async') and implement + * message handling. The base class automatically handles state initialization: + * - Sync: Uses bootstrap state from HTML + * - Async: Requests full state from extension after connection + */ +export abstract class StateProviderBase> + implements Disposable +{ + protected readonly disposable: Disposable; + protected readonly provider: ContextProvider; + + protected _state: State; + get state(): State { + return this._state; + } + + get webviewId() { + return this._state.webviewId; + } + + get webviewInstanceId() { + return this._state.webviewInstanceId; + } + + get timestamp() { + return this._state.timestamp; + } + + constructor( + protected host: ReactiveElementHost, + bootstrap: string, + protected ipc: HostIpc, + protected logger: LoggerContext, + ) { + // Deserialize bootstrap from base64 + this._state = this.ipc.deserializeIpcData(fromBase64ToString(bootstrap)); + this.logger?.log(`bootstrap duration=${Date.now() - this._state.timestamp}ms`); + + this.provider = this.createContextProvider(this._state); + this.onPersistState?.(this._state); + + this.disposable = this.ipc.onReceiveMessage(this.onMessageReceived.bind(this)); + void this.initializeState(); + } + + dispose(): void { + this.disposable.dispose(); + } + + protected get deferBootstrap(): boolean { + return false; + } + + protected abstract createContextProvider(state: State): ContextProvider; + + protected async initializeState(): Promise { + if (this.deferBootstrap) { + const response = await this.ipc.sendRequest(WebviewReadyRequest, { bootstrap: true }); + if (response.state != null) { + const state: State = (isPromise(response.state) ? await response.state : response.state) as State; + this._state = { ...state, timestamp: Date.now() }; + this.provider.setValue(this._state as ContextType, true); + this.host.requestUpdate(); + } + } else { + void this.ipc.sendRequest(WebviewReadyRequest, { bootstrap: false }); + } + } + + protected abstract onMessageReceived(msg: IpcMessage): void; + protected onPersistState?(state: State): void; +} diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index ca36a416bd694..4e2b41eaf26e5 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -72,7 +72,6 @@ import type { LinesChangeEvent } from '../../trackers/lineTracker'; import type { ShowInCommitGraphCommandArgs } from '../plus/graph/registration'; import type { Change } from '../plus/patchDetails/protocol'; import type { IpcCallMessageType, IpcMessage } from '../protocol'; -import { updatePendingContext } from '../webviewController'; import type { WebviewHost, WebviewProvider, WebviewShowingArgs } from '../webviewProvider'; import type { WebviewShowOptions } from '../webviewsController'; import { isSerializedState } from '../webviewsController'; @@ -100,6 +99,7 @@ import { DidChangeHasAccountNotification, DidChangeIntegrationsNotification, DidChangeNotification, + DidChangeOrgSettingsNotification, DidChangeWipStateNotification, ExecuteCommitActionCommand, ExecuteFileActionCommand, @@ -169,11 +169,8 @@ interface Context { } export class CommitDetailsWebviewProvider implements WebviewProvider { - private _bootstraping = true; /** The context the webview has */ private _context: Context; - /** The context the webview should have */ - private _pendingContext: Partial | undefined; private readonly _disposable: Disposable; private _pinned = false; private _focused = false; @@ -276,15 +273,15 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - this.updatePendingContext({ source: arg.source }); + this._context.source = arg.source; const shouldChangeReview = arg.inReview != null && this.inReview !== arg.inReview; if (this.mode !== 'wip' || (arg.repository != null && this._context.wip?.repo !== arg.repository)) { - if (shouldChangeReview) { - this.updatePendingContext({ inReview: arg.inReview }); + if (shouldChangeReview && arg.inReview != null) { + this._context.inReview = arg.inReview; } await this.setMode('wip', arg.repository); if (shouldChangeReview && arg.inReview === true) { @@ -384,12 +381,14 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - this._bootstraping = true; - - this._context = { ...this._context, ...this._pendingContext }; - this._pendingContext = undefined; - + includeBootstrap(deferrable?: boolean): Promise { + if (deferrable) { + return Promise.resolve({ + webviewId: this.host.id, + webviewInstanceId: this.host.instanceId, + timestamp: Date.now(), + } as State); + } return this.getState(this._context); } @@ -825,7 +824,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { @@ -915,9 +897,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { @@ -950,8 +930,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - this.updatePendingContext({ mode: mode }); + this._context.mode = mode; if (mode === 'commit') { - this.updateState(true); + void this.notifyDidChangeState(true); } else { await this.updateWipState(repository ?? this.container.git.getBestRepositoryOrFirst()); } @@ -1301,27 +1280,26 @@ export class CommitDetailsWebviewProvider implements WebviewProvider, force: boolean = false): boolean { - const [changed, pending] = updatePendingContext(this._context, this._pendingContext, context, force); - if (changed) { - this._pendingContext = pending; - } - - return changed; - } + private _notifyDidChangeCommitDebounced: Deferrable<() => void> | undefined = undefined; - private _notifyDidChangeStateDebounced: Deferrable<() => void> | undefined = undefined; - - private updateState(immediate: boolean = false) { + private notifyDidChangeCommit(immediate: boolean = false) { if (immediate) { void this.notifyDidChangeState(); return; } - this._notifyDidChangeStateDebounced ??= debounce(this.notifyDidChangeState.bind(this), 500); - this._notifyDidChangeStateDebounced(); + this._notifyDidChangeCommitDebounced ??= debounce(this.notifyDidChangeState.bind(this), 500); + this._notifyDidChangeCommitDebounced(); + } + + private notifyDidChangeOrgSettings() { + this._context.orgSettings = this.getOrgSettings(); + void this.host.notify(DidChangeOrgSettingsNotification, { + orgSettings: this._context.orgSettings, + }); + } + + private notifyDidChangeHasAccount(hasAccount: boolean) { + this._context.hasAccount = hasAccount; + void this.host.notify(DidChangeHasAccountNotification, { hasAccount: hasAccount }); + } + + private notifyDidChangeIntegrations(hasIntegrationsConnected: boolean) { + this._context.hasIntegrationsConnected = hasIntegrationsConnected; + void this.host.notify(DidChangeIntegrationsNotification, { + hasIntegrationsConnected: hasIntegrationsConnected, + }); } private updateNavigation() { @@ -1621,53 +1603,43 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { try { await this.host.notify(DidChangeNotification, { - state: await this.getState(context), + state: await this.getState(this._context), }); } catch (ex) { Logger.error(ex, scope); @@ -1687,9 +1659,15 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { + includeBootstrap(_deferrable?: boolean): Promise { return this.getState(); } diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index dc0d37776ffdd..d8713aabe73c4 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -258,7 +258,7 @@ export class ComposerWebviewProvider implements WebviewProvider { + includeBootstrap(_deferrable?: boolean): Promise { return this._cache.get('bootstrap', () => this.getBootstrapState()); } diff --git a/src/webviews/plus/graph/graphWebview.ts b/src/webviews/plus/graph/graphWebview.ts index a616cb0627bb8..cbc3bd4430ab8 100644 --- a/src/webviews/plus/graph/graphWebview.ts +++ b/src/webviews/plus/graph/graphWebview.ts @@ -487,7 +487,7 @@ export class GraphWebviewProvider implements WebviewProvider { + includeBootstrap(_deferrable?: boolean): Promise { return this.getState(true); } @@ -734,7 +734,11 @@ export class GraphWebviewProvider implements WebviewProvider> { + includeBootstrap(_deferrable?: boolean): Promise> { return this.getState(this._context); } diff --git a/src/webviews/plus/timeline/timelineWebview.ts b/src/webviews/plus/timeline/timelineWebview.ts index 745f1f669b69d..12caf689dd6e9 100644 --- a/src/webviews/plus/timeline/timelineWebview.ts +++ b/src/webviews/plus/timeline/timelineWebview.ts @@ -223,7 +223,7 @@ export class TimelineWebviewProvider implements WebviewProvider { + includeBootstrap(_deferrable?: boolean): Promise { return this._cache.get('bootstrap', () => this.getState(this._context, false)); } diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts index bff9a651b5e30..59769f377e05d 100644 --- a/src/webviews/protocol.ts +++ b/src/webviews/protocol.ts @@ -72,9 +72,15 @@ export class IpcRequest extends IpcCall extends IpcCall {} -// COMMANDS +// COMMANDS & REQUESTS -export const WebviewReadyCommand = new IpcCommand('core', 'webview/ready'); +export interface WebviewReadyResponse { + state?: unknown | Promise; +} +export const WebviewReadyRequest = new IpcRequest<{ bootstrap?: boolean }, WebviewReadyResponse>( + 'core', + 'webview/ready', +); export interface WebviewFocusChangedParams { focused: boolean; diff --git a/src/webviews/settings/settingsWebview.ts b/src/webviews/settings/settingsWebview.ts index 82be14a63c520..7dd1e07e30768 100644 --- a/src/webviews/settings/settingsWebview.ts +++ b/src/webviews/settings/settingsWebview.ts @@ -88,7 +88,7 @@ export class SettingsWebviewProvider implements WebviewProvider { + async includeBootstrap(_deferrable?: boolean): Promise { const scopes: ['user' | 'workspace', string][] = [['user', 'User']]; if (workspace.workspaceFolders?.length) { scopes.push(['workspace', 'Workspace']); diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index f33d9a7e9a717..7335df84e2f21 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -41,7 +41,7 @@ import { IpcPromiseSettled, TelemetrySendEventCommand, WebviewFocusChangedCommand, - WebviewReadyCommand, + WebviewReadyRequest, } from './protocol'; import type { WebviewCommandCallback, WebviewCommandRegistrar } from './webviewCommandRegistrar'; import type { WebviewHost, WebviewProvider, WebviewShowingArgs } from './webviewProvider'; @@ -482,8 +482,11 @@ export class WebviewController< setLogScopeExit(scope, ` \u2022 ipc (webview -> host) duration=${Date.now() - e.timestamp}ms`); switch (true) { - case WebviewReadyCommand.is(e): + case WebviewReadyRequest.is(e): this._ready = true; + void this.respond(WebviewReadyRequest, e, { + state: e.params.bootstrap ? this.provider.includeBootstrap?.(false) : undefined, + }); this.sendPendingIpcNotifications(); void this.provider.onReady?.(); @@ -617,7 +620,7 @@ export class WebviewController< const [bytes, bootstrap, head, body, endOfBody] = await Promise.all([ workspace.fs.readFile(uri), - this.provider.includeBootstrap?.(), + this.provider.includeBootstrap?.(true), this.provider.includeHead?.(), this.provider.includeBody?.(), this.provider.includeEndOfBody?.(), diff --git a/src/webviews/webviewProvider.ts b/src/webviews/webviewProvider.ts index ec884abe094cf..2a39c8753e10a 100644 --- a/src/webviews/webviewProvider.ts +++ b/src/webviews/webviewProvider.ts @@ -35,7 +35,7 @@ export interface WebviewProvider | undefined]>; registerCommands?(): Disposable[]; - includeBootstrap?(): SerializedState | Promise; + includeBootstrap?(deferrable?: boolean): SerializedState | Promise; includeHead?(): string | Promise; includeBody?(): string | Promise; includeEndOfBody?(): string | Promise; From 138b1fa36e1ba551ca76ed933d3605e2a7951a96 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 6 Oct 2025 17:52:33 -0400 Subject: [PATCH 53/83] Adds context menus to Commit/Graph details --- contributions.json | 893 ++++++++++++++++- package.json | 943 +++++++++++++++++- src/constants.commands.generated.ts | 64 ++ src/constants.commands.ts | 35 +- src/constants.context.ts | 8 +- src/constants.views.ts | 16 + src/env/node/gk/cli/commands.ts | 3 +- src/system/decorators/command.ts | 35 +- src/views/viewCommands.ts | 31 +- .../components/gl-commit-details.ts | 38 +- .../components/gl-details-base.ts | 6 + .../components/gl-wip-details.ts | 26 +- .../shared/components/tree/tree-generator.ts | 50 + .../apps/shared/components/tree/tree-item.ts | 27 + .../commitDetails/commitDetailsWebview.ts | 505 +++++++++- .../commitDetailsWebview.utils.ts | 82 ++ src/webviews/commitDetails/protocol.ts | 20 + src/webviews/webviewController.ts | 13 +- src/webviews/webviewProvider.ts | 3 +- src/webviews/webviewsController.ts | 10 +- 20 files changed, 2680 insertions(+), 128 deletions(-) create mode 100644 src/webviews/commitDetails/commitDetailsWebview.utils.ts diff --git a/contributions.json b/contributions.json index ad619c838fb8f..f28ed3ee9f52b 100644 --- a/contributions.json +++ b/contributions.json @@ -660,7 +660,33 @@ "menus": { "gitlens/share": [ { - "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))/ && !listMultiSelection", + "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))\\b/ && !listMultiSelection", + "group": "1_gitlens", + "order": 25 + } + ] + } + }, + "gitlens.copyDeepLinkToCommit:commitDetails": { + "label": "Copy Link to Commit", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 25 + } + ] + } + }, + "gitlens.copyDeepLinkToCommit:graphDetails": { + "label": "Copy Link to Commit", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && webview == gitlens.views.graphDetails", "group": "1_gitlens", "order": 25 } @@ -706,6 +732,32 @@ ] } }, + "gitlens.copyDeepLinkToFile:commitDetails": { + "label": "Copy Link to File", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 26 + } + ] + } + }, + "gitlens.copyDeepLinkToFile:graphDetails": { + "label": "Copy Link to File", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 26 + } + ] + } + }, "gitlens.copyDeepLinkToFileAtRevision": { "label": "Copy Link to File at Revision...", "icon": "$(copy)", @@ -733,6 +785,32 @@ ] } }, + "gitlens.copyDeepLinkToFileAtRevision:commitDetails": { + "label": "Copy Link to File at Revision...", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 27 + } + ] + } + }, + "gitlens.copyDeepLinkToFileAtRevision:graphDetails": { + "label": "Copy Link to File at Revision...", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 27 + } + ] + } + }, "gitlens.copyDeepLinkToLines": { "label": "Copy Link to Code", "icon": "$(copy)", @@ -829,6 +907,18 @@ "label": "Copy Changes (Patch)", "commandPalette": "gitlens:enabled && !gitlens:untrusted && !gitlens:hasVirtualFolders" }, + "gitlens.copyPatchToClipboard:commitDetails": { + "label": "Copy Changes (Patch)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste", + "order": 3 + } + ] + } + }, "gitlens.copyPatchToClipboard:graph": { "label": "Copy Changes (Patch)", "menus": { @@ -841,6 +931,18 @@ ] } }, + "gitlens.copyPatchToClipboard:graphDetails": { + "label": "Copy Changes (Patch)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste", + "order": 3 + } + ] + } + }, "gitlens.copyPatchToClipboard:scm": { "label": "Copy Changes (Patch)", "menus": { @@ -924,6 +1026,32 @@ ] } }, + "gitlens.copyRelativePathToClipboard:commitDetails": { + "label": "Copy Relative Path", + "icon": "$(copy)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste", + "order": 2 + } + ] + } + }, + "gitlens.copyRelativePathToClipboard:graphDetails": { + "label": "Copy Relative Path", + "icon": "$(copy)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste", + "order": 2 + } + ] + } + }, "gitlens.copyRemoteBranchesUrl": { "label": "Copy Remote Branches URL", "icon": "$(copy)" @@ -1041,6 +1169,32 @@ ] } }, + "gitlens.copyRemoteFileUrlFrom:commitDetails": { + "label": "Copy Remote File URL From...", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens", + "order": 2 + } + ] + } + }, + "gitlens.copyRemoteFileUrlFrom:graphDetails": { + "label": "Copy Remote File URL From...", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens", + "order": 2 + } + ] + } + }, "gitlens.copyRemoteFileUrlToClipboard": { "label": "Copy Remote File URL", "icon": "$(copy)", @@ -1100,6 +1254,32 @@ ] } }, + "gitlens.copyRemoteFileUrlWithoutRange:commitDetails": { + "label": "Copy Remote File URL", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.copyRemoteFileUrlWithoutRange:graphDetails": { + "label": "Copy Remote File URL", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens", + "order": 1 + } + ] + } + }, "gitlens.copyRemotePullRequestUrl": { "label": "Copy Pull Request URL", "icon": "$(copy)" @@ -1456,6 +1636,7 @@ "menus": { "gitlens/commit/file/changes": [ { + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens", "order": 3 } @@ -1488,12 +1669,39 @@ ] } }, + "gitlens.diffWithRevision:commitDetails": { + "label": "Open Changes with Revision...", + "icon": "$(gitlens-prev-commit-menu)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 3 + } + ] + } + }, + "gitlens.diffWithRevision:graphDetails": { + "label": "Open Changes with Revision...", + "icon": "$(gitlens-prev-commit-menu)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 3 + } + ] + } + }, "gitlens.diffWithRevisionFrom": { "label": "Open Changes with Branch or Tag...", "commandPalette": "resource in gitlens:tabs:tracked", "menus": { "gitlens/commit/file/changes": [ { + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens", "order": 4 } @@ -1526,6 +1734,30 @@ ] } }, + "gitlens.diffWithRevisionFrom:commitDetails": { + "label": "Open Changes with Branch or Tag...", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 4 + } + ] + } + }, + "gitlens.diffWithRevisionFrom:graphDetails": { + "label": "Open Changes with Branch or Tag...", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 4 + } + ] + } + }, "gitlens.diffWithWorking": { "label": "Open Changes with Working File", "icon": "$(gitlens-compare-ref-working)", @@ -1622,7 +1854,7 @@ { "when": "viewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders", "group": "1_gitlens_", - "order": 1 + "order": 5 } ], "gitlens/scm/resourceState/changes": [ @@ -1634,6 +1866,30 @@ ] } }, + "gitlens.externalDiff:commitDetails": { + "label": "Open Changes (difftool)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_", + "order": 5 + } + ] + } + }, + "gitlens.externalDiff:graphDetails": { + "label": "Open Changes (difftool)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_", + "order": 5 + } + ] + } + }, "gitlens.externalDiffAll": { "label": "Open All Changes (difftool)", "commandPalette": "gitlens:enabled && !gitlens:hasVirtualFolders", @@ -3430,7 +3686,7 @@ "menus": { "gitlens/commit/file/history": [ { - "when": "view != gitlens.views.fileHistory/", + "when": "viewItem =~ /gitlens:file\\b/ && view != gitlens.views.fileHistory/", "group": "1_gitlens", "order": 1 } @@ -3455,6 +3711,32 @@ ] } }, + "gitlens.openFileHistory:commitDetails": { + "label": "Open File History", + "icon": "$(history)", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.openFileHistory:graphDetails": { + "label": "Open File History", + "icon": "$(history)", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 1 + } + ] + } + }, "gitlens.openFileOnRemote": { "label": "Open File on Remote", "icon": "$(globe)", @@ -3517,6 +3799,32 @@ ] } }, + "gitlens.openFileOnRemote:commitDetails": { + "label": "Open File on Remote", + "icon": "$(globe)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file", + "order": 5 + } + ] + } + }, + "gitlens.openFileOnRemote:graphDetails": { + "label": "Open File on Remote", + "icon": "$(globe)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file", + "order": 5 + } + ] + } + }, "gitlens.openFileOnRemoteFrom": { "label": "Open File on Remote From...", "icon": "$(globe)", @@ -3908,6 +4216,7 @@ "menus": { "gitlens/commit/file/history": [ { + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens_quick", "order": 1 } @@ -3932,6 +4241,30 @@ ] } }, + "gitlens.quickOpenFileHistory:commitDetails": { + "label": "Quick Open File History", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_quick", + "order": 1 + } + ] + } + }, + "gitlens.quickOpenFileHistory:graphDetails": { + "label": "Quick Open File History", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_quick", + "order": 1 + } + ] + } + }, "gitlens.regenerateMarkdownDocument": { "label": "Regenerate", "icon": "$(refresh)", @@ -3960,6 +4293,42 @@ "label": "Reset Views Layout", "commandPalette": true }, + "gitlens.restore.file:commitDetails": { + "label": "Restore Changes (Checkout)", + "icon": "$(discard)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions", + "order": 3 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions", + "order": 3 + } + ] + } + }, + "gitlens.restore.file:graphDetails": { + "label": "Restore Changes (Checkout)", + "icon": "$(discard)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions", + "order": 3 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions", + "order": 3 + } + ] + } + }, "gitlens.restore.file:views": { "label": "Restore Changes (Checkout)", "menus": { @@ -3977,6 +4346,30 @@ ] } }, + "gitlens.restorePrevious.file:commitDetails": { + "label": "Restore Previous Changes", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions", + "order": 4 + } + ] + } + }, + "gitlens.restorePrevious.file:graphDetails": { + "label": "Restore Previous Changes", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions", + "order": 4 + } + ] + } + }, "gitlens.restorePrevious.file:views": { "label": "Restore Previous Changes", "menus": { @@ -4069,6 +4462,30 @@ ] } }, + "gitlens.shareAsCloudPatch:commitDetails": { + "label": "Share as Cloud Patch...", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webview == gitlens.views.commitDetails", + "group": "1_a_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.shareAsCloudPatch:graphDetails": { + "label": "Share as Cloud Patch...", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webview == gitlens.views.graphDetails", + "group": "1_a_gitlens", + "order": 1 + } + ] + } + }, "gitlens.showAccountView": { "label": "Show Account on Home", "commandPalette": true @@ -5911,6 +6328,42 @@ ] } }, + "gitlens.views.applyChanges:commitDetails": { + "label": "Apply Changes", + "enablement": "!operationInProgress", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions", + "order": 1 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions", + "order": 1 + } + ] + } + }, + "gitlens.views.applyChanges:graphDetails": { + "label": "Apply Changes", + "enablement": "!operationInProgress", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions", + "order": 1 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions", + "order": 1 + } + ] + } + }, "gitlens.views.associateIssueWithBranch": { "label": "Associate Issue with Branch...", "enablement": "!operationInProgress", @@ -7414,6 +7867,30 @@ ] } }, + "gitlens.views.compareFileWithSelected:commitDetails": { + "label": "Compare with Selected", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && !listMultiSelection && gitlens:views:canCompare:file && webview == gitlens.views.commitDetails", + "group": "4_gitlens_compare", + "order": 99 + } + ] + } + }, + "gitlens.views.compareFileWithSelected:graphDetails": { + "label": "Compare with Selected", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && !listMultiSelection && gitlens:views:canCompare:file && webview == gitlens.views.graphDetails", + "group": "4_gitlens_compare", + "order": 99 + } + ] + } + }, "gitlens.views.compareWithHead": { "label": "Compare to/from HEAD", "icon": "$(compare-changes)", @@ -8005,6 +8482,32 @@ ] } }, + "gitlens.views.copy:commitDetails": { + "label": "Copy", + "icon": "$(copy)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+(staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste", + "order": 1 + } + ] + } + }, + "gitlens.views.copy:graphDetails": { + "label": "Copy", + "icon": "$(copy)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+(staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste", + "order": 1 + } + ] + } + }, "gitlens.views.copyAsMarkdown": { "label": "Copy as Markdown", "icon": "$(copy)", @@ -8029,7 +8532,33 @@ "menus": { "gitlens/share": [ { - "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))/ && !listMultiSelection && gitlens:repos:withRemotes", + "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))\\b/ && !listMultiSelection && gitlens:repos:withRemotes", + "group": "2_gitlens", + "order": 25 + } + ] + } + }, + "gitlens.views.copyRemoteCommitUrl:commitDetails": { + "label": "Copy Remote Commit URL", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens", + "order": 25 + } + ] + } + }, + "gitlens.views.copyRemoteCommitUrl:graphDetails": { + "label": "Copy Remote Commit URL", + "icon": "$(copy)", + "menus": { + "gitlens/share": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", "group": "2_gitlens", "order": 25 } @@ -9157,31 +9686,79 @@ ], "view/title": [ { - "when": "view == gitlens.views.graphDetails", - "group": "navigation", - "order": 99 + "when": "view == gitlens.views.graphDetails", + "group": "navigation", + "order": 99 + } + ] + } + }, + "gitlens.views.highlightChanges": { + "label": "Highlight All Changes Since Before this Commit", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+(committed|stashed)\\b)|:results)/", + "group": "2_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.views.highlightChanges:commitDetails": { + "label": "Highlight All Changes Since Before this Commit", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.views.highlightChanges:graphDetails": { + "label": "Highlight All Changes Since Before this Commit", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.views.highlightRevisionChanges": { + "label": "Highlight Changes from this Commit", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results)/", + "group": "2_gitlens", + "order": 2 } ] } }, - "gitlens.views.highlightChanges": { - "label": "Highlight All Changes Since Before this Commit", + "gitlens.views.highlightRevisionChanges:commitDetails": { + "label": "Highlight Changes from this Commit", "menus": { "gitlens/commit/file/changes": [ { - "when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+(committed|stashed)\\b)|:results)/", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", "group": "2_gitlens", - "order": 1 + "order": 2 } ] } }, - "gitlens.views.highlightRevisionChanges": { + "gitlens.views.highlightRevisionChanges:graphDetails": { "label": "Highlight Changes from this Commit", "menus": { "gitlens/commit/file/changes": [ { - "when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results)/", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", "group": "2_gitlens", "order": 2 } @@ -9825,6 +10402,40 @@ ] } }, + "gitlens.views.mergeChangesWithWorking:commitDetails": { + "label": "Merge Changes (Manually)...", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions", + "order": 2 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions", + "order": 2 + } + ] + } + }, + "gitlens.views.mergeChangesWithWorking:graphDetails": { + "label": "Merge Changes (Manually)...", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions", + "order": 2 + }, + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions", + "order": 2 + } + ] + } + }, "gitlens.views.openBranchOnRemote": { "label": "Open Branch on Remote", "icon": "$(globe)", @@ -9971,6 +10582,32 @@ ] } }, + "gitlens.views.openChanges:commitDetails": { + "label": "Open Changes", + "icon": "$(git-compare)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen", + "order": 1 + } + ] + } + }, + "gitlens.views.openChanges:graphDetails": { + "label": "Open Changes", + "icon": "$(git-compare)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen", + "order": 1 + } + ] + } + }, "gitlens.views.openChangesWithMergeBase": { "label": "Open Changes with Common Base", "menus": { @@ -10003,6 +10640,32 @@ ] } }, + "gitlens.views.openChangesWithWorking:commitDetails": { + "label": "Open Changes with Working File", + "icon": "$(gitlens-compare-ref-working)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 1 + } + ] + } + }, + "gitlens.views.openChangesWithWorking:graphDetails": { + "label": "Open Changes with Working File", + "icon": "$(gitlens-compare-ref-working)", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 1 + } + ] + } + }, "gitlens.views.openCommitOnRemote": { "label": "Open Commit on Remote", "icon": "$(globe)", @@ -10090,6 +10753,32 @@ ] } }, + "gitlens.views.openFile:commitDetails": { + "label": "Open File", + "icon": "$(go-to-file)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file", + "order": 3 + } + ] + } + }, + "gitlens.views.openFile:graphDetails": { + "label": "Open File", + "icon": "$(go-to-file)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file", + "order": 3 + } + ] + } + }, "gitlens.views.openFileRevision": { "label": "Open File at Revision", "icon": "$(gitlens-open-revision)", @@ -10109,6 +10798,32 @@ ] } }, + "gitlens.views.openFileRevision:commitDetails": { + "label": "Open File at Revision", + "icon": "$(gitlens-open-revision)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file", + "order": 4 + } + ] + } + }, + "gitlens.views.openFileRevision:graphDetails": { + "label": "Open File at Revision", + "icon": "$(gitlens-open-revision)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file", + "order": 4 + } + ] + } + }, "gitlens.views.openInIntegratedTerminal": { "label": "Open in Integrated Terminal", "menus": { @@ -10217,6 +10932,30 @@ ] } }, + "gitlens.views.openPreviousChangesWithWorking:commitDetails": { + "label": "Open Previous Changes with Working File", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 2 + } + ] + } + }, + "gitlens.views.openPreviousChangesWithWorking:graphDetails": { + "label": "Open Previous Changes with Working File", + "menus": { + "gitlens/commit/file/changes": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 2 + } + ] + } + }, "gitlens.views.openPullRequest": { "label": "Open Pull Request", "icon": "$(git-pull-request)", @@ -13859,6 +14598,30 @@ ] } }, + "gitlens.views.selectFileForCompare:commitDetails": { + "label": "Select for Compare", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && webview == gitlens.views.commitDetails", + "group": "4_gitlens_compare", + "order": 99 + } + ] + } + }, + "gitlens.views.selectFileForCompare:graphDetails": { + "label": "Select for Compare", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && webview == gitlens.views.graphDetails", + "group": "4_gitlens_compare", + "order": 99 + } + ] + } + }, "gitlens.views.selectForCompare": { "label": "Select for Compare", "menus": { @@ -14542,6 +15305,32 @@ ] } }, + "gitlens.views.stageFile:commitDetails": { + "label": "Stage Changes", + "icon": "$(add)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+unstaged\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions", + "order": 1 + } + ] + } + }, + "gitlens.views.stageFile:graphDetails": { + "label": "Stage Changes", + "icon": "$(add)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+unstaged\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions", + "order": 1 + } + ] + } + }, "gitlens.views.stashes.attach": { "label": "Group into GitLens View", "icon": "$(close)", @@ -15358,6 +16147,32 @@ ] } }, + "gitlens.views.unstageFile:commitDetails": { + "label": "Unstage Changes", + "icon": "$(remove)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+staged\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions", + "order": 2 + } + ] + } + }, + "gitlens.views.unstageFile:graphDetails": { + "label": "Unstage Changes", + "icon": "$(remove)", + "menus": { + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+staged\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions", + "order": 2 + } + ] + } + }, "gitlens.views.workspaces.addRepos": { "label": "Add Repositories...", "icon": "$(add)", @@ -16206,6 +17021,19 @@ "icon": "$(graph-scatter)", "commandPalette": "gitlens:enabled && resource in gitlens:tabs:tracked" }, + "gitlens.visualizeHistory.file:commitDetails": { + "label": "Open Visual File History", + "icon": "$(graph-scatter)", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens", + "order": 2 + } + ] + } + }, "gitlens.visualizeHistory.file:editor": { "label": "Open Visual File History", "icon": "$(graph-scatter)", @@ -16230,6 +17058,19 @@ ] } }, + "gitlens.visualizeHistory.file:graphDetails": { + "label": "Open Visual File History", + "icon": "$(graph-scatter)", + "menus": { + "gitlens/commit/file/history": [ + { + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens", + "order": 2 + } + ] + } + }, "gitlens.visualizeHistory.file:scm": { "label": "Open Visual File History", "icon": "$(graph-scatter)", @@ -16248,6 +17089,7 @@ "menus": { "gitlens/commit/file/history": [ { + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens", "order": 2 } @@ -16357,7 +17199,7 @@ "menus": { "view/item/context": [ { - "when": "viewItem =~ /gitlens:(branch|commit|file\\b(?=.*?\\b\\+committed\\b)|stash|tag)\\b/ && !listMultiSelection && !gitlens:hasVirtualFolders", + "when": "viewItem =~ /gitlens:(branch|commit|stash|tag)\\b/ && !listMultiSelection && !gitlens:hasVirtualFolders", "group": "3_gitlens_explore", "order": 100 } @@ -16385,6 +17227,13 @@ "group": "7_gitlens_cutcopypaste", "order": 10 } + ], + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/", + "group": "7_gitlens_cutcopypaste", + "order": 10 + } ] } }, @@ -16397,6 +17246,13 @@ "group": "2_gitlens_quickopen", "order": 2 } + ], + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/", + "group": "2_gitlens_quickopen", + "order": 2 + } ] } }, @@ -16421,6 +17277,13 @@ "group": "3_gitlens_explore", "order": 2 } + ], + "webview/context": [ + { + "when": "webviewItem =~ /gitlens:file\\b/", + "group": "3_gitlens_explore", + "order": 2 + } ] } }, @@ -16813,7 +17676,7 @@ ], "webview/context": [ { - "when": "webviewItem =~ /gitlens:(branch|commit|stash|tag)\\b/", + "when": "webviewItem =~ /gitlens:(branch|commit|stash|tag|file\\b(?=.*?\\b\\+(committed|staged|unstaged)\\b))\\b/", "group": "7_gitlens_a_share", "order": 1 } diff --git a/package.json b/package.json index d82639761acbf..5e1d89b2c5a97 100644 --- a/package.json +++ b/package.json @@ -6487,6 +6487,16 @@ "title": "Copy Link to Commit", "icon": "$(copy)" }, + { + "command": "gitlens.copyDeepLinkToCommit:commitDetails", + "title": "Copy Link to Commit", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyDeepLinkToCommit:graphDetails", + "title": "Copy Link to Commit", + "icon": "$(copy)" + }, { "command": "gitlens.copyDeepLinkToComparison", "title": "Copy Link to Comparison", @@ -6497,11 +6507,31 @@ "title": "Copy Link to File", "icon": "$(copy)" }, + { + "command": "gitlens.copyDeepLinkToFile:commitDetails", + "title": "Copy Link to File", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyDeepLinkToFile:graphDetails", + "title": "Copy Link to File", + "icon": "$(copy)" + }, { "command": "gitlens.copyDeepLinkToFileAtRevision", "title": "Copy Link to File at Revision...", "icon": "$(copy)" }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:commitDetails", + "title": "Copy Link to File at Revision...", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:graphDetails", + "title": "Copy Link to File at Revision...", + "icon": "$(copy)" + }, { "command": "gitlens.copyDeepLinkToLines", "title": "Copy Link to Code", @@ -6534,10 +6564,18 @@ "title": "Copy Changes (Patch)", "category": "GitLens" }, + { + "command": "gitlens.copyPatchToClipboard:commitDetails", + "title": "Copy Changes (Patch)" + }, { "command": "gitlens.copyPatchToClipboard:graph", "title": "Copy Changes (Patch)" }, + { + "command": "gitlens.copyPatchToClipboard:graphDetails", + "title": "Copy Changes (Patch)" + }, { "command": "gitlens.copyPatchToClipboard:scm", "title": "Copy Changes (Patch)" @@ -6552,6 +6590,16 @@ "category": "GitLens", "icon": "$(copy)" }, + { + "command": "gitlens.copyRelativePathToClipboard:commitDetails", + "title": "Copy Relative Path", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyRelativePathToClipboard:graphDetails", + "title": "Copy Relative Path", + "icon": "$(copy)" + }, { "command": "gitlens.copyRemoteBranchesUrl", "title": "Copy Remote Branches URL", @@ -6579,6 +6627,16 @@ "category": "GitLens", "icon": "$(copy)" }, + { + "command": "gitlens.copyRemoteFileUrlFrom:commitDetails", + "title": "Copy Remote File URL From...", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyRemoteFileUrlFrom:graphDetails", + "title": "Copy Remote File URL From...", + "icon": "$(copy)" + }, { "command": "gitlens.copyRemoteFileUrlToClipboard", "title": "Copy Remote File URL", @@ -6590,6 +6648,16 @@ "title": "Copy Remote File URL", "icon": "$(copy)" }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:commitDetails", + "title": "Copy Remote File URL", + "icon": "$(copy)" + }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:graphDetails", + "title": "Copy Remote File URL", + "icon": "$(copy)" + }, { "command": "gitlens.copyRemotePullRequestUrl", "title": "Copy Pull Request URL", @@ -6712,11 +6780,29 @@ "category": "GitLens", "icon": "$(gitlens-prev-commit-menu)" }, + { + "command": "gitlens.diffWithRevision:commitDetails", + "title": "Open Changes with Revision...", + "icon": "$(gitlens-prev-commit-menu)" + }, + { + "command": "gitlens.diffWithRevision:graphDetails", + "title": "Open Changes with Revision...", + "icon": "$(gitlens-prev-commit-menu)" + }, { "command": "gitlens.diffWithRevisionFrom", "title": "Open Changes with Branch or Tag...", "category": "GitLens" }, + { + "command": "gitlens.diffWithRevisionFrom:commitDetails", + "title": "Open Changes with Branch or Tag..." + }, + { + "command": "gitlens.diffWithRevisionFrom:graphDetails", + "title": "Open Changes with Branch or Tag..." + }, { "command": "gitlens.diffWithWorking", "title": "Open Changes with Working File", @@ -6769,6 +6855,14 @@ "title": "Open Changes (difftool)", "category": "GitLens" }, + { + "command": "gitlens.externalDiff:commitDetails", + "title": "Open Changes (difftool)" + }, + { + "command": "gitlens.externalDiff:graphDetails", + "title": "Open Changes (difftool)" + }, { "command": "gitlens.externalDiffAll", "title": "Open All Changes (difftool)", @@ -7553,12 +7647,32 @@ "title": "Open File History", "category": "GitLens" }, + { + "command": "gitlens.openFileHistory:commitDetails", + "title": "Open File History", + "icon": "$(history)" + }, + { + "command": "gitlens.openFileHistory:graphDetails", + "title": "Open File History", + "icon": "$(history)" + }, { "command": "gitlens.openFileOnRemote", "title": "Open File on Remote", "category": "GitLens", "icon": "$(globe)" }, + { + "command": "gitlens.openFileOnRemote:commitDetails", + "title": "Open File on Remote", + "icon": "$(globe)" + }, + { + "command": "gitlens.openFileOnRemote:graphDetails", + "title": "Open File on Remote", + "icon": "$(globe)" + }, { "command": "gitlens.openFileOnRemoteFrom", "title": "Open File on Remote From...", @@ -7724,6 +7838,14 @@ "title": "Quick Open File History", "category": "GitLens" }, + { + "command": "gitlens.quickOpenFileHistory:commitDetails", + "title": "Quick Open File History" + }, + { + "command": "gitlens.quickOpenFileHistory:graphDetails", + "title": "Quick Open File History" + }, { "command": "gitlens.regenerateMarkdownDocument", "title": "Regenerate", @@ -7739,10 +7861,28 @@ "title": "Reset Views Layout", "category": "GitLens" }, + { + "command": "gitlens.restore.file:commitDetails", + "title": "Restore Changes (Checkout)", + "icon": "$(discard)" + }, + { + "command": "gitlens.restore.file:graphDetails", + "title": "Restore Changes (Checkout)", + "icon": "$(discard)" + }, { "command": "gitlens.restore.file:views", "title": "Restore Changes (Checkout)" }, + { + "command": "gitlens.restorePrevious.file:commitDetails", + "title": "Restore Previous Changes" + }, + { + "command": "gitlens.restorePrevious.file:graphDetails", + "title": "Restore Previous Changes" + }, { "command": "gitlens.restorePrevious.file:views", "title": "Restore Previous Changes" @@ -7769,6 +7909,14 @@ "title": "Share as Cloud Patch...", "category": "GitLens" }, + { + "command": "gitlens.shareAsCloudPatch:commitDetails", + "title": "Share as Cloud Patch..." + }, + { + "command": "gitlens.shareAsCloudPatch:graphDetails", + "title": "Share as Cloud Patch..." + }, { "command": "gitlens.showAccountView", "title": "Show Account on Home", @@ -8369,6 +8517,16 @@ "title": "Apply Changes", "enablement": "!operationInProgress" }, + { + "command": "gitlens.views.applyChanges:commitDetails", + "title": "Apply Changes", + "enablement": "!operationInProgress" + }, + { + "command": "gitlens.views.applyChanges:graphDetails", + "title": "Apply Changes", + "enablement": "!operationInProgress" + }, { "command": "gitlens.views.associateIssueWithBranch", "title": "Associate Issue with Branch...", @@ -8615,6 +8773,14 @@ "command": "gitlens.views.compareFileWithSelected", "title": "Compare with Selected" }, + { + "command": "gitlens.views.compareFileWithSelected:commitDetails", + "title": "Compare with Selected" + }, + { + "command": "gitlens.views.compareFileWithSelected:graphDetails", + "title": "Compare with Selected" + }, { "command": "gitlens.views.compareWithHead", "title": "Compare to/from HEAD", @@ -8718,6 +8884,16 @@ "title": "Copy", "icon": "$(copy)" }, + { + "command": "gitlens.views.copy:commitDetails", + "title": "Copy", + "icon": "$(copy)" + }, + { + "command": "gitlens.views.copy:graphDetails", + "title": "Copy", + "icon": "$(copy)" + }, { "command": "gitlens.views.copyAsMarkdown", "title": "Copy as Markdown", @@ -8728,6 +8904,16 @@ "title": "Copy Remote Commit URL", "icon": "$(copy)" }, + { + "command": "gitlens.views.copyRemoteCommitUrl:commitDetails", + "title": "Copy Remote Commit URL", + "icon": "$(copy)" + }, + { + "command": "gitlens.views.copyRemoteCommitUrl:graphDetails", + "title": "Copy Remote Commit URL", + "icon": "$(copy)" + }, { "command": "gitlens.views.copyRemoteCommitUrl.multi", "title": "Copy Remote Commit URLs", @@ -8975,10 +9161,26 @@ "command": "gitlens.views.highlightChanges", "title": "Highlight All Changes Since Before this Commit" }, + { + "command": "gitlens.views.highlightChanges:commitDetails", + "title": "Highlight All Changes Since Before this Commit" + }, + { + "command": "gitlens.views.highlightChanges:graphDetails", + "title": "Highlight All Changes Since Before this Commit" + }, { "command": "gitlens.views.highlightRevisionChanges", "title": "Highlight Changes from this Commit" }, + { + "command": "gitlens.views.highlightRevisionChanges:commitDetails", + "title": "Highlight Changes from this Commit" + }, + { + "command": "gitlens.views.highlightRevisionChanges:graphDetails", + "title": "Highlight Changes from this Commit" + }, { "command": "gitlens.views.home.disablePreview", "title": "Revert to Old Home View", @@ -9120,6 +9322,14 @@ "command": "gitlens.views.mergeChangesWithWorking", "title": "Merge Changes (Manually)..." }, + { + "command": "gitlens.views.mergeChangesWithWorking:commitDetails", + "title": "Merge Changes (Manually)..." + }, + { + "command": "gitlens.views.mergeChangesWithWorking:graphDetails", + "title": "Merge Changes (Manually)..." + }, { "command": "gitlens.views.openBranchOnRemote", "title": "Open Branch on Remote", @@ -9166,6 +9376,16 @@ "title": "Open Changes", "icon": "$(compare-changes)" }, + { + "command": "gitlens.views.openChanges:commitDetails", + "title": "Open Changes", + "icon": "$(git-compare)" + }, + { + "command": "gitlens.views.openChanges:graphDetails", + "title": "Open Changes", + "icon": "$(git-compare)" + }, { "command": "gitlens.views.openChangesWithMergeBase", "title": "Open Changes with Common Base" @@ -9175,6 +9395,16 @@ "title": "Open Changes with Working File", "icon": "$(gitlens-compare-ref-working)" }, + { + "command": "gitlens.views.openChangesWithWorking:commitDetails", + "title": "Open Changes with Working File", + "icon": "$(gitlens-compare-ref-working)" + }, + { + "command": "gitlens.views.openChangesWithWorking:graphDetails", + "title": "Open Changes with Working File", + "icon": "$(gitlens-compare-ref-working)" + }, { "command": "gitlens.views.openCommitOnRemote", "title": "Open Commit on Remote", @@ -9198,11 +9428,31 @@ "title": "Open File", "icon": "$(go-to-file)" }, + { + "command": "gitlens.views.openFile:commitDetails", + "title": "Open File", + "icon": "$(go-to-file)" + }, + { + "command": "gitlens.views.openFile:graphDetails", + "title": "Open File", + "icon": "$(go-to-file)" + }, { "command": "gitlens.views.openFileRevision", "title": "Open File at Revision", "icon": "$(gitlens-open-revision)" }, + { + "command": "gitlens.views.openFileRevision:commitDetails", + "title": "Open File at Revision", + "icon": "$(gitlens-open-revision)" + }, + { + "command": "gitlens.views.openFileRevision:graphDetails", + "title": "Open File at Revision", + "icon": "$(gitlens-open-revision)" + }, { "command": "gitlens.views.openInIntegratedTerminal", "title": "Open in Integrated Terminal" @@ -9229,6 +9479,14 @@ "command": "gitlens.views.openPreviousChangesWithWorking", "title": "Open Previous Changes with Working File" }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:commitDetails", + "title": "Open Previous Changes with Working File" + }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:graphDetails", + "title": "Open Previous Changes with Working File" + }, { "command": "gitlens.views.openPullRequest", "title": "Open Pull Request", @@ -10039,6 +10297,14 @@ "command": "gitlens.views.selectFileForCompare", "title": "Select for Compare" }, + { + "command": "gitlens.views.selectFileForCompare:commitDetails", + "title": "Select for Compare" + }, + { + "command": "gitlens.views.selectFileForCompare:graphDetails", + "title": "Select for Compare" + }, { "command": "gitlens.views.selectForCompare", "title": "Select for Compare" @@ -10116,6 +10382,16 @@ "icon": "$(add)", "enablement": "!operationInProgress" }, + { + "command": "gitlens.views.stageFile:commitDetails", + "title": "Stage Changes", + "icon": "$(add)" + }, + { + "command": "gitlens.views.stageFile:graphDetails", + "title": "Stage Changes", + "icon": "$(add)" + }, { "command": "gitlens.views.stashes.attach", "title": "Group into GitLens View", @@ -10279,6 +10555,16 @@ "icon": "$(remove)", "enablement": "!operationInProgress" }, + { + "command": "gitlens.views.unstageFile:commitDetails", + "title": "Unstage Changes", + "icon": "$(remove)" + }, + { + "command": "gitlens.views.unstageFile:graphDetails", + "title": "Unstage Changes", + "icon": "$(remove)" + }, { "command": "gitlens.views.workspaces.addRepos", "title": "Add Repositories...", @@ -10453,6 +10739,11 @@ "category": "GitLens", "icon": "$(graph-scatter)" }, + { + "command": "gitlens.visualizeHistory.file:commitDetails", + "title": "Open Visual File History", + "icon": "$(graph-scatter)" + }, { "command": "gitlens.visualizeHistory.file:editor", "title": "Open Visual File History", @@ -10463,6 +10754,11 @@ "title": "Open Visual File History", "icon": "$(graph-scatter)" }, + { + "command": "gitlens.visualizeHistory.file:graphDetails", + "title": "Open Visual File History", + "icon": "$(graph-scatter)" + }, { "command": "gitlens.visualizeHistory.file:scm", "title": "Open Visual File History", @@ -11195,6 +11491,14 @@ "command": "gitlens.copyDeepLinkToCommit", "when": "false" }, + { + "command": "gitlens.copyDeepLinkToCommit:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyDeepLinkToCommit:graphDetails", + "when": "false" + }, { "command": "gitlens.copyDeepLinkToComparison", "when": "false" @@ -11203,10 +11507,26 @@ "command": "gitlens.copyDeepLinkToFile", "when": "false" }, + { + "command": "gitlens.copyDeepLinkToFile:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyDeepLinkToFile:graphDetails", + "when": "false" + }, { "command": "gitlens.copyDeepLinkToFileAtRevision", "when": "false" }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:graphDetails", + "when": "false" + }, { "command": "gitlens.copyDeepLinkToLines", "when": "false" @@ -11231,10 +11551,18 @@ "command": "gitlens.copyPatchToClipboard", "when": "gitlens:enabled && !gitlens:untrusted && !gitlens:hasVirtualFolders" }, + { + "command": "gitlens.copyPatchToClipboard:commitDetails", + "when": "false" + }, { "command": "gitlens.copyPatchToClipboard:graph", "when": "false" }, + { + "command": "gitlens.copyPatchToClipboard:graphDetails", + "when": "false" + }, { "command": "gitlens.copyPatchToClipboard:scm", "when": "false" @@ -11247,6 +11575,14 @@ "command": "gitlens.copyRelativePathToClipboard", "when": "gitlens:enabled" }, + { + "command": "gitlens.copyRelativePathToClipboard:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyRelativePathToClipboard:graphDetails", + "when": "false" + }, { "command": "gitlens.copyRemoteBranchesUrl", "when": "false" @@ -11267,6 +11603,14 @@ "command": "gitlens.copyRemoteFileUrlFrom", "when": "gitlens:repos:withRemotes" }, + { + "command": "gitlens.copyRemoteFileUrlFrom:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyRemoteFileUrlFrom:graphDetails", + "when": "false" + }, { "command": "gitlens.copyRemoteFileUrlToClipboard", "when": "gitlens:repos:withRemotes" @@ -11275,6 +11619,14 @@ "command": "gitlens.copyRemoteFileUrlWithoutRange", "when": "false" }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:commitDetails", + "when": "false" + }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:graphDetails", + "when": "false" + }, { "command": "gitlens.copyRemotePullRequestUrl", "when": "false" @@ -11367,10 +11719,26 @@ "command": "gitlens.diffWithRevision", "when": "resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.diffWithRevision:commitDetails", + "when": "false" + }, + { + "command": "gitlens.diffWithRevision:graphDetails", + "when": "false" + }, { "command": "gitlens.diffWithRevisionFrom", "when": "resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.diffWithRevisionFrom:commitDetails", + "when": "false" + }, + { + "command": "gitlens.diffWithRevisionFrom:graphDetails", + "when": "false" + }, { "command": "gitlens.diffWithWorking", "when": "gitlens:enabled && resourceScheme =~ /^(gitlens|git|pr)$/" @@ -11411,6 +11779,14 @@ "command": "gitlens.externalDiff", "when": "!gitlens:hasVirtualFolders && resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.externalDiff:commitDetails", + "when": "false" + }, + { + "command": "gitlens.externalDiff:graphDetails", + "when": "false" + }, { "command": "gitlens.externalDiffAll", "when": "gitlens:enabled && !gitlens:hasVirtualFolders" @@ -12047,10 +12423,26 @@ "command": "gitlens.openFileHistory", "when": "resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.openFileHistory:commitDetails", + "when": "false" + }, + { + "command": "gitlens.openFileHistory:graphDetails", + "when": "false" + }, { "command": "gitlens.openFileOnRemote", "when": "gitlens:repos:withRemotes" }, + { + "command": "gitlens.openFileOnRemote:commitDetails", + "when": "false" + }, + { + "command": "gitlens.openFileOnRemote:graphDetails", + "when": "false" + }, { "command": "gitlens.openFileOnRemoteFrom", "when": "gitlens:repos:withRemotes" @@ -12167,14 +12559,38 @@ "command": "gitlens.quickOpenFileHistory", "when": "resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.quickOpenFileHistory:commitDetails", + "when": "false" + }, + { + "command": "gitlens.quickOpenFileHistory:graphDetails", + "when": "false" + }, { "command": "gitlens.regenerateMarkdownDocument", "when": "false" }, + { + "command": "gitlens.restore.file:commitDetails", + "when": "false" + }, + { + "command": "gitlens.restore.file:graphDetails", + "when": "false" + }, { "command": "gitlens.restore.file:views", "when": "false" }, + { + "command": "gitlens.restorePrevious.file:commitDetails", + "when": "false" + }, + { + "command": "gitlens.restorePrevious.file:graphDetails", + "when": "false" + }, { "command": "gitlens.restorePrevious.file:views", "when": "false" @@ -12195,6 +12611,14 @@ "command": "gitlens.shareAsCloudPatch", "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled" }, + { + "command": "gitlens.shareAsCloudPatch:commitDetails", + "when": "false" + }, + { + "command": "gitlens.shareAsCloudPatch:graphDetails", + "when": "false" + }, { "command": "gitlens.showBranchesView", "when": "gitlens:enabled" @@ -12623,6 +13047,14 @@ "command": "gitlens.views.applyChanges", "when": "false" }, + { + "command": "gitlens.views.applyChanges:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.applyChanges:graphDetails", + "when": "false" + }, { "command": "gitlens.views.associateIssueWithBranch", "when": "false" @@ -12835,6 +13267,14 @@ "command": "gitlens.views.compareFileWithSelected", "when": "false" }, + { + "command": "gitlens.views.compareFileWithSelected:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.compareFileWithSelected:graphDetails", + "when": "false" + }, { "command": "gitlens.views.compareWithHead", "when": "false" @@ -12923,6 +13363,14 @@ "command": "gitlens.views.copy", "when": "false" }, + { + "command": "gitlens.views.copy:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.copy:graphDetails", + "when": "false" + }, { "command": "gitlens.views.copyAsMarkdown", "when": "false" @@ -12931,6 +13379,14 @@ "command": "gitlens.views.copyRemoteCommitUrl", "when": "false" }, + { + "command": "gitlens.views.copyRemoteCommitUrl:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.copyRemoteCommitUrl:graphDetails", + "when": "false" + }, { "command": "gitlens.views.copyRemoteCommitUrl.multi", "when": "false" @@ -13127,10 +13583,26 @@ "command": "gitlens.views.highlightChanges", "when": "false" }, + { + "command": "gitlens.views.highlightChanges:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.highlightChanges:graphDetails", + "when": "false" + }, { "command": "gitlens.views.highlightRevisionChanges", "when": "false" }, + { + "command": "gitlens.views.highlightRevisionChanges:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.highlightRevisionChanges:graphDetails", + "when": "false" + }, { "command": "gitlens.views.home.disablePreview", "when": "false" @@ -13247,6 +13719,14 @@ "command": "gitlens.views.mergeChangesWithWorking", "when": "false" }, + { + "command": "gitlens.views.mergeChangesWithWorking:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.mergeChangesWithWorking:graphDetails", + "when": "false" + }, { "command": "gitlens.views.openBranchOnRemote", "when": "false" @@ -13287,6 +13767,14 @@ "command": "gitlens.views.openChanges", "when": "false" }, + { + "command": "gitlens.views.openChanges:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.openChanges:graphDetails", + "when": "false" + }, { "command": "gitlens.views.openChangesWithMergeBase", "when": "false" @@ -13295,28 +13783,52 @@ "command": "gitlens.views.openChangesWithWorking", "when": "false" }, + { + "command": "gitlens.views.openChangesWithWorking:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.openChangesWithWorking:graphDetails", + "when": "false" + }, { "command": "gitlens.views.openCommitOnRemote", "when": "false" }, { - "command": "gitlens.views.openCommitOnRemote.multi", + "command": "gitlens.views.openCommitOnRemote.multi", + "when": "false" + }, + { + "command": "gitlens.views.openDirectoryDiff", + "when": "false" + }, + { + "command": "gitlens.views.openDirectoryDiffWithWorking", + "when": "false" + }, + { + "command": "gitlens.views.openFile", + "when": "false" + }, + { + "command": "gitlens.views.openFile:commitDetails", "when": "false" }, { - "command": "gitlens.views.openDirectoryDiff", + "command": "gitlens.views.openFile:graphDetails", "when": "false" }, { - "command": "gitlens.views.openDirectoryDiffWithWorking", + "command": "gitlens.views.openFileRevision", "when": "false" }, { - "command": "gitlens.views.openFile", + "command": "gitlens.views.openFileRevision:commitDetails", "when": "false" }, { - "command": "gitlens.views.openFileRevision", + "command": "gitlens.views.openFileRevision:graphDetails", "when": "false" }, { @@ -13343,6 +13855,14 @@ "command": "gitlens.views.openPreviousChangesWithWorking", "when": "false" }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:graphDetails", + "when": "false" + }, { "command": "gitlens.views.openPullRequest", "when": "false" @@ -14023,6 +14543,14 @@ "command": "gitlens.views.selectFileForCompare", "when": "false" }, + { + "command": "gitlens.views.selectFileForCompare:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.selectFileForCompare:graphDetails", + "when": "false" + }, { "command": "gitlens.views.selectForCompare", "when": "false" @@ -14087,6 +14615,14 @@ "command": "gitlens.views.stageFile", "when": "false" }, + { + "command": "gitlens.views.stageFile:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.stageFile:graphDetails", + "when": "false" + }, { "command": "gitlens.views.stashes.attach", "when": "false" @@ -14207,6 +14743,14 @@ "command": "gitlens.views.unstageFile", "when": "false" }, + { + "command": "gitlens.views.unstageFile:commitDetails", + "when": "false" + }, + { + "command": "gitlens.views.unstageFile:graphDetails", + "when": "false" + }, { "command": "gitlens.views.workspaces.addRepos", "when": "false" @@ -14351,6 +14895,10 @@ "command": "gitlens.visualizeHistory.file", "when": "gitlens:enabled && resource in gitlens:tabs:tracked" }, + { + "command": "gitlens.visualizeHistory.file:commitDetails", + "when": "false" + }, { "command": "gitlens.visualizeHistory.file:editor", "when": "false" @@ -14359,6 +14907,10 @@ "command": "gitlens.visualizeHistory.file:explorer", "when": "false" }, + { + "command": "gitlens.visualizeHistory.file:graphDetails", + "when": "false" + }, { "command": "gitlens.visualizeHistory.file:scm", "when": "false" @@ -14835,16 +15387,18 @@ }, { "command": "gitlens.diffWithRevision", + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens@3" }, { "command": "gitlens.diffWithRevisionFrom", + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens@4" }, { "command": "gitlens.externalDiff", "when": "viewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders", - "group": "1_gitlens_@1" + "group": "1_gitlens_@5" }, { "command": "gitlens.views.highlightChanges", @@ -14860,6 +15414,76 @@ "command": "gitlens.views.openChangesWithMergeBase", "when": "viewItem =~ /gitlens:file:results\\b/", "group": "1_gitlens@2" + }, + { + "command": "gitlens.views.openChangesWithWorking:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@1" + }, + { + "command": "gitlens.views.openChangesWithWorking:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@1" + }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@2" + }, + { + "command": "gitlens.views.openPreviousChangesWithWorking:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@2" + }, + { + "command": "gitlens.diffWithRevision:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@3" + }, + { + "command": "gitlens.diffWithRevision:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@3" + }, + { + "command": "gitlens.diffWithRevisionFrom:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@4" + }, + { + "command": "gitlens.diffWithRevisionFrom:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@4" + }, + { + "command": "gitlens.externalDiff:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_@5" + }, + { + "command": "gitlens.externalDiff:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_@5" + }, + { + "command": "gitlens.views.highlightChanges:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens@1" + }, + { + "command": "gitlens.views.highlightChanges:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens@1" + }, + { + "command": "gitlens.views.highlightRevisionChanges:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens@2" + }, + { + "command": "gitlens.views.highlightRevisionChanges:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens@2" } ], "gitlens/commit/file/commit": [ @@ -14953,15 +15577,47 @@ "gitlens/commit/file/history": [ { "command": "gitlens.openFileHistory", - "when": "view != gitlens.views.fileHistory/", + "when": "viewItem =~ /gitlens:file\\b/ && view != gitlens.views.fileHistory/", "group": "1_gitlens@1" }, { "command": "gitlens.visualizeHistory.file:views", + "when": "viewItem =~ /gitlens:file\\b/", "group": "1_gitlens@2" }, { "command": "gitlens.quickOpenFileHistory", + "when": "viewItem =~ /gitlens:file\\b/", + "group": "1_gitlens_quick@1" + }, + { + "command": "gitlens.openFileHistory:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@1" + }, + { + "command": "gitlens.openFileHistory:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@1" + }, + { + "command": "gitlens.visualizeHistory.file:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens@2" + }, + { + "command": "gitlens.visualizeHistory.file:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens@2" + }, + { + "command": "gitlens.quickOpenFileHistory:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_quick@1" + }, + { + "command": "gitlens.quickOpenFileHistory:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", "group": "1_gitlens_quick@1" } ], @@ -15544,12 +16200,12 @@ }, { "command": "gitlens.copyDeepLinkToCommit", - "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))/ && !listMultiSelection", + "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))\\b/ && !listMultiSelection", "group": "1_gitlens@25" }, { "command": "gitlens.views.copyRemoteCommitUrl", - "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))/ && !listMultiSelection && gitlens:repos:withRemotes", + "when": "viewItem =~ /gitlens:(commit|file\\b(?=.*?\\b\\+committed\\b))\\b/ && !listMultiSelection && gitlens:repos:withRemotes", "group": "2_gitlens@25" }, { @@ -15632,6 +16288,76 @@ "when": "webviewItem =~ /gitlens:commit\\b/ && !listMultiSelection && gitlens:repos:withRemotes", "group": "2_gitlens@25" }, + { + "command": "gitlens.shareAsCloudPatch:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webview == gitlens.views.commitDetails", + "group": "1_a_gitlens@1" + }, + { + "command": "gitlens.shareAsCloudPatch:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webview == gitlens.views.graphDetails", + "group": "1_a_gitlens@1" + }, + { + "command": "gitlens.copyDeepLinkToCommit:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && webview == gitlens.views.commitDetails", + "group": "1_gitlens@25" + }, + { + "command": "gitlens.copyDeepLinkToCommit:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && webview == gitlens.views.graphDetails", + "group": "1_gitlens@25" + }, + { + "command": "gitlens.copyDeepLinkToFile:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "1_gitlens@26" + }, + { + "command": "gitlens.copyDeepLinkToFile:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "1_gitlens@26" + }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "1_gitlens@27" + }, + { + "command": "gitlens.copyDeepLinkToFileAtRevision:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "1_gitlens@27" + }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens@1" + }, + { + "command": "gitlens.copyRemoteFileUrlWithoutRange:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens@1" + }, + { + "command": "gitlens.copyRemoteFileUrlFrom:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens@2" + }, + { + "command": "gitlens.copyRemoteFileUrlFrom:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens@2" + }, + { + "command": "gitlens.views.copyRemoteCommitUrl:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens@25" + }, + { + "command": "gitlens.views.copyRemoteCommitUrl:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)\\b/ && !listMultiSelection && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens@25" + }, { "command": "gitlens.graph.copyDeepLinkToTag", "when": "webviewItem =~ /gitlens:tag\\b/ && !listMultiSelection", @@ -17443,7 +18169,7 @@ }, { "submenu": "gitlens/commit/browse", - "when": "viewItem =~ /gitlens:(branch|commit|file\\b(?=.*?\\b\\+committed\\b)|stash|tag)\\b/ && !listMultiSelection && !gitlens:hasVirtualFolders", + "when": "viewItem =~ /gitlens:(branch|commit|stash|tag)\\b/ && !listMultiSelection && !gitlens:hasVirtualFolders", "group": "3_gitlens_explore@100" }, { @@ -23325,7 +24051,7 @@ }, { "submenu": "gitlens/share", - "when": "webviewItem =~ /gitlens:(branch|commit|stash|tag)\\b/", + "when": "webviewItem =~ /gitlens:(branch|commit|stash|tag|file\\b(?=.*?\\b\\+(committed|staged|unstaged)\\b))\\b/", "group": "7_gitlens_a_share@1" }, { @@ -23463,6 +24189,201 @@ "when": "webviewItem =~ /gitlens:contributor\\b(?!.*?\\b\\+current\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders", "group": "1_gitlens_actions@2" }, + { + "command": "gitlens.views.applyChanges:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions@1" + }, + { + "command": "gitlens.views.applyChanges:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions@1" + }, + { + "command": "gitlens.views.stageFile:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+unstaged\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions@1" + }, + { + "command": "gitlens.views.stageFile:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+unstaged\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions@1" + }, + { + "command": "gitlens.views.mergeChangesWithWorking:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions@2" + }, + { + "command": "gitlens.views.mergeChangesWithWorking:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions@2" + }, + { + "command": "gitlens.views.unstageFile:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+staged\\b)/ && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions@2" + }, + { + "command": "gitlens.views.unstageFile:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+staged\\b)/ && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions@2" + }, + { + "command": "gitlens.restore.file:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "1_gitlens_actions@3" + }, + { + "command": "gitlens.restore.file:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "1_gitlens_actions@3" + }, + { + "command": "gitlens.views.openChanges:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen@1" + }, + { + "command": "gitlens.views.openChanges:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen@1" + }, + { + "submenu": "gitlens/commit/file/changes", + "when": "webviewItem =~ /gitlens:file\\b/", + "group": "2_gitlens_quickopen@2" + }, + { + "command": "gitlens.views.openFile:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file@3" + }, + { + "command": "gitlens.views.openFile:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file@3" + }, + { + "command": "gitlens.views.openFileRevision:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file@4" + }, + { + "command": "gitlens.views.openFileRevision:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file@4" + }, + { + "command": "gitlens.openFileOnRemote:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && gitlens:repos:withRemotes && webview == gitlens.views.commitDetails", + "group": "2_gitlens_quickopen_file@5" + }, + { + "command": "gitlens.openFileOnRemote:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && gitlens:repos:withRemotes && webview == gitlens.views.graphDetails", + "group": "2_gitlens_quickopen_file@5" + }, + { + "submenu": "gitlens/commit/file/history", + "when": "webviewItem =~ /gitlens:file\\b/", + "group": "3_gitlens_explore@2" + }, + { + "command": "gitlens.views.compareFileWithSelected:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && !listMultiSelection && gitlens:views:canCompare:file && webview == gitlens.views.commitDetails", + "group": "4_gitlens_compare@99" + }, + { + "command": "gitlens.views.compareFileWithSelected:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && !listMultiSelection && gitlens:views:canCompare:file && webview == gitlens.views.graphDetails", + "group": "4_gitlens_compare@99" + }, + { + "command": "gitlens.views.selectFileForCompare:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && webview == gitlens.views.commitDetails", + "group": "4_gitlens_compare@99" + }, + { + "command": "gitlens.views.selectFileForCompare:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+conflicted\\b)/ && webview == gitlens.views.graphDetails", + "group": "4_gitlens_compare@99" + }, + { + "command": "gitlens.views.copy:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+(staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste@1" + }, + { + "command": "gitlens.views.copy:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?!.*?\\b\\+(staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste@1" + }, + { + "command": "gitlens.copyRelativePathToClipboard:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste@2" + }, + { + "command": "gitlens.copyRelativePathToClipboard:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b/ && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste@2" + }, + { + "command": "gitlens.copyPatchToClipboard:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "7_gitlens_cutcopypaste@3" + }, + { + "command": "gitlens.copyPatchToClipboard:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "7_gitlens_cutcopypaste@3" + }, + { + "submenu": "gitlens/commit/copy", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/", + "group": "7_gitlens_cutcopypaste@10" + }, + { + "command": "gitlens.views.applyChanges:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions@1" + }, + { + "command": "gitlens.views.applyChanges:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions@1" + }, + { + "command": "gitlens.views.mergeChangesWithWorking:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions@2" + }, + { + "command": "gitlens.views.mergeChangesWithWorking:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions@2" + }, + { + "command": "gitlens.restore.file:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions@3" + }, + { + "command": "gitlens.restore.file:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions@3" + }, + { + "command": "gitlens.restorePrevious.file:commitDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.commitDetails", + "group": "8_gitlens_actions@4" + }, + { + "command": "gitlens.restorePrevious.file:graphDetails", + "when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && webview == gitlens.views.graphDetails", + "group": "8_gitlens_actions@4" + }, { "submenu": "gitlens/graph/markers", "when": "webviewItem =~ /gitlens:graph:(columns|settings)\\b/", diff --git a/src/constants.commands.generated.ts b/src/constants.commands.generated.ts index 5361baf30bdc6..3523419777cff 100644 --- a/src/constants.commands.generated.ts +++ b/src/constants.commands.generated.ts @@ -40,25 +40,39 @@ export type ContributedCommands = | 'gitlens.connectRemoteProvider' | 'gitlens.copyDeepLinkToBranch' | 'gitlens.copyDeepLinkToCommit' + | 'gitlens.copyDeepLinkToCommit:commitDetails' + | 'gitlens.copyDeepLinkToCommit:graphDetails' | 'gitlens.copyDeepLinkToComparison' | 'gitlens.copyDeepLinkToFile' + | 'gitlens.copyDeepLinkToFile:commitDetails' + | 'gitlens.copyDeepLinkToFile:graphDetails' | 'gitlens.copyDeepLinkToFileAtRevision' + | 'gitlens.copyDeepLinkToFileAtRevision:commitDetails' + | 'gitlens.copyDeepLinkToFileAtRevision:graphDetails' | 'gitlens.copyDeepLinkToLines' | 'gitlens.copyDeepLinkToRepo' | 'gitlens.copyDeepLinkToTag' | 'gitlens.copyDeepLinkToWorkspace' | 'gitlens.copyMessageToClipboard' + | 'gitlens.copyPatchToClipboard:commitDetails' | 'gitlens.copyPatchToClipboard:graph' + | 'gitlens.copyPatchToClipboard:graphDetails' | 'gitlens.copyPatchToClipboard:scm' | 'gitlens.copyPatchToClipboard:views' | 'gitlens.copyRelativePathToClipboard' + | 'gitlens.copyRelativePathToClipboard:commitDetails' + | 'gitlens.copyRelativePathToClipboard:graphDetails' | 'gitlens.copyRemoteBranchUrl' | 'gitlens.copyRemoteBranchesUrl' | 'gitlens.copyRemoteCommitUrl' | 'gitlens.copyRemoteComparisonUrl' | 'gitlens.copyRemoteFileUrlFrom' + | 'gitlens.copyRemoteFileUrlFrom:commitDetails' + | 'gitlens.copyRemoteFileUrlFrom:graphDetails' | 'gitlens.copyRemoteFileUrlToClipboard' | 'gitlens.copyRemoteFileUrlWithoutRange' + | 'gitlens.copyRemoteFileUrlWithoutRange:commitDetails' + | 'gitlens.copyRemoteFileUrlWithoutRange:graphDetails' | 'gitlens.copyRemotePullRequestUrl' | 'gitlens.copyRemoteRepositoryUrl' | 'gitlens.copyShaToClipboard' @@ -76,11 +90,17 @@ export type ContributedCommands = | 'gitlens.diffWithPrevious:editor/title' | 'gitlens.diffWithPrevious:explorer' | 'gitlens.diffWithRevision' + | 'gitlens.diffWithRevision:commitDetails' + | 'gitlens.diffWithRevision:graphDetails' | 'gitlens.diffWithRevisionFrom' + | 'gitlens.diffWithRevisionFrom:commitDetails' + | 'gitlens.diffWithRevisionFrom:graphDetails' | 'gitlens.diffWithWorking:editor' | 'gitlens.diffWithWorking:editor/title' | 'gitlens.disconnectRemoteProvider' | 'gitlens.externalDiff' + | 'gitlens.externalDiff:commitDetails' + | 'gitlens.externalDiff:graphDetails' | 'gitlens.externalDiffAll' | 'gitlens.fetchRepositories' | 'gitlens.getStarted' @@ -198,7 +218,11 @@ export type ContributedCommands = | 'gitlens.openCommitOnRemote' | 'gitlens.openComparisonOnRemote' | 'gitlens.openFileHistory' + | 'gitlens.openFileHistory:commitDetails' + | 'gitlens.openFileHistory:graphDetails' | 'gitlens.openFileOnRemote' + | 'gitlens.openFileOnRemote:commitDetails' + | 'gitlens.openFileOnRemote:graphDetails' | 'gitlens.openFileOnRemoteFrom' | 'gitlens.openFolderHistory' | 'gitlens.openOnlyChangedFiles' @@ -212,13 +236,21 @@ export type ContributedCommands = | 'gitlens.pullRepositories' | 'gitlens.pushRepositories' | 'gitlens.quickOpenFileHistory' + | 'gitlens.quickOpenFileHistory:commitDetails' + | 'gitlens.quickOpenFileHistory:graphDetails' | 'gitlens.regenerateMarkdownDocument' + | 'gitlens.restore.file:commitDetails' + | 'gitlens.restore.file:graphDetails' | 'gitlens.restore.file:views' + | 'gitlens.restorePrevious.file:commitDetails' + | 'gitlens.restorePrevious.file:graphDetails' | 'gitlens.restorePrevious.file:views' | 'gitlens.revealCommitInView' | 'gitlens.setUpstream:graph' | 'gitlens.setUpstream:views' | 'gitlens.shareAsCloudPatch' + | 'gitlens.shareAsCloudPatch:commitDetails' + | 'gitlens.shareAsCloudPatch:graphDetails' | 'gitlens.showCommitSearch' | 'gitlens.showCommitsInView' | 'gitlens.showGraph' @@ -287,6 +319,8 @@ export type ContributedCommands = | 'gitlens.views.addAuthors' | 'gitlens.views.addRemote' | 'gitlens.views.applyChanges' + | 'gitlens.views.applyChanges:commitDetails' + | 'gitlens.views.applyChanges:graphDetails' | 'gitlens.views.associateIssueWithBranch' | 'gitlens.views.branches.attach' | 'gitlens.views.branches.refresh' @@ -338,6 +372,8 @@ export type ContributedCommands = | 'gitlens.views.compareAncestryWithWorking' | 'gitlens.views.compareBranchWithHead' | 'gitlens.views.compareFileWithSelected' + | 'gitlens.views.compareFileWithSelected:commitDetails' + | 'gitlens.views.compareFileWithSelected:graphDetails' | 'gitlens.views.compareWithHead' | 'gitlens.views.compareWithMergeBase' | 'gitlens.views.compareWithSelected' @@ -359,9 +395,13 @@ export type ContributedCommands = | 'gitlens.views.contributors.setShowStatisticsOn' | 'gitlens.views.contributors.viewOptionsTitle' | 'gitlens.views.copy' + | 'gitlens.views.copy:commitDetails' + | 'gitlens.views.copy:graphDetails' | 'gitlens.views.copyAsMarkdown' | 'gitlens.views.copyRemoteCommitUrl' | 'gitlens.views.copyRemoteCommitUrl.multi' + | 'gitlens.views.copyRemoteCommitUrl:commitDetails' + | 'gitlens.views.copyRemoteCommitUrl:graphDetails' | 'gitlens.views.copyUrl' | 'gitlens.views.copyUrl.multi' | 'gitlens.views.createBranch' @@ -408,7 +448,11 @@ export type ContributedCommands = | 'gitlens.views.graph.refresh' | 'gitlens.views.graphDetails.refresh' | 'gitlens.views.highlightChanges' + | 'gitlens.views.highlightChanges:commitDetails' + | 'gitlens.views.highlightChanges:graphDetails' | 'gitlens.views.highlightRevisionChanges' + | 'gitlens.views.highlightRevisionChanges:commitDetails' + | 'gitlens.views.highlightRevisionChanges:graphDetails' | 'gitlens.views.home.disablePreview' | 'gitlens.views.home.discussions' | 'gitlens.views.home.enablePreview' @@ -436,6 +480,8 @@ export type ContributedCommands = | 'gitlens.views.loadAllChildren' | 'gitlens.views.mergeBranchInto' | 'gitlens.views.mergeChangesWithWorking' + | 'gitlens.views.mergeChangesWithWorking:commitDetails' + | 'gitlens.views.mergeChangesWithWorking:graphDetails' | 'gitlens.views.openBranchOnRemote' | 'gitlens.views.openBranchOnRemote.multi' | 'gitlens.views.openChangedFileDiffs' @@ -446,20 +492,30 @@ export type ContributedCommands = | 'gitlens.views.openChangedFileRevisions' | 'gitlens.views.openChangedFiles' | 'gitlens.views.openChanges' + | 'gitlens.views.openChanges:commitDetails' + | 'gitlens.views.openChanges:graphDetails' | 'gitlens.views.openChangesWithMergeBase' | 'gitlens.views.openChangesWithWorking' + | 'gitlens.views.openChangesWithWorking:commitDetails' + | 'gitlens.views.openChangesWithWorking:graphDetails' | 'gitlens.views.openCommitOnRemote' | 'gitlens.views.openCommitOnRemote.multi' | 'gitlens.views.openDirectoryDiff' | 'gitlens.views.openDirectoryDiffWithWorking' | 'gitlens.views.openFile' + | 'gitlens.views.openFile:commitDetails' + | 'gitlens.views.openFile:graphDetails' | 'gitlens.views.openFileRevision' + | 'gitlens.views.openFileRevision:commitDetails' + | 'gitlens.views.openFileRevision:graphDetails' | 'gitlens.views.openInIntegratedTerminal' | 'gitlens.views.openInTerminal' | 'gitlens.views.openInWorktree' | 'gitlens.views.openOnlyChangedFiles' | 'gitlens.views.openPausedOperationInRebaseEditor' | 'gitlens.views.openPreviousChangesWithWorking' + | 'gitlens.views.openPreviousChangesWithWorking:commitDetails' + | 'gitlens.views.openPreviousChangesWithWorking:graphDetails' | 'gitlens.views.openPullRequest' | 'gitlens.views.openPullRequestChanges' | 'gitlens.views.openPullRequestComparison' @@ -626,6 +682,8 @@ export type ContributedCommands = | 'gitlens.views.searchAndCompare.swapComparison' | 'gitlens.views.searchAndCompare.viewOptionsTitle' | 'gitlens.views.selectFileForCompare' + | 'gitlens.views.selectFileForCompare:commitDetails' + | 'gitlens.views.selectFileForCompare:graphDetails' | 'gitlens.views.selectForCompare' | 'gitlens.views.setAsDefault' | 'gitlens.views.setBranchComparisonToBranch' @@ -642,6 +700,8 @@ export type ContributedCommands = | 'gitlens.views.skipPausedOperation' | 'gitlens.views.stageDirectory' | 'gitlens.views.stageFile' + | 'gitlens.views.stageFile:commitDetails' + | 'gitlens.views.stageFile:graphDetails' | 'gitlens.views.stashes.attach' | 'gitlens.views.stashes.refresh' | 'gitlens.views.stashes.setFilesLayoutToAuto' @@ -670,6 +730,8 @@ export type ContributedCommands = | 'gitlens.views.unsetAsDefault' | 'gitlens.views.unstageDirectory' | 'gitlens.views.unstageFile' + | 'gitlens.views.unstageFile:commitDetails' + | 'gitlens.views.unstageFile:graphDetails' | 'gitlens.views.workspaces.addRepos' | 'gitlens.views.workspaces.addReposFromLinked' | 'gitlens.views.workspaces.changeAutoAddSetting' @@ -703,8 +765,10 @@ export type ContributedCommands = | 'gitlens.views.worktrees.setShowStashesOff' | 'gitlens.views.worktrees.setShowStashesOn' | 'gitlens.views.worktrees.viewOptionsTitle' + | 'gitlens.visualizeHistory.file:commitDetails' | 'gitlens.visualizeHistory.file:editor' | 'gitlens.visualizeHistory.file:explorer' + | 'gitlens.visualizeHistory.file:graphDetails' | 'gitlens.visualizeHistory.file:scm' | 'gitlens.visualizeHistory.file:views' | 'gitlens.visualizeHistory.folder:explorer' diff --git a/src/constants.commands.ts b/src/constants.commands.ts index b1690a15b12ce..70e9ca263662b 100644 --- a/src/constants.commands.ts +++ b/src/constants.commands.ts @@ -245,9 +245,32 @@ export type TreeViewCommandSuffixesByViewType = Extract TreeViewCommandsByViewType >; -export type WebviewCommands = - | FilterCommands<`gitlens.${WebviewTypes}`, GlCommands> - | FilterCommands<'gitlens.', GlCommands, `:${WebviewTypes}`>; -export type WebviewViewCommands = - | FilterCommands<`gitlens.views.${WebviewViewTypes}`, GlCommands> - | FilterCommands<'gitlens.views.', GlCommands, `:${WebviewViewTypes}`>; +export type WebviewCommands = + | FilterCommands<`gitlens.${T}`, GlCommands> + | FilterCommands<'gitlens.', GlCommands, `:${T}`>; +export type WebviewViewCommands = + | FilterCommands<`gitlens.views.${T}`, GlCommands> + | FilterCommands<'gitlens.views.', GlCommands, `:${T}`> + | FilterCommands<'gitlens.', GlCommands, `:${T}`>; + +/** + * Extracts all possible prefixes (before the colon) from a union of commands. + * Example: 'gitlens.foo:graph' | 'gitlens.bar:timeline' -> 'gitlens.foo' | 'gitlens.bar' + */ +type ExtractCommandPrefix< + T extends GlCommands, + U extends WebviewTypes | WebviewViewTypes, +> = T extends `${infer Prefix}:${U}` ? `${Prefix}:` : never; + +type WebviewCommandPrefixes = ExtractCommandPrefix, T>; +export type WebviewCommandsOrCommandsWithSuffix = + | WebviewCommands + | WebviewCommandPrefixes; + +type WebviewViewCommandPrefixes = ExtractCommandPrefix< + WebviewViewCommands, + T +>; +export type WebviewViewCommandsOrCommandsWithSuffix = + | WebviewViewCommands + | WebviewViewCommandPrefixes; diff --git a/src/constants.context.ts b/src/constants.context.ts index 9bbf188f2b7a7..fc5291618df9e 100644 --- a/src/constants.context.ts +++ b/src/constants.context.ts @@ -9,6 +9,12 @@ import type { OrgAIProviders } from './plus/gk/models/organization'; import type { PromoKeys } from './plus/gk/models/promo'; import type { SubscriptionPlanIds } from './plus/gk/models/subscription'; +interface CompareSelectedFileInfo { + ref: string; + repoPath: string | undefined; + uri: Uri; +} + export type ContextKeys = { 'gitlens:debugging': boolean; 'gitlens:disabled': boolean; @@ -49,7 +55,7 @@ export type ContextKeys = { 'gitlens:tabs:tracked': Uri[]; 'gitlens:untrusted': boolean; 'gitlens:views:canCompare': boolean; - 'gitlens:views:canCompare:file': boolean; + 'gitlens:views:canCompare:file': CompareSelectedFileInfo; 'gitlens:views:commits:filtered': boolean; 'gitlens:views:commits:hideMergeCommits': boolean; 'gitlens:views:contributors:hideMergeCommits': boolean; diff --git a/src/constants.views.ts b/src/constants.views.ts index 806942df0f542..9a32dd2be6851 100644 --- a/src/constants.views.ts +++ b/src/constants.views.ts @@ -43,6 +43,22 @@ export type WebviewIds = `gitlens.${WebviewTypes}`; export type WebviewViewTypes = 'commitDetails' | 'graph' | 'graphDetails' | 'home' | 'patchDetails' | 'timeline'; export type WebviewViewIds = `gitlens.views.${T}`; +export type WebviewTypeFromId = T extends `gitlens.${infer U}` + ? U extends WebviewTypes + ? U + : never + : never; +export type WebviewViewTypeFromId = T extends `gitlens.views.${infer U}` + ? U extends WebviewViewTypes + ? U + : never + : never; +export type WebviewOrWebviewViewTypeFromId = T extends WebviewIds + ? WebviewTypeFromId + : T extends WebviewViewIds + ? WebviewViewTypeFromId + : never; + export type ViewTypes = TreeViewTypes | WebviewViewTypes; export type ViewIds = TreeViewIds | WebviewViewIds; diff --git a/src/env/node/gk/cli/commands.ts b/src/env/node/gk/cli/commands.ts index 36b7a429d4757..6690a2dbdb1e8 100644 --- a/src/env/node/gk/cli/commands.ts +++ b/src/env/node/gk/cli/commands.ts @@ -8,9 +8,10 @@ import { executeCommand } from '../../../../system/-webview/command'; import { createCommandDecorator } from '../../../../system/decorators/command'; import type { CliCommandRequest, CliCommandResponse, CliIpcServer } from './integration'; +type CliCommand = 'cherry-pick' | 'compare' | 'graph' | 'merge' | 'rebase'; type CliCommandHandler = (request: CliCommandRequest, repo?: Repository | undefined) => Promise; -const { command, getCommands } = createCommandDecorator(); +const { command, getCommands } = createCommandDecorator(); export class CliCommandHandlers implements Disposable { constructor( diff --git a/src/system/decorators/command.ts b/src/system/decorators/command.ts index eddc339feffcd..8b145ca983799 100644 --- a/src/system/decorators/command.ts +++ b/src/system/decorators/command.ts @@ -1,6 +1,15 @@ +import type { + GlCommands, + WebviewCommands, + WebviewCommandsOrCommandsWithSuffix, + WebviewViewCommands, + WebviewViewCommandsOrCommandsWithSuffix, +} from '../../constants.commands'; +import type { WebviewTypes, WebviewViewTypes } from '../../constants.views'; + interface Command< - THandler extends (...args: any[]) => any, - TCommand extends string = string, + TCommand extends string | GlCommands = GlCommands, + THandler extends (...args: any[]) => any = (...args: any[]) => any, TOptions extends object | void = void, > { command: TCommand; @@ -9,8 +18,8 @@ interface Command< } export function createCommandDecorator< + TCommand extends string | GlCommands = GlCommands, THandler extends (...args: any[]) => any = (...args: any[]) => any, - TCommand extends string = string, TOptions extends object | void = void, >(): { command: ( @@ -21,9 +30,9 @@ export function createCommandDecorator< contextOrKey?: string | ClassMethodDecoratorContext, descriptor?: PropertyDescriptor, ) => PropertyDescriptor | undefined; - getCommands: () => Iterable>; + getCommands: () => Iterable>; } { - const commands = new Map>(); + const commands = new Map>(); function command(command: TCommand, options?: TOptions) { return function ( @@ -66,3 +75,19 @@ export function createCommandDecorator< getCommands: () => commands.values(), }; } + +export function getWebviewCommand( + command: WebviewCommandsOrCommandsWithSuffix, + type: T, +): WebviewCommands { + return command.endsWith(':') ? (`${command}${type}` as WebviewCommands) : (command as WebviewCommands); +} + +export function getWebviewViewCommand( + command: WebviewViewCommandsOrCommandsWithSuffix, + type: T, +): WebviewViewCommands { + return command.endsWith(':') + ? (`${command}${type}` as WebviewViewCommands) + : (command as WebviewViewCommands); +} diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index f67a4841faf0f..cd9f7dfff1627 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -51,7 +51,7 @@ import { registerCommand, } from '../system/-webview/command'; import { configuration } from '../system/-webview/configuration'; -import { setContext } from '../system/-webview/context'; +import { getContext, setContext } from '../system/-webview/context'; import { revealInFileExplorer } from '../system/-webview/vscode'; import type { MergeEditorInputs } from '../system/-webview/vscode/editors'; import { editorLineToDiffRange, openMergeEditor } from '../system/-webview/vscode/editors'; @@ -111,8 +111,8 @@ import type { WorktreeNode } from './nodes/worktreeNode'; import type { WorktreesNode } from './nodes/worktreesNode'; const { command, getCommands } = createCommandDecorator< - (...args: any[]) => unknown, GlCommands, + (...args: any[]) => unknown, { multiselect?: boolean | 'sequential'; args?: (...args: unknown[]) => unknown[]; @@ -1318,36 +1318,31 @@ export class ViewCommands implements Disposable { @command('gitlens.views.compareFileWithSelected') @log() private compareFileWithSelected(node: ViewRefFileNode) { - if (this._selectedFile == null || !(node instanceof ViewRefFileNode) || node.ref == null) { + const selectedFile = getContext('gitlens:views:canCompare:file'); + if (selectedFile == null || !(node instanceof ViewRefFileNode) || node.ref == null) { return Promise.resolve(); } - if (this._selectedFile.repoPath !== node.repoPath) { + void setContext('gitlens:views:canCompare:file', undefined); + + if (selectedFile.repoPath !== node.repoPath) { this.selectFileForCompare(node); return Promise.resolve(); } - const selected = this._selectedFile; - - this._selectedFile = undefined; - void setContext('gitlens:views:canCompare:file', false); - - return this.compareFileWith(selected.repoPath!, selected.uri!, selected.ref, node.uri, node.ref.ref); + return this.compareFileWith(selectedFile.repoPath, selectedFile.uri, selectedFile.ref, node.uri, node.ref.ref); } - private _selectedFile: CompareSelectedInfo | undefined; - @command('gitlens.views.selectFileForCompare') @log() private selectFileForCompare(node: ViewRefFileNode) { if (!(node instanceof ViewRefFileNode) || node.ref == null) return; - this._selectedFile = { + void setContext('gitlens:views:canCompare:file', { ref: node.ref.ref, repoPath: node.repoPath, uri: node.uri, - }; - void setContext('gitlens:views:canCompare:file', true); + }); } @command('gitlens.views.openChangedFileDiffs', { args: (n, o) => [n, o] }) @@ -1830,12 +1825,6 @@ export class ViewCommands implements Disposable { } } -interface CompareSelectedInfo { - ref: string; - repoPath: string | undefined; - uri?: Uri; -} - export function registerViewCommand( command: GlCommands, callback: (...args: any[]) => unknown, diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index 612ecbcc1575c..611b4b28acba8 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -8,7 +8,8 @@ import type { IssueOrPullRequest } from '../../../../git/models/issueOrPullReque import type { PullRequestShape } from '../../../../git/models/pullRequest'; import { createCommandLink } from '../../../../system/commands'; import type { IpcSerialized } from '../../../../system/ipcSerialize'; -import type { State as _State } from '../../../commitDetails/protocol'; +import { serializeWebviewItemContext } from '../../../../system/webview'; +import type { State as _State, DetailsItemContext, DetailsItemTypedContext } from '../../../commitDetails/protocol'; import { messageHeadlineSplitterToken } from '../../../commitDetails/protocol'; import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; import { uncommittedSha } from '../commitDetails'; @@ -466,11 +467,36 @@ export class GlCommitDetails extends GlDetailsBase { action: 'file-open-on-remote', }); } - actions.push({ - icon: 'ellipsis', - label: 'Show more actions', - action: 'file-more-actions', - }); return actions; } + + override getFileContextData(file: File): string | undefined { + if (!this.state?.commit) return undefined; + + // Build webviewItem with modifiers matching view context values + // Pattern: gitlens:file+committed[+current][+HEAD][+unpublished] + const commit = this.state.commit; + const isStash = commit.stashNumber != null; + + let webviewItem: DetailsItemContext['webviewItem']; + if (isStash) { + webviewItem = 'gitlens:file+stashed'; + } else { + webviewItem = 'gitlens:file+committed'; + } + + const context: DetailsItemTypedContext = { + webviewItem: webviewItem, + webviewItemValue: { + type: 'file', + path: file.path, + repoPath: commit.repoPath, + sha: commit.sha, + stashNumber: commit.stashNumber, + status: file.status, + }, + }; + + return serializeWebviewItemContext(context); + } } diff --git a/src/webviews/apps/commitDetails/components/gl-details-base.ts b/src/webviews/apps/commitDetails/components/gl-details-base.ts index 7c9e6bdd882de..bd1b2eba28815 100644 --- a/src/webviews/apps/commitDetails/components/gl-details-base.ts +++ b/src/webviews/apps/commitDetails/components/gl-details-base.ts @@ -314,6 +314,11 @@ export class GlDetailsBase extends LitElement { return []; } + protected getFileContextData(_file: File): string | undefined { + // To be overridden by subclasses + return undefined; + } + protected fileToTreeModel( file: File, options?: Partial, @@ -336,6 +341,7 @@ export class GlDetailsBase extends LitElement { description: `${flat === true ? filePath : ''}${file.status === 'R' ? ` ← ${file.originalPath}` : ''}`, context: [file], actions: this.getFileActions(file, options), + contextData: this.getFileContextData(file), // decorations: [{ type: 'text', label: file.status }], ...options, }; diff --git a/src/webviews/apps/commitDetails/components/gl-wip-details.ts b/src/webviews/apps/commitDetails/components/gl-wip-details.ts index 0e28e0c1a8017..97f02ec6d9cbb 100644 --- a/src/webviews/apps/commitDetails/components/gl-wip-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-wip-details.ts @@ -7,7 +7,13 @@ import { when } from 'lit/directives/when.js'; import { uncommitted } from '../../../../git/models/revision'; import { createCommandLink } from '../../../../system/commands'; import { equalsIgnoreCase } from '../../../../system/string'; -import type { DraftState, Wip } from '../../../commitDetails/protocol'; +import { serializeWebviewItemContext } from '../../../../system/webview'; +import type { + DetailsFileContextValue, + DetailsItemTypedContext, + DraftState, + Wip, +} from '../../../commitDetails/protocol'; import type { ComposerCommandArgs } from '../../../plus/composer/registration'; import type { Change } from '../../../plus/patchDetails/protocol'; import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; @@ -418,6 +424,24 @@ export class GlWipDetails extends GlDetailsBase { return [openFile, { icon: 'plus', label: 'Stage changes', action: 'file-stage' }]; } + override getFileContextData(file: File): string | undefined { + if (!this.wip?.repo?.path) return undefined; + + const context: DetailsItemTypedContext = { + webviewItem: file.staged ? 'gitlens:file+staged' : 'gitlens:file+unstaged', + webviewItemValue: { + type: 'file', + path: file.path, + repoPath: this.wip.repo.path, + sha: uncommitted, + staged: file.staged, + status: file.status, + }, + }; + + return serializeWebviewItemContext(context); + } + private onDataActionClick(name: string) { void this.dispatchEvent(new CustomEvent('data-action', { detail: { name: name } })); } diff --git a/src/webviews/apps/shared/components/tree/tree-generator.ts b/src/webviews/apps/shared/components/tree/tree-generator.ts index 40f9b5c312392..241a157882b12 100644 --- a/src/webviews/apps/shared/components/tree/tree-generator.ts +++ b/src/webviews/apps/shared/components/tree/tree-generator.ts @@ -20,6 +20,7 @@ import '../actions/action-item'; import '../status/git-status'; import '../code-icon'; import './tree-item'; +import type { GlTreeItem } from './tree-item'; @customElement('gl-tree-generator') export class GlTreeGenerator extends GlElement { @@ -101,6 +102,10 @@ export class GlTreeGenerator extends GlElement { this.addEventListener('keydown', this.handleKeydown, { capture: true }); this.addEventListener('focusin', this.handleFocusIn, { capture: true }); this.addEventListener('focusout', this.handleFocusOut, { capture: true }); + + // Listen for contextmenu events from tree items and re-dispatch them + // so they can cross the shadow DOM boundary with the context data + this.addEventListener('contextmenu', this.handleContextMenu); } override disconnectedCallback(): void { @@ -109,6 +114,7 @@ export class GlTreeGenerator extends GlElement { this.removeEventListener('keydown', this.handleKeydown, { capture: true }); this.removeEventListener('focusin', this.handleFocusIn, { capture: true }); this.removeEventListener('focusout', this.handleFocusOut, { capture: true }); + this.removeEventListener('contextmenu', this.handleContextMenu); // Clean up type-ahead timer and reset state if (this._typeAheadTimer) { @@ -231,6 +237,7 @@ export class GlTreeGenerator extends GlElement { .focused=${isFocused && this._containerHasFocus && !this._actionButtonHasFocus} .focusedInactive=${isFocused && (!this._containerHasFocus || this._actionButtonHasFocus)} .tabIndex=${-1} + .vscodeContext=${model.contextData as string | undefined} @gl-tree-item-select=${() => this.onBeforeTreeItemSelected(model)} @gl-tree-item-selected=${(e: CustomEvent) => this.onTreeItemSelected(e, model)} @gl-tree-item-checked=${(e: CustomEvent) => this.onTreeItemChecked(e, model)} @@ -407,6 +414,49 @@ export class GlTreeGenerator extends GlElement { } }; + private handleContextMenu = (e: MouseEvent) => { + // Find the tree-item element that triggered the context menu + const path = e.composedPath(); + const treeItem = path.find(el => (el as HTMLElement).tagName === 'GL-TREE-ITEM') as GlTreeItem | undefined; + if (!treeItem) return; + + // Get the context data from the tree-item + const contextData = treeItem.vscodeContext; + if (!contextData) return; + + // Prevent the original event from bubbling + e.preventDefault(); + e.stopPropagation(); + + // Copy the context data to this element (tree-generator host) + // so VS Code's injected library can read it + this.dataset.vscodeContext = contextData; + + // Re-dispatch the event from this element so it can cross the shadow DOM boundary + const evt = new MouseEvent('contextmenu', { + bubbles: true, + composed: true, + cancelable: true, + clientX: e.clientX, + clientY: e.clientY, + button: e.button, + buttons: e.buttons, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + altKey: e.altKey, + metaKey: e.metaKey, + }); + + // Dispatch the new event + this.dispatchEvent(evt); + + // Clean up the context data after a short delay + // (VS Code should have read it by then) + setTimeout(() => { + delete this.dataset.vscodeContext; + }, 100); + }; + private handleKeydown = (e: KeyboardEvent) => { if (e.key !== 'Tab') return; diff --git a/src/webviews/apps/shared/components/tree/tree-item.ts b/src/webviews/apps/shared/components/tree/tree-item.ts index 9c316b8460482..5e2408a88df62 100644 --- a/src/webviews/apps/shared/components/tree/tree-item.ts +++ b/src/webviews/apps/shared/components/tree/tree-item.ts @@ -54,6 +54,9 @@ export class GlTreeItem extends GlElement { @property({ type: Number }) override tabIndex = -1; + @property({ type: String, attribute: 'vscode-context' }) + vscodeContext?: string; + // state @state() selected = false; @@ -183,6 +186,7 @@ export class GlTreeItem extends GlElement { tabindex=${this.tabIndex} @click=${this.onButtonClick} @dblclick=${this.onButtonDblClick} + @contextmenu=${this.onButtonContextMenu} > ${when(this.showIcon, () => html``)} @@ -244,6 +248,29 @@ export class GlTreeItem extends GlElement { }); } + private onButtonContextMenu(e: MouseEvent) { + e.preventDefault(); + e.stopPropagation(); + + // Create a new contextmenu event that can cross shadow DOM boundaries + const evt = new MouseEvent('contextmenu', { + bubbles: true, + composed: true, // This is key - allows event to cross shadow DOM boundaries + cancelable: true, + clientX: e.clientX, + clientY: e.clientY, + button: e.button, + buttons: e.buttons, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + altKey: e.altKey, + metaKey: e.metaKey, + }); + + // Dispatch from the host element (outside shadow DOM) + this.dispatchEvent(evt); + } + private onCheckboxClick(e: Event) { e.stopPropagation(); } diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index 4e2b41eaf26e5..025587ffde871 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -4,12 +4,18 @@ import { CancellationTokenSource, Disposable, env, Uri, window } from 'vscode'; import type { MaybeEnrichedAutolink } from '../../autolinks/models/autolinks'; import { serializeAutolink } from '../../autolinks/utils/-webview/autolinks.utils'; import { getAvatarUri } from '../../avatars'; +import type { CopyDeepLinkCommandArgs, CopyFileDeepLinkCommandArgs } from '../../commands/copyDeepLink'; import type { CopyMessageToClipboardCommandArgs } from '../../commands/copyMessageToClipboard'; import type { CopyShaToClipboardCommandArgs } from '../../commands/copyShaToClipboard'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; import type { ExplainCommitCommandArgs } from '../../commands/explainCommit'; import type { ExplainStashCommandArgs } from '../../commands/explainStash'; import type { ExplainWipCommandArgs } from '../../commands/explainWip'; +import type { OpenFileOnRemoteCommandArgs } from '../../commands/openFileOnRemote'; +import type { OpenOnRemoteCommandArgs } from '../../commands/openOnRemote'; import type { OpenPullRequestOnRemoteCommandArgs } from '../../commands/openPullRequestOnRemote'; +import type { CreatePatchCommandArgs } from '../../commands/patches'; +import type { WebviewViewCommandsOrCommandsWithSuffix } from '../../constants.commands'; import type { ContextKeys } from '../../constants.context'; import { isSupportedCloudIntegrationId } from '../../constants.integrations'; import type { InspectTelemetryContext, Sources } from '../../constants.telemetry'; @@ -17,11 +23,14 @@ import type { Container } from '../../container'; import type { CommitSelectedEvent } from '../../eventBus'; import { executeGitCommand } from '../../git/actions'; import { + applyChanges, openChanges, openChangesWithWorking, openComparisonChanges, openFile, + openFileAtRevision, openFileOnRemote, + restoreFile, showDetailsQuickPick, } from '../../git/actions/commit'; import * as RepoActions from '../../git/actions/repository'; @@ -34,11 +43,13 @@ import type { IssueOrPullRequest } from '../../git/models/issueOrPullRequest'; import type { PullRequest } from '../../git/models/pullRequest'; import type { GitRevisionReference } from '../../git/models/reference'; import type { GitRemote } from '../../git/models/remote'; +import { RemoteResourceType } from '../../git/models/remoteResource'; import type { Repository } from '../../git/models/repository'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../../git/models/repository'; import { uncommitted, uncommittedStaged } from '../../git/models/revision'; import type { RemoteProvider } from '../../git/remotes/remoteProvider'; import { getReferenceFromRevision } from '../../git/utils/-webview/reference.utils'; +import { splitCommitMessage } from '../../git/utils/commit.utils'; import { serializeIssueOrPullRequest } from '../../git/utils/issueOrPullRequest.utils'; import { getComparisonRefsForPullRequest, serializePullRequest } from '../../git/utils/pullRequest.utils'; import { createReference } from '../../git/utils/reference.utils'; @@ -56,10 +67,13 @@ import { executeCommand, executeCoreCommand, executeCoreGitCommand, - registerCommand, + registerWebviewCommand, } from '../../system/-webview/command'; import { configuration } from '../../system/-webview/configuration'; -import { getContext, onDidChangeContext } from '../../system/-webview/context'; +import { getContext, onDidChangeContext, setContext } from '../../system/-webview/context'; +import type { MergeEditorInputs } from '../../system/-webview/vscode/editors'; +import { openMergeEditor } from '../../system/-webview/vscode/editors'; +import { createCommandDecorator, getWebviewViewCommand } from '../../system/decorators/command'; import { debug } from '../../system/decorators/log'; import type { Deferrable } from '../../system/function/debounce'; import { debounce } from '../../system/function/debounce'; @@ -75,9 +89,16 @@ import type { IpcCallMessageType, IpcMessage } from '../protocol'; import type { WebviewHost, WebviewProvider, WebviewShowingArgs } from '../webviewProvider'; import type { WebviewShowOptions } from '../webviewsController'; import { isSerializedState } from '../webviewsController'; +import { + getFileCommitFromContext, + getUriFromContext, + isDetailsFileContext, + isDetailsItemContext, +} from './commitDetailsWebview.utils'; import type { CommitDetails, CreatePatchFromWipParams, + DetailsItemContext, DidExplainParams, DidGenerateParams, ExecuteFileActionParams, @@ -132,6 +153,9 @@ import { } from './protocol'; import type { CommitDetailsWebviewShowingArgs } from './registration'; +const { command, getCommands } = + createCommandDecorator>(); + type RepositorySubscription = { repo: Repository; subscription: Disposable }; // interface WipContext extends Wip @@ -393,7 +417,15 @@ export class CommitDetailsWebviewProvider implements WebviewProvider this.host.refresh(true))]; + const subscriptions: Disposable[] = [ + registerWebviewCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)), + ]; + + for (const { command, handler } of getCommands()) { + subscriptions.push(registerWebviewCommand(getWebviewViewCommand(command, this.host.type), handler, this)); + } + + return subscriptions; } onFocusChanged(focused: boolean): void { @@ -416,11 +448,11 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { + if (item == null) return []; + + if (isDetailsItemContext(item)) { + if (!isDetailsFileContext(item)) return []; + + return getFileCommitFromContext(this.container, item.webviewItemValue); + } + + return this.getFileCommitFromParams(item); + } + private async getFileCommitFromParams( params: ExecuteFileActionParams, - ): Promise<[commit: GitCommit, file: GitFileChange] | undefined> { + ): Promise<[commit: GitCommit, file: GitFileChange] | [commit?: undefined, file?: undefined]> { let commit: GitCommit | undefined; if (this.mode === 'wip') { const uri = this._context.wip?.changes?.repository.uri; - if (uri == null) return; + if (uri == null) return []; commit = await this.container.git.getRepositoryService(Uri.parse(uri)).commits.getCommit(uncommitted); } else { @@ -1786,7 +1832,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider('gitlens.copyPatchToClipboard', { + repoPath: commit.repoPath, + to: commit.ref, + from: `${commit.ref}^`, + title: title, + description: description, + uris: [file.uri], + }); + } + + @command('gitlens.views.openFileRevision:') + private async openFileRevision(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; this.suspendLineTracker(); - void openFile(file, commit, { - preserveFocus: true, - preview: true, - ...this.getShowOptions(params), + void openFileAtRevision(file, commit, { preserveFocus: true, preview: false }); + } + + @command('gitlens.openFileHistory:') + private async openFileHistory(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.openFileHistory', file.uri); + } + + @command('gitlens.quickOpenFileHistory:') + private async quickOpenFileHistory(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.quickOpenFileHistory', file.uri); + } + + @command('gitlens.visualizeHistory.file:') + private async visualizeFileHistory(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.visualizeHistory.file', file.uri); + } + + @command('gitlens.restore.file:') + private async restoreFile(item: DetailsItemContext | undefined) { + if (!isDetailsFileContext(item)) return; + + const { path, repoPath, sha } = item.webviewItemValue; + if (sha == null || sha === uncommitted) return; + + await this.container.git.getRepositoryService(repoPath).checkout(sha, { path: path }); + } + + @command('gitlens.restorePrevious.file:') + private async restorePreviousFile(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void restoreFile(file, commit, true); + } + + @command('gitlens.views.selectFileForCompare:') + private selectFileForCompare(item: DetailsItemContext | undefined) { + if (!isDetailsFileContext(item)) return; + + const { repoPath, sha } = item.webviewItemValue; + const uri = getUriFromContext(this.container, item.webviewItemValue); + if (uri == null) return; + + void setContext('gitlens:views:canCompare:file', { ref: sha ?? uncommitted, repoPath: repoPath, uri: uri }); + } + + @command('gitlens.views.compareFileWithSelected:') + private async compareFileWithSelected(item: DetailsItemContext | undefined) { + const selectedFile = getContext('gitlens:views:canCompare:file'); + if (selectedFile == null || !isDetailsFileContext(item)) return; + + void setContext('gitlens:views:canCompare:file', undefined); + + const { repoPath, sha } = item.webviewItemValue; + if (selectedFile.repoPath !== repoPath) { + this.selectFileForCompare(item); + return; + } + + const uri = getUriFromContext(this.container, item.webviewItemValue); + if (uri == null) return; + + await this.compareFileWith(selectedFile.repoPath, selectedFile.uri, selectedFile.ref, uri, sha ?? uncommitted); + } + + private async compareFileWith( + repoPath: string, + lhsUri: Uri, + lhsRef: string, + rhsUri: Uri | undefined, + rhsRef: string, + ) { + rhsUri ??= await this.container.git.getRepositoryService(repoPath).getWorkingUri(lhsUri); + + return executeCommand('gitlens.diffWith', { + repoPath: repoPath, + lhs: { sha: lhsRef, uri: lhsUri }, + rhs: { sha: rhsRef, uri: rhsUri ?? lhsUri }, }); } - private async openFileOnRemote(params: ExecuteFileActionParams) { - const result = await this.getFileCommitFromParams(params); - if (result == null) return; + @command('gitlens.views.applyChanges:') + private async applyChanges(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; - const [commit, file] = result; + void applyChanges(file, commit); + } - void openFileOnRemote(file, commit); + @command('gitlens.views.mergeChangesWithWorking:') + private async mergeChangesWithWorking(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + const svc = this.container.git.getRepositoryService(commit.repoPath); + if (svc == null) return; + + const nodeUri = await svc.getBestRevisionUri(file.path, commit.ref); + if (nodeUri == null) return; + + const input1: MergeEditorInputs['input1'] = { + uri: nodeUri, + title: `Incoming`, + detail: ` ${commit.shortSha}`, + }; + + const [mergeBaseResult, workingUriResult] = await Promise.allSettled([ + svc.refs.getMergeBase(commit.ref, 'HEAD'), + svc.getWorkingUri(file.uri), + ]); + + const workingUri = getSettledValue(workingUriResult); + if (workingUri == null) { + void window.showWarningMessage('Unable to open the merge editor, no working file found'); + return; + } + const input2: MergeEditorInputs['input2'] = { + uri: workingUri, + title: 'Current', + detail: ' Working Tree', + }; + + const headUri = await svc.getBestRevisionUri(file.path, 'HEAD'); + if (headUri != null) { + const branch = await svc.branches.getBranch?.(); + + input2.uri = headUri; + input2.detail = ` ${branch?.name || 'HEAD'}`; + } + + const mergeBase = getSettledValue(mergeBaseResult); + const baseUri = mergeBase != null ? await svc.getBestRevisionUri(file.path, mergeBase) : undefined; + + return openMergeEditor({ + base: baseUri ?? nodeUri, + input1: input1, + input2: input2, + output: workingUri, + }); } - private async stageFile(params: ExecuteFileActionParams) { - const result = await this.getFileCommitFromParams(params); - if (result == null) return; + @command('gitlens.diffWithRevision:') + private diffWithRevision(item: DetailsItemContext | undefined) { + if (!isDetailsFileContext(item)) return; - const [commit, file] = result; + const uri = getUriFromContext(this.container, item.webviewItemValue); + if (uri == null) return; - await this.container.git.getRepositoryService(commit.repoPath).staging?.stageFile(file.path); + void executeCommand('gitlens.diffWithRevision', uri); } - private async unstageFile(params: ExecuteFileActionParams) { - const result = await this.getFileCommitFromParams(params); - if (result == null) return; + @command('gitlens.diffWithRevisionFrom:') + private diffWithRevisionFrom(item: DetailsItemContext | undefined) { + if (!isDetailsFileContext(item)) return; - const [commit, file] = result; + const uri = getUriFromContext(this.container, item.webviewItemValue); + if (uri == null) return; - await this.container.git.getRepositoryService(commit.repoPath).staging?.unstageFile(file.path); + void executeCommand('gitlens.diffWithRevisionFrom', uri); } - private getShowOptions(params: ExecuteFileActionParams): TextDocumentShowOptions | undefined { - return params.showOptions; + @command('gitlens.externalDiff:') + private async externalDiff(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; - // return getContext('gitlens:webview:graph:active') || getContext('gitlens:webview:rebase:active') - // ? { ...params.showOptions, viewColumn: ViewColumn.Beside } : params.showOptions; + void executeCommand('gitlens.externalDiff', { + files: [ + { + uri: file.uri, + staged: false, + ref1: `${commit.ref}^`, + ref2: commit.ref, + }, + ], + }); + } + + @command('gitlens.views.highlightChanges:') + private async highlightChanges(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + this.suspendLineTracker(); + await openFile(file, commit, { preserveFocus: true, preview: true }); + void (await this.container.fileAnnotations.toggle( + window.activeTextEditor, + 'changes', + { sha: commit.ref }, + true, + )); + } + + @command('gitlens.views.highlightRevisionChanges:') + private async highlightRevisionChanges(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + this.suspendLineTracker(); + await openFile(file, commit, { preserveFocus: true, preview: true }); + void (await this.container.fileAnnotations.toggle( + window.activeTextEditor, + 'changes', + { sha: commit.ref, only: true }, + true, + )); + } + + @command('gitlens.copyDeepLinkToCommit:') + private async copyDeepLinkToCommit(item: DetailsItemContext | undefined) { + const [commit] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.copyDeepLinkToCommit', { refOrRepoPath: commit }); + } + + @command('gitlens.copyDeepLinkToFile:') + private async copyDeepLinkToFile(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.copyDeepLinkToFile', { + ref: commit, + filePath: file.path, + repoPath: commit.repoPath, + }); + } + + @command('gitlens.copyDeepLinkToFileAtRevision:') + private async copyDeepLinkToFileAtRevision(item: DetailsItemContext | undefined) { + const [commit, file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.copyDeepLinkToFileAtRevision', { + ref: commit, + filePath: file.path, + repoPath: commit.repoPath, + chooseRef: true, + }); + } + + @command('gitlens.views.copyRemoteCommitUrl:') + private async copyRemoteCommitUrl(item: DetailsItemContext | undefined) { + const [commit] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.openOnRemote', { + repoPath: commit.repoPath, + resource: { type: RemoteResourceType.Commit, sha: commit.ref }, + clipboard: true, + }); + } + + @command('gitlens.shareAsCloudPatch:') + private async shareAsCloudPatch(item: DetailsItemContext | undefined) { + const [commit] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + if (commit.message == null) { + await commit.ensureFullDetails(); + } + + const { summary: title, body: description } = splitCommitMessage(commit.message); + + void executeCommand('gitlens.createCloudPatch', { + to: commit.ref, + repoPath: commit.repoPath, + title: title, + description: description, + }); + } + + @command('gitlens.copyRemoteFileUrlFrom:') + private async copyRemoteFileUrlFrom(item: DetailsItemContext | undefined) { + const [commit, _file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.copyRemoteFileUrlFrom', { + sha: commit.ref, + clipboard: true, + pickBranchOrTag: true, + range: false, + }); + } + + @command('gitlens.copyRemoteFileUrlWithoutRange:') + private async copyRemoteFileUrlWithoutRange(item: DetailsItemContext | undefined) { + const [commit, _file] = await this.getFileCommitFromContextOrParams(item); + if (commit == null) return; + + void executeCommand('gitlens.copyRemoteFileUrlWithoutRange', { + sha: commit.ref, + clipboard: true, + range: false, + }); } } diff --git a/src/webviews/commitDetails/commitDetailsWebview.utils.ts b/src/webviews/commitDetails/commitDetailsWebview.utils.ts new file mode 100644 index 0000000000000..78a5f55455cc9 --- /dev/null +++ b/src/webviews/commitDetails/commitDetailsWebview.utils.ts @@ -0,0 +1,82 @@ +import type { Uri } from 'vscode'; +import type { Container } from '../../container'; +import type { GitCommit } from '../../git/models/commit'; +import type { GitFileChange } from '../../git/models/fileChange'; +import { uncommitted } from '../../git/models/revision'; +import { isUncommitted } from '../../git/utils/revision.utils'; +import { isWebviewItemContext } from '../../system/webview'; +import type { + DetailsFileContextValue, + DetailsItemContext, + DetailsItemTypedContext, + DetailsItemTypedContextValue, +} from './protocol'; + +export function isDetailsItemContext(item: unknown): item is DetailsItemContext { + if (item == null) return false; + + return ( + isWebviewItemContext(item) && + (item.webview === 'gitlens.views.commitDetails' || item.webview === 'gitlens.views.graphDetails') + ); +} + +export function isDetailsItemTypedContext(item: unknown, type: 'file'): item is DetailsItemTypedContext; +export function isDetailsItemTypedContext( + item: unknown, + type: DetailsItemTypedContextValue['type'], +): item is DetailsItemTypedContext { + if (item == null) return false; + + return ( + isDetailsItemContext(item) && typeof item.webviewItemValue === 'object' && item.webviewItemValue.type === type + ); +} + +export function isDetailsFileContext(item: unknown): item is DetailsItemTypedContext { + if (item == null) return false; + + return isDetailsItemTypedContext(item, 'file'); +} + +export function getUriFromContext(container: Container, context: DetailsFileContextValue): Uri | undefined { + const { path, repoPath, sha } = context; + const svc = container.git.getRepositoryService(repoPath); + + let uri: Uri | undefined; + if (sha != null && !isUncommitted(sha)) { + uri = svc.getRevisionUri(sha, path); + } else { + uri = svc.getAbsoluteUri(path, repoPath); + } + return uri; +} + +export async function getFileCommitFromContext( + container: Container, + context: DetailsFileContextValue, +): Promise<[commit: GitCommit, file: GitFileChange] | [commit?: undefined, file?: undefined]> { + const { path, repoPath, sha, staged, stashNumber } = context; + const svc = container.git.getRepositoryService(repoPath); + + if (stashNumber != null) { + const stash = await svc.stash?.getStash(); + const commit = stash?.stashes.get(sha!); + if (commit == null) return []; + + const file = await commit.findFile(path); + return commit != null && file != null ? [commit, file] : []; + } + + if (isUncommitted(sha)) { + let commit = await svc.commits.getCommit(uncommitted); + commit = await commit?.getCommitForFile(path, staged); + return commit?.file != null ? [commit, commit.file] : []; + } + + const uri = getUriFromContext(container, context); + if (uri == null) return []; + + const commit = await svc.commits.getCommitForFile(uri, sha); + return commit?.file != null ? [commit, commit.file] : []; +} diff --git a/src/webviews/commitDetails/protocol.ts b/src/webviews/commitDetails/protocol.ts index 1cbfd9e14015f..f13e3e26aeaf6 100644 --- a/src/webviews/commitDetails/protocol.ts +++ b/src/webviews/commitDetails/protocol.ts @@ -4,11 +4,13 @@ import type { Config, DateStyle } from '../../config'; import type { Sources } from '../../constants.telemetry'; import type { GitCommitIdentityShape, GitCommitStats } from '../../git/models/commit'; import type { GitFileChangeShape } from '../../git/models/fileChange'; +import type { GitFileStatus } from '../../git/models/fileStatus'; import type { IssueOrPullRequest } from '../../git/models/issueOrPullRequest'; import type { PullRequestShape } from '../../git/models/pullRequest'; import type { Repository } from '../../git/models/repository'; import type { Draft, DraftVisibility } from '../../plus/drafts/models/drafts'; import type { DateTimeFormat } from '../../system/date'; +import type { WebviewItemContext } from '../../system/webview'; import type { Change, DraftUserSelection } from '../plus/patchDetails/protocol'; import type { IpcScope, WebviewState } from '../protocol'; import { IpcCommand, IpcNotification, IpcRequest } from '../protocol'; @@ -260,3 +262,21 @@ export const DidChangeIntegrationsNotification = new IpcNotification; +export type DetailsItemContextValue = DetailsItemTypedContextValue; + +export type DetailsItemTypedContext = WebviewItemContext; +export type DetailsItemTypedContextValue = DetailsFileContextValue; + +export interface DetailsFileContextValue { + type: 'file'; + path: string; + repoPath: string; + sha?: string; + stashNumber?: string; + staged?: boolean; + status?: GitFileStatus; +} diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 7335df84e2f21..ba20658cabe85 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -5,7 +5,14 @@ import { base64 } from '@env/base64'; import { getNonce } from '@env/crypto'; import type { WebviewCommands, WebviewViewCommands } from '../constants.commands'; import type { WebviewTelemetryContext } from '../constants.telemetry'; -import type { CustomEditorTypes, WebviewIds, WebviewTypes, WebviewViewIds, WebviewViewTypes } from '../constants.views'; +import type { + CustomEditorTypes, + WebviewIds, + WebviewOrWebviewViewTypeFromId, + WebviewTypes, + WebviewViewIds, + WebviewViewTypes, +} from '../constants.views'; import type { Container } from '../container'; import { isCancellationError } from '../errors'; import { getSubscriptionNextPaidPlanId } from '../plus/gk/utils/subscription.utils'; @@ -152,6 +159,10 @@ export class WebviewController< readonly id: ID; + get type(): WebviewOrWebviewViewTypeFromId { + return this.descriptor.type as WebviewOrWebviewViewTypeFromId; + } + private _ready: boolean = false; get ready(): boolean { return this._ready; diff --git a/src/webviews/webviewProvider.ts b/src/webviews/webviewProvider.ts index 2a39c8753e10a..5312b0c8b1fcf 100644 --- a/src/webviews/webviewProvider.ts +++ b/src/webviews/webviewProvider.ts @@ -1,7 +1,7 @@ import type { Disposable, Uri, ViewBadge, ViewColumn } from 'vscode'; import type { WebviewCommands, WebviewViewCommands } from '../constants.commands'; import type { WebviewTelemetryContext } from '../constants.telemetry'; -import type { WebviewIds, WebviewViewIds } from '../constants.views'; +import type { WebviewIds, WebviewOrWebviewViewTypeFromId, WebviewViewIds } from '../constants.views'; import type { WebviewContext } from '../system/webview'; import type { IpcCallMessageType, @@ -58,6 +58,7 @@ export interface WebviewStateProvier { readonly id: ID; readonly instanceId: string; + readonly type: WebviewOrWebviewViewTypeFromId; readonly originalTitle: string; title: string; diff --git a/src/webviews/webviewsController.ts b/src/webviews/webviewsController.ts index 7df9a5335fab1..a13c24d1d7175 100644 --- a/src/webviews/webviewsController.ts +++ b/src/webviews/webviewsController.ts @@ -10,7 +10,7 @@ import { Disposable, Uri, ViewColumn, window } from 'vscode'; import { uuid } from '@env/crypto'; import type { GlCommands } from '../constants.commands'; import type { TrackedUsageFeatures } from '../constants.telemetry'; -import type { WebviewIds, WebviewTypes, WebviewViewIds, WebviewViewTypes } from '../constants.views'; +import type { WebviewIds, WebviewTypeFromId, WebviewViewIds, WebviewViewTypeFromId } from '../constants.views'; import type { Container } from '../container'; import { ensurePlusFeaturesEnabled } from '../plus/gk/utils/-webview/plus.utils'; import { executeCoreCommand, registerCommand } from '../system/-webview/command'; @@ -28,9 +28,9 @@ export interface WebviewPanelDescriptor { readonly fileName: string; readonly iconPath: string; readonly title: string; - readonly contextKeyPrefix: `gitlens:webview:${WebviewTypes}`; + readonly contextKeyPrefix: `gitlens:webview:${WebviewTypeFromId}`; readonly trackingFeature: TrackedUsageFeatures; - readonly type: WebviewTypes; + readonly type: WebviewTypeFromId; readonly plusFeature: boolean; readonly column?: ViewColumn; readonly webviewOptions?: WebviewOptions; @@ -88,9 +88,9 @@ export interface WebviewViewDescriptor}`; readonly trackingFeature: TrackedUsageFeatures; - readonly type: WebviewViewTypes; + readonly type: WebviewViewTypeFromId; readonly plusFeature: boolean; readonly webviewOptions?: WebviewOptions; readonly webviewHostOptions?: { From 3bad6de3fcaef5fc7e98df08655be053510850fe Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 01:16:38 -0400 Subject: [PATCH 54/83] Fixes #4714 ensures all files when uncommited --- CHANGELOG.md | 1 + .../commitDetails/commitDetailsWebview.ts | 17 +++++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f697ea75014a..11ae858ca2741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes intermittent stuck loading state on the _Commit Graph_ ([#4669](https://github.com/gitkraken/vscode-gitlens/issues/4669)) - Fixes underlines showing on home branch actions ([#4703](https://github.com/gitkraken/vscode-gitlens/issues/4703)) +- Fixes _Inspect_ view not showing uncommitted files on the Inspect tab ([#4714](https://github.com/gitkraken/vscode-gitlens/issues/4714)) ## [17.6.2] - 2025-10-16 diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index 025587ffde871..dfa018859619a 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -1239,13 +1239,8 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { const [commitResult, avatarUriResult, remoteResult] = await Promise.allSettled([ - !commit.hasFullDetails() ? commit.ensureFullDetails().then(() => commit) : commit, + !commit.hasFullDetails() + ? commit.ensureFullDetails({ include: { uncommittedFiles: true } }).then(() => commit) + : commit, commit.author.getAvatarUri(commit, { size: 32 }), this.container.git .getRepositoryService(commit.repoPath) @@ -1734,7 +1731,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider Date: Wed, 22 Oct 2025 16:45:18 -0400 Subject: [PATCH 55/83] Closes #4716 select wip row by default Adds `graph.initialRowSelection` setting to control the behavior --- CHANGELOG.md | 2 ++ docs/telemetry-events.md | 1 + package.json | 17 ++++++++++++++++ src/config.ts | 1 + src/webviews/plus/graph/graphWebview.ts | 27 ++++++++++++++++++++----- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ae858ca2741..a60b83e014559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed +- Changes to select the "Work in progress" (WIP) row in the _Commit Graph_ by default if there are uncommitted changes ([#4716](https://github.com/gitkraken/vscode-gitlens/issues/4716)) + - Adds `gitlens.graph.initialRowSelection` setting to specify whether to select the "Work in progress" (WIP) row instead of HEAD if there are uncommitted changes - Changes to use the "merge target" when we are creating pull requests ([#4709](https://github.com/gitkraken/vscode-gitlens/issues/4709)) - Changes the minimum VS Code version to 1.95.0 ([#4691](https://github.com/gitkraken/vscode-gitlens/issues/4691)) diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index 47039a3b70cc3..390c3575c10e0 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -2174,6 +2174,7 @@ or 'context.config.dimMergeCommits': boolean, 'context.config.experimental.renderer.enabled': boolean, 'context.config.highlightRowsOnRefHover': boolean, + 'context.config.initialRowSelection': 'wip' | 'head', 'context.config.issues.enabled': boolean, 'context.config.layout': 'editor' | 'panel', 'context.config.minimap.additionalTypes': string, diff --git a/package.json b/package.json index 5e1d89b2c5a97..6140c423dbc7f 100644 --- a/package.json +++ b/package.json @@ -1117,6 +1117,23 @@ "scope": "window", "order": 500 }, + "gitlens.graph.initialRowSelection": { + "type": [ + "string" + ], + "default": "wip", + "enum": [ + "wip", + "head" + ], + "enumDescriptions": [ + "Selects the working changes (WIP) row when there are uncommitted changes, otherwise selects the HEAD row", + "Always selects the HEAD row" + ], + "markdownDescription": "Specifies whether to select the \"Work in progress\" (WIP) row instead of HEAD if there are uncommitted changes in the _Commit Graph_", + "scope": "window", + "order": 501 + }, "gitlens.graph.dateStyle": { "type": [ "string", diff --git a/src/config.ts b/src/config.ts index a92174624cc1c..c23a12e47abe2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -438,6 +438,7 @@ export interface GraphConfig { }; readonly scrollRowPadding: number; readonly searchItemLimit: number; + readonly initialRowSelection: 'head' | 'wip'; readonly showDetailsView: 'open' | 'selection' | false; readonly showGhostRefsOnRowHover: boolean; readonly showRemoteNames: boolean; diff --git a/src/webviews/plus/graph/graphWebview.ts b/src/webviews/plus/graph/graphWebview.ts index cbc3bd4430ab8..f0fa51de32716 100644 --- a/src/webviews/plus/graph/graphWebview.ts +++ b/src/webviews/plus/graph/graphWebview.ts @@ -2057,14 +2057,14 @@ export class GraphWebviewProvider implements WebviewProvider { + private async getWorkingTreeStats( + hasWorkingChanges?: boolean, + cancellation?: CancellationToken, + ): Promise { if (this.repository == null || !this.container.git.repositoryCount) return undefined; const svc = this.container.git.getRepositoryService(this.repository.path); + hasWorkingChanges ??= await svc.status.hasWorkingChanges( + { staged: true, unstaged: true, untracked: false }, + cancellation, + ); + const [statusResult, pausedOpStatusResult] = await Promise.allSettled([ - svc.status.getStatus(cancellation), + hasWorkingChanges ? svc.status.getStatus(cancellation) : undefined, svc.status.getPausedOperationStatus?.(cancellation), ]); @@ -2610,6 +2618,15 @@ export class GraphWebviewProvider implements WebviewProvider Date: Wed, 22 Oct 2025 16:53:18 -0400 Subject: [PATCH 56/83] Fixes lint error --- .../apps/commitDetails/components/gl-wip-details.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/webviews/apps/commitDetails/components/gl-wip-details.ts b/src/webviews/apps/commitDetails/components/gl-wip-details.ts index 97f02ec6d9cbb..eeace883acb73 100644 --- a/src/webviews/apps/commitDetails/components/gl-wip-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-wip-details.ts @@ -8,12 +8,7 @@ import { uncommitted } from '../../../../git/models/revision'; import { createCommandLink } from '../../../../system/commands'; import { equalsIgnoreCase } from '../../../../system/string'; import { serializeWebviewItemContext } from '../../../../system/webview'; -import type { - DetailsFileContextValue, - DetailsItemTypedContext, - DraftState, - Wip, -} from '../../../commitDetails/protocol'; +import type { DetailsItemTypedContext, DraftState, Wip } from '../../../commitDetails/protocol'; import type { ComposerCommandArgs } from '../../../plus/composer/registration'; import type { Change } from '../../../plus/patchDetails/protocol'; import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; @@ -427,7 +422,7 @@ export class GlWipDetails extends GlDetailsBase { override getFileContextData(file: File): string | undefined { if (!this.wip?.repo?.path) return undefined; - const context: DetailsItemTypedContext = { + const context: DetailsItemTypedContext = { webviewItem: file.staged ? 'gitlens:file+staged' : 'gitlens:file+unstaged', webviewItemValue: { type: 'file', From 17798d75eec1c795330affe08dfff1932a1e4039 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 16:53:30 -0400 Subject: [PATCH 57/83] Removes excludes --- .vscode/settings.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 85e45283a8e1c..857995de54fed 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,10 +5,6 @@ "files.associations": { ".eslintrc*.json": "jsonc" }, - "files.exclude": { - "**/.vscode-test": true, - "**/.vscode-test-web": true - }, "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, "githubIssues.queries": [ From 98d82e64e3008cbbe430ddab3e7ddcd1b5732c58 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 17:08:08 -0400 Subject: [PATCH 58/83] Attempts to fix missing events (infrequent) --- .../nodes/abstract/subscribeableViewNode.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/views/nodes/abstract/subscribeableViewNode.ts b/src/views/nodes/abstract/subscribeableViewNode.ts index f1e1474b3d0b5..a98cbb06846fc 100644 --- a/src/views/nodes/abstract/subscribeableViewNode.ts +++ b/src/views/nodes/abstract/subscribeableViewNode.ts @@ -59,11 +59,35 @@ export abstract class SubscribeableViewNode< @debug() override async triggerChange(reset: boolean = false, force: boolean = false): Promise { - if (!this.loaded || this._disposed) return; + const scope = getLogScope(); + + // If the node has been disposed, nothing to do + if (this._disposed) { + setLogScopeExit(scope, ' \u2022 ignored; disposed'); + return; + } + + // If the node hasn't been loaded yet, don't trigger view refreshes now. + // If this is a reset, record it so it will be applied when the node becomes loaded/visible. + if (!this.loaded) { + if (reset) { + setLogScopeExit(scope, ' \u2022 ignored; pending reset'); + // If the view isn't visible, we'll persist the pending reset for application on visible. + // If the view is visible but the node isn't loaded, it's still safer to record the reset + // and let the normal load/visibility logic apply it rather than firing tree updates for + // a node that doesn't exist yet in the tree. + this._pendingReset = reset; + } else { + setLogScopeExit(scope, ' \u2022 ignored; not loaded'); + } + return; + } if (reset && !this.view.visible) { this._pendingReset = reset; } + + setLogScopeExit(scope, ' \u2022 refreshing view'); await super.triggerChange(reset, force); } From c4d1f3049d02b25fd40db39bd145c814938cca35 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 17:36:02 -0400 Subject: [PATCH 59/83] Fixes showing overview mode when selecting WIP row --- src/webviews/commitDetails/commitDetailsWebview.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index dfa018859619a..3a5872d4e680b 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -1106,9 +1106,8 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { this._context.mode = mode; - if (mode === 'commit') { - void this.notifyDidChangeState(true); - } else { + void this.notifyDidChangeState(true); + if (mode === 'wip') { await this.updateWipState(repository ?? this.container.git.getBestRepositoryOrFirst()); } From de3274025c3955a5887600875fef49178e4ce83b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Oct 2025 18:53:31 -0400 Subject: [PATCH 60/83] Improves row selection --- src/env/node/git/sub-providers/graph.ts | 25 ++++++++++-------- .../providers/github/sub-providers/graph.ts | 5 ++-- src/webviews/plus/graph/graphWebview.ts | 26 +++++++++++++------ 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/env/node/git/sub-providers/graph.ts b/src/env/node/git/sub-providers/graph.ts index 0cd258f46d7e8..7e2c12752ebaa 100644 --- a/src/env/node/git/sub-providers/graph.ts +++ b/src/env/node/git/sub-providers/graph.ts @@ -40,7 +40,7 @@ import { } from '../../../../git/utils/branch.utils'; import { getChangedFilesCount } from '../../../../git/utils/commit.utils'; import { createReference } from '../../../../git/utils/reference.utils'; -import { isUncommittedStaged } from '../../../../git/utils/revision.utils'; +import { isUncommitted } from '../../../../git/utils/revision.utils'; import { getTagId } from '../../../../git/utils/tag.utils'; import { isUserMatch } from '../../../../git/utils/user.utils'; import { getWorktreeId } from '../../../../git/utils/worktree.utils'; @@ -94,14 +94,16 @@ export class GraphGitSubProvider implements GitGraphSubProvider { const [shaResult, stashResult, branchesResult, remotesResult, currentUserResult, worktreesResult] = await Promise.allSettled([ - this.git.exec( - { cwd: repoPath, configs: gitConfigsLog }, - 'log', - ...shaParser.arguments, - '-n1', - rev && !isUncommittedStaged(rev) ? rev : 'HEAD', - '--', - ), + !isUncommitted(rev, true) + ? this.git.exec( + { cwd: repoPath, configs: gitConfigsLog }, + 'log', + ...shaParser.arguments, + '-n1', + rev ?? 'HEAD', + '--', + ) + : undefined, this.provider.stash?.getStash(repoPath, undefined, cancellation), this.provider.branches.getBranches(repoPath, undefined, cancellation), this.provider.remotes.getRemotes(repoPath, undefined, cancellation), @@ -131,7 +133,8 @@ export class GraphGitSubProvider implements GitGraphSubProvider { const remotes = getSettledValue(remotesResult); const remoteMap = remotes != null ? new Map(remotes.map(r => [r.name, r])) : new Map(); - const selectSha = first(shaParser.parse(getSettledValue(shaResult)?.stdout)); + const shas = getSettledValue(shaResult)?.stdout; + const selectSha = shas != null ? first(shaParser.parse(shas)) : undefined; const downstreamMap = new Map(); @@ -589,7 +592,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider { worktrees: worktrees, worktreesByBranch: worktreesByBranch, rows: rows, - id: sha, + id: sha ?? rev, rowsStats: rowStats, rowsStatsDeferred: rowsStatsDeferred, paging: { diff --git a/src/plus/integrations/providers/github/sub-providers/graph.ts b/src/plus/integrations/providers/github/sub-providers/graph.ts index 49b4a6f54383e..6e19df0cb68d7 100644 --- a/src/plus/integrations/providers/github/sub-providers/graph.ts +++ b/src/plus/integrations/providers/github/sub-providers/graph.ts @@ -27,6 +27,7 @@ import { getRemoteIconUri } from '../../../../../git/utils/-webview/icons'; import { getBranchId, getBranchNameWithoutRemote } from '../../../../../git/utils/branch.utils'; import { getChangedFilesCount } from '../../../../../git/utils/commit.utils'; import { createReference } from '../../../../../git/utils/reference.utils'; +import { isUncommitted } from '../../../../../git/utils/revision.utils'; import { getTagId } from '../../../../../git/utils/tag.utils'; import { configuration } from '../../../../../system/-webview/configuration'; import { log } from '../../../../../system/decorators/log'; @@ -66,7 +67,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider { const [logResult, headBranchResult, branchesResult, remotesResult, tagsResult, currentUserResult] = await Promise.allSettled([ - this.provider.commits.getLog(repoPath, rev, { + this.provider.commits.getLog(repoPath, !rev || isUncommitted(rev) ? 'HEAD' : rev, { all: true, ordering: ordering, limit: defaultLimit, @@ -449,7 +450,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider { worktrees: worktrees, worktreesByBranch: worktreesByBranch, rows: rows, - id: options?.ref, + id: options?.ref ?? first(log.commits.values())?.sha, paging: { limit: log.limit, diff --git a/src/webviews/plus/graph/graphWebview.ts b/src/webviews/plus/graph/graphWebview.ts index f0fa51de32716..18f4133d5dd38 100644 --- a/src/webviews/plus/graph/graphWebview.ts +++ b/src/webviews/plus/graph/graphWebview.ts @@ -2623,18 +2623,25 @@ export class GraphWebviewProvider implements WebviewProvider this.host.asWebviewUri(uri), { include: { @@ -2662,18 +2669,21 @@ export class GraphWebviewProvider implements WebviewProvider Date: Thu, 23 Oct 2025 02:20:08 -0400 Subject: [PATCH 61/83] Fixes #4717 handles undefined params --- src/webviews/webviewController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index ba20658cabe85..4e2194081190a 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -673,9 +673,9 @@ export class WebviewController< const scope = getNewLogScope(`${getLoggableName(this)}.notify(${id}|${notificationType.method})`, true); const sw = maybeStopWatch(scope, { log: false, logLevel: 'debug' }); - const serializedParams = this.serializeIpcData(params); + const serializedParams = params != null ? this.serializeIpcData(params) : undefined; - sw?.restart({ message: `\u2022 serialized params; length=${serializedParams.length}` }); + sw?.restart({ message: `\u2022 serialized params; length=${serializedParams?.length ?? 0}` }); let bytes: Uint8Array | undefined; let compression: IpcMessage['compressed'] = false; From 00db62492a82b0490765cba577e9638ff1d57e48 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 22 Oct 2025 16:31:45 -0400 Subject: [PATCH 62/83] Fixes text overflow on composer commit messages --- .../composer/components/commit-message.ts | 102 +++++++++++------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/src/webviews/apps/plus/composer/components/commit-message.ts b/src/webviews/apps/plus/composer/components/commit-message.ts index f1ad4794f9f22..8bf013cc1ba45 100644 --- a/src/webviews/apps/plus/composer/components/commit-message.ts +++ b/src/webviews/apps/plus/composer/components/commit-message.ts @@ -1,10 +1,11 @@ import type { PropertyValues } from 'lit'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { when } from 'lit/directives/when.js'; import { debounce } from '../../../../../system/function/debounce'; import { focusableBaseStyles } from '../../../shared/components/styles/lit/a11y.css'; -import { boxSizingBase } from '../../../shared/components/styles/lit/base.css'; +import { boxSizingBase, scrollableBase } from '../../../shared/components/styles/lit/base.css'; @customElement('gl-commit-message') export class CommitMessage extends LitElement { @@ -14,6 +15,7 @@ export class CommitMessage extends LitElement { }; static override styles = [ + scrollableBase, boxSizingBase, focusableBaseStyles, css` @@ -25,19 +27,19 @@ export class CommitMessage extends LitElement { max-width: 80rem; } + .commit-message__text, + .commit-message__input { + border-radius: 0.2rem; + font-family: inherit; + font-size: 1.3rem; + line-height: 2rem; + color: var(--vscode-input-foreground); + -webkit-font-smoothing: auto; + } + .commit-message__text { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - padding: 1.2rem 1.6rem; - font-size: 1.6rem; - line-height: 1.4; - overflow-wrap: break-word; - word-wrap: break-word; border: 1px solid var(--vscode-panel-border); - border-radius: 0.4rem; background: var(--color-background); - color: var(--vscode-input-foreground); margin-block: 0; } @@ -46,42 +48,67 @@ export class CommitMessage extends LitElement { font-style: italic; } - .commit-message__field { - position: relative; + .commit-message__text .scrollable { + display: block; + overflow-y: auto; } + .commit-message__text .scrollable, .commit-message__input { - width: 100%; padding: 0.5rem; - font-family: inherit; - font-size: 1.3rem; - line-height: 2rem; - border: 1px solid var(--vscode-input-border); - border-radius: 0.2rem; - background: var(--vscode-input-background); - color: var(--vscode-input-foreground); - vertical-align: middle; - -webkit-font-smoothing: auto; + min-height: 1lh; + max-height: 10lh; } - .commit-message__input:has(~ .commit-message__ai-button) { - padding-right: 3rem; + .commit-message__field { + position: relative; } - textarea.commit-message__input { + .commit-message__input { box-sizing: content-box; width: calc(100% - 1rem); - resize: vertical; + border: 1px solid var(--vscode-input-border); + background: var(--vscode-input-background); + vertical-align: middle; field-sizing: content; - min-height: 1lh; - max-height: 10lh; resize: none; } - textarea.commit-message__input:has(~ .commit-message__ai-button) { + + .commit-message__input::-webkit-scrollbar { + width: 10px; + } + + .commit-message__input::-webkit-scrollbar-track { + background: transparent; + } + + .commit-message__input::-webkit-scrollbar-thumb { + background-color: transparent; + border-color: transparent; + border-right-style: inset; + border-right-width: calc(100vw + 100vh); + border-radius: unset !important; + } + + .commit-message__input:hover::-webkit-scrollbar-thumb, + .commit-message__input:focus-within::-webkit-scrollbar-thumb { + border-color: var(--vscode-scrollbarSlider-background); + } + + .commit-message__input::-webkit-scrollbar-thumb:hover { + border-color: var(--vscode-scrollbarSlider-hoverBackground); + } + + .commit-message__input::-webkit-scrollbar-thumb:active { + border-color: var(--vscode-scrollbarSlider-activeBackground); + } + + .commit-message__input:has(~ .commit-message__ai-button) { + padding-right: 3rem; width: calc(100% - 3.5rem); } - .has-explanation { + .commit-message__input.has-explanation { border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -267,12 +294,15 @@ export class CommitMessage extends LitElement { } private renderReadOnly() { - const displayMessage = - this.message && this.message.trim().length > 0 ? this.message : 'Draft commit (add a commit message)'; - const isPlaceholder = !this.message || this.message.trim().length === 0; + let displayMessage = 'Draft commit (add a commit message)'; + let isPlaceholder = true; + if (this.message && this.message.trim().length > 0) { + displayMessage = this.message.replace(/\n/g, '
'); + isPlaceholder = false; + } - return html`

- ${displayMessage} + return html`

+ ${unsafeHTML(displayMessage)}

`; } From 11f58b4a61fc2412f6d25f4bb1c10d6a24b4e35e Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 23 Oct 2025 12:23:00 -0400 Subject: [PATCH 63/83] Updates graph dependency Resolves #4544 --- CHANGELOG.md | 1 + package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60b83e014559..422cd53889a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes intermittent stuck loading state on the _Commit Graph_ ([#4669](https://github.com/gitkraken/vscode-gitlens/issues/4669)) - Fixes underlines showing on home branch actions ([#4703](https://github.com/gitkraken/vscode-gitlens/issues/4703)) - Fixes _Inspect_ view not showing uncommitted files on the Inspect tab ([#4714](https://github.com/gitkraken/vscode-gitlens/issues/4714)) +- Fixes _Commit Graph_ losing row selection when graph updates ([#4544](https://github.com/gitkraken/vscode-gitlens/issues/4544)) ## [17.6.2] - 2025-10-16 diff --git a/package.json b/package.json index 6140c423dbc7f..2cbe6b2d91ec8 100644 --- a/package.json +++ b/package.json @@ -25939,7 +25939,7 @@ "vscode:prepublish": "pnpm run bundle" }, "dependencies": { - "@gitkraken/gitkraken-components": "13.0.0-vnext.9", + "@gitkraken/gitkraken-components": "13.0.0-vnext.10", "@gitkraken/provider-apis": "0.29.7", "@gitkraken/shared-web-components": "0.1.1-rc.15", "@gk-nzaytsev/fast-string-truncated-width": "1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2476092e03def..76fe85fb59093 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ importers: .: dependencies: '@gitkraken/gitkraken-components': - specifier: 13.0.0-vnext.9 - version: 13.0.0-vnext.9(@types/react@19.0.14)(react@19.0.0) + specifier: 13.0.0-vnext.10 + version: 13.0.0-vnext.10(@types/react@19.0.14)(react@19.0.0) '@gitkraken/provider-apis': specifier: 0.29.7 version: 0.29.7(encoding@0.1.13) @@ -335,7 +335,7 @@ importers: packages: '@axosoft/react-virtualized@9.22.3-gitkraken.3': - resolution: {integrity: sha512-sCU8gM0Ut1I3lNBYLQCq7nmRObFsdGKkTIMZkVThZhFYtmQchl1RLnsXilicmNlwCNZdm3/uDCpOw6q7T1gtog==} + resolution: {integrity: sha512-sCU8gM0Ut1I3lNBYLQCq7nmRObFsdGKkTIMZkVThZhFYtmQchl1RLnsXilicmNlwCNZdm3/uDCpOw6q7T1gtog==, tarball: https://registry.npmjs.org/@axosoft/react-virtualized/-/react-virtualized-9.22.3-gitkraken.3.tgz} peerDependencies: react: ^15.3.0 || ^16.0.0-alpha react-dom: ^15.3.0 || ^16.0.0-alpha @@ -662,8 +662,8 @@ packages: '@github/catalyst@1.7.0': resolution: {integrity: sha512-qOAxrDdRZz9+v4y2WoAfh11rpRY/x4FRofPNmJyZFzAjubtzE3sCa/tAycWWufmQGoYiwwzL/qJBBgyg7avxPw==} - '@gitkraken/gitkraken-components@13.0.0-vnext.9': - resolution: {integrity: sha512-PvwOVrCk27aRG/J/Khx1EuipDfpULmmCi2YnKCQSFESY+uo12I2e7RIA4EPJ516/PaeQUvo6Zgps7Jjz0SOiRw==} + '@gitkraken/gitkraken-components@13.0.0-vnext.10': + resolution: {integrity: sha512-2V1ANVfW9mQZV/AQYCIt2yBIfqjet3WL05O/i2ptCbgmdqIVeDalNSQAodZWqtLqpXCIg59y7b2vtOzo6bYPBw==} peerDependencies: react: 19.0.0 @@ -6723,7 +6723,7 @@ snapshots: '@github/catalyst@1.7.0': {} - '@gitkraken/gitkraken-components@13.0.0-vnext.9(@types/react@19.0.14)(react@19.0.0)': + '@gitkraken/gitkraken-components@13.0.0-vnext.10(@types/react@19.0.14)(react@19.0.0)': dependencies: '@axosoft/react-virtualized': 9.22.3-gitkraken.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) classnames: 2.5.1 From 427653812cacf8f2fe7571ffc11da8c7fb0b49ee Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 23 Oct 2025 17:39:57 -0400 Subject: [PATCH 64/83] Re-adds webview url filtering --- .vscode/launch.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 643773eecfad6..65c30e64648cb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,7 +17,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}/src/webviews/apps" }, "outFiles": ["${workspaceFolder}/dist/**/*.js"], @@ -55,7 +55,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}" }, "outFiles": ["${workspaceFolder}/dist/browser/**/*.js"], @@ -87,7 +87,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}/src/webviews/apps" }, "outFiles": ["${workspaceFolder}/dist/**/*.js"], @@ -140,7 +140,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}/src/webviews/apps" }, "outFiles": ["${workspaceFolder}/dist/**/*.js"], @@ -179,7 +179,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}" }, "outFiles": ["${workspaceFolder}/dist/browser/**/*.js"], @@ -211,7 +211,7 @@ "sourceMapRenames": true, "sourceMaps": true, "trace": true, - // "urlFilter": "*eamodio.gitlens*", + "urlFilter": "*eamodio.gitlens*", "webRoot": "${workspaceFolder}/src/webviews/apps" }, "outFiles": ["${workspaceFolder}/dist/**/*.js"], From 644dc27efd2f4dc4abdd803ccae294740088b52c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 23 Oct 2025 19:55:58 -0400 Subject: [PATCH 65/83] Fixes missing lint during watch --- package.json | 2 +- pnpm-lock.yaml | 33 ++++++--------------------------- pnpm-workspace.yaml | 1 + webpack.config.mjs | 13 +++++++++++++ 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 2cbe6b2d91ec8..12645285c7fc1 100644 --- a/package.json +++ b/package.json @@ -25979,7 +25979,7 @@ }, "devDependencies": { "@custom-elements-manifest/analyzer": "0.10.10", - "@eamodio/eslint-lite-webpack-plugin": "0.3.2", + "@eamodio/eslint-lite-webpack-plugin": "0.3.3", "@eslint/compat": "1.4.0", "@eslint/js": "9.37.0", "@playwright/test": "1.56.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 76fe85fb59093..f4e0c1260c4ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,8 +131,8 @@ importers: specifier: 0.10.10 version: 0.10.10 '@eamodio/eslint-lite-webpack-plugin': - specifier: 0.3.2 - version: 0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.37.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.102.1) + specifier: 0.3.3 + version: 0.3.3(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1) '@eslint/compat': specifier: 1.4.0 version: 1.4.0(eslint@9.37.0(jiti@2.4.0)) @@ -335,7 +335,7 @@ importers: packages: '@axosoft/react-virtualized@9.22.3-gitkraken.3': - resolution: {integrity: sha512-sCU8gM0Ut1I3lNBYLQCq7nmRObFsdGKkTIMZkVThZhFYtmQchl1RLnsXilicmNlwCNZdm3/uDCpOw6q7T1gtog==, tarball: https://registry.npmjs.org/@axosoft/react-virtualized/-/react-virtualized-9.22.3-gitkraken.3.tgz} + resolution: {integrity: sha512-sCU8gM0Ut1I3lNBYLQCq7nmRObFsdGKkTIMZkVThZhFYtmQchl1RLnsXilicmNlwCNZdm3/uDCpOw6q7T1gtog==} peerDependencies: react: ^15.3.0 || ^16.0.0-alpha react-dom: ^15.3.0 || ^16.0.0-alpha @@ -428,8 +428,8 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} - '@eamodio/eslint-lite-webpack-plugin@0.3.2': - resolution: {integrity: sha512-vTjob+y8He0tiRSplYngmRF6cqBKau5MKWH67HGPU7UtMS9PVs+6oIBPsdwEeWvCHrM6AIiPjWKv8T2R+sQ6Bg==} + '@eamodio/eslint-lite-webpack-plugin@0.3.3': + resolution: {integrity: sha512-cXBm16OFztEv3ngaGopLLo15qUJaLs3h+qiKzUEV5cQzGj/A9kY0mGkAwA4CKIrEkC+L4ZPN5ji+W2JipF7n1Q==} engines: {node: '>= 22.12.0', pnpm: '>= 10.0.0'} peerDependencies: eslint: ^9.23.0 @@ -1647,9 +1647,6 @@ packages: '@types/warning@3.0.3': resolution: {integrity: sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==} - '@types/webpack@5.28.5': - resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==} - '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -6549,18 +6546,11 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} - '@eamodio/eslint-lite-webpack-plugin@0.3.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(eslint@9.37.0(jiti@2.4.0))(webpack-cli@6.0.1)(webpack@5.102.1)': + '@eamodio/eslint-lite-webpack-plugin@0.3.3(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1)': dependencies: - '@types/eslint': 9.6.1 - '@types/webpack': 5.28.5(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) eslint: 9.37.0(jiti@2.4.0) minimatch: 10.0.3 webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli '@emnapi/core@1.5.0': dependencies: @@ -7627,17 +7617,6 @@ snapshots: '@types/warning@3.0.3': {} - '@types/webpack@5.28.5(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1)': - dependencies: - '@types/node': 20.16.15 - tapable: 2.3.0 - webpack: 5.102.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.10)(webpack-cli@6.0.1) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fe45a55ee2ab1..19108aab17898 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,6 @@ minimumReleaseAge: 10080 minimumReleaseAgeExclude: + - '@eamodio/eslint-lite-webpack-plugin' - '@gitkraken/*' - '@typescript-eslint/*' - 'typescript-eslint' diff --git a/webpack.config.mjs b/webpack.config.mjs index 0961d31163cf0..34b4f2d08c3a5 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -485,6 +485,19 @@ function getWebviewConfig(webviews, overrides, mode, env) { ); } + if (!env.skipLint) { + plugins.push( + new ESLintLitePlugin({ + files: path.join(basePath, '**', '*.ts?(x)'), + worker: eslintWorker, + eslintOptions: { + ...eslintOptions, + cacheLocation: path.join(__dirname, '.eslintcache', 'webviews/'), + }, + }), + ); + } + let name = ''; let filePrefix = ''; if (Object.keys(webviews).length > 1) { From 67a31bf658e817604458f6c421009e82c3f7990e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 23 Oct 2025 22:27:40 -0400 Subject: [PATCH 66/83] Tweaks with a failed caching attempt --- webpack.config.mjs | 130 ++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/webpack.config.mjs b/webpack.config.mjs index 34b4f2d08c3a5..8dd21bd9ae1f6 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -41,6 +41,7 @@ const eslintOptions = { // concurrency: 'auto', }; +const useAsyncTypeChecking = false; const useNpm = Boolean(process.env.GL_USE_NPM); if (useNpm) { console.log('Using npm to run scripts'); @@ -87,6 +88,25 @@ const stats = { timings: true, }; +/** + * @param {string} name + * @param { 'node' | 'webworker' } target + * @param { 'production' | 'development' | 'none' } mode + * @returns { WebpackConfig['cache'] } + */ +function getCacheConfig(name, target, mode) { + return undefined; + // Attempt at caching to improve build times, but it doesn't seem to help much if at all + // return { + // type: 'filesystem', + // cacheDirectory: path.join(__dirname, '.webpack-cache'), + // buildDependencies: { + // config: [__filename], + // }, + // name: `${name}-${target}-${mode}`, // Unique per config + // }; +} + /** * @param { 'production' | 'development' | 'none' } mode * @param {{ analyzeBundle?: boolean; analyzeDeps?: boolean; esbuild?: boolean; skipLint?: boolean }} env @@ -133,6 +153,7 @@ function getCommonConfig(mode, env) { plugins: plugins, infrastructureLogging: mode === 'production' ? undefined : { level: 'log' }, // enables logging required for problem matchers stats: stats, + cache: getCacheConfig('common', 'node', mode), }; } @@ -154,10 +175,11 @@ function getExtensionConfig(target, mode, env) { DEBUG: mode === 'development', }), new ForkTsCheckerPlugin({ - async: false, + async: useAsyncTypeChecking, formatter: 'basic', typescript: { configFile: tsConfigPath, + memoryLimit: 4096, }, }), ]; @@ -322,6 +344,7 @@ function getExtensionConfig(target, mode, env) { plugins: plugins, infrastructureLogging: mode === 'production' ? undefined : { level: 'log' }, // enables logging required for problem matchers stats: stats, + cache: getCacheConfig('extension', target, mode), }; } @@ -440,6 +463,7 @@ function getWebviewsCommonConfig(mode, env) { plugins: plugins, infrastructureLogging: mode === 'production' ? undefined : { level: 'log' }, // enables logging required for problem matchers stats: stats, + cache: getCacheConfig('webviews-common', 'webworker', mode), }; } @@ -460,10 +484,11 @@ function getWebviewConfig(webviews, overrides, mode, env) { DEBUG: mode === 'development', }), new ForkTsCheckerPlugin({ - async: false, + async: useAsyncTypeChecking, formatter: 'basic', typescript: { configFile: tsConfigPath, + memoryLimit: 4096, }, }), new WebpackRequireFromPlugin({ @@ -673,6 +698,7 @@ function getWebviewConfig(webviews, overrides, mode, env) { plugins: plugins, infrastructureLogging: mode === 'production' ? undefined : { level: 'log' }, // enables logging required for problem matchers stats: stats, + cache: getCacheConfig(name, 'webworker', mode), }; } @@ -762,52 +788,52 @@ function getHtmlPlugin(name, plus, mode, env) { }); } -class InlineChunkHtmlPlugin { - constructor(htmlPlugin, patterns) { - this.htmlPlugin = htmlPlugin; - this.patterns = patterns; - } - - getInlinedTag(publicPath, assets, tag) { - if ( - (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) && - (tag.tagName !== 'link' || !(tag.attributes && tag.attributes.href)) - ) { - return tag; - } - - let chunkName = tag.tagName === 'link' ? tag.attributes.href : tag.attributes.src; - if (publicPath) { - chunkName = chunkName.replace(publicPath, ''); - } - if (!this.patterns.some(pattern => chunkName.match(pattern))) { - return tag; - } - - const asset = assets[chunkName]; - if (asset == null) { - return tag; - } - - return { tagName: tag.tagName === 'link' ? 'style' : tag.tagName, innerHTML: asset.source(), closeTag: true }; - } - - apply(compiler) { - let publicPath = compiler.options.output.publicPath || ''; - if (publicPath && !publicPath.endsWith('/')) { - publicPath += '/'; - } - - compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => { - const getInlinedTagFn = tag => this.getInlinedTag(publicPath, compilation.assets, tag); - const sortFn = (a, b) => (a.tagName === 'script' ? 1 : -1) - (b.tagName === 'script' ? 1 : -1); - this.htmlPlugin.getHooks(compilation).alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => { - assets.headTags = assets.headTags.map(getInlinedTagFn).sort(sortFn); - assets.bodyTags = assets.bodyTags.map(getInlinedTagFn).sort(sortFn); - }); - }); - } -} +// class InlineChunkHtmlPlugin { +// constructor(htmlPlugin, patterns) { +// this.htmlPlugin = htmlPlugin; +// this.patterns = patterns; +// } + +// getInlinedTag(publicPath, assets, tag) { +// if ( +// (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) && +// (tag.tagName !== 'link' || !(tag.attributes && tag.attributes.href)) +// ) { +// return tag; +// } + +// let chunkName = tag.tagName === 'link' ? tag.attributes.href : tag.attributes.src; +// if (publicPath) { +// chunkName = chunkName.replace(publicPath, ''); +// } +// if (!this.patterns.some(pattern => chunkName.match(pattern))) { +// return tag; +// } + +// const asset = assets[chunkName]; +// if (asset == null) { +// return tag; +// } + +// return { tagName: tag.tagName === 'link' ? 'style' : tag.tagName, innerHTML: asset.source(), closeTag: true }; +// } + +// apply(compiler) { +// let publicPath = compiler.options.output.publicPath || ''; +// if (publicPath && !publicPath.endsWith('/')) { +// publicPath += '/'; +// } + +// compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => { +// const getInlinedTagFn = tag => this.getInlinedTag(publicPath, compilation.assets, tag); +// const sortFn = (a, b) => (a.tagName === 'script' ? 1 : -1) - (b.tagName === 'script' ? 1 : -1); +// this.htmlPlugin.getHooks(compilation).alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => { +// assets.headTags = assets.headTags.map(getInlinedTagFn).sort(sortFn); +// assets.bodyTags = assets.bodyTags.map(getInlinedTagFn).sort(sortFn); +// }); +// }); +// } +// } const schema = { type: 'object', @@ -858,6 +884,9 @@ class FileGeneratorPlugin { return changed; } + /** + * @param {import("webpack").Compiler} compiler + */ apply(compiler) { let pendingGeneration = false; @@ -993,6 +1022,9 @@ class LicensesPlugin extends FileGeneratorPlugin { class FantasticonPlugin { alreadyRun = false; + /** + * @param {{config?: { [key:string]: any }; configPath?: string; onBefore?: Function; onComplete?: Function }} options + */ constructor(options = {}) { this.pluginName = 'fantasticon'; this.options = options; @@ -1082,7 +1114,9 @@ class FantasticonPlugin { } const generateFn = generate.bind(this); + // @ts-ignore compiler.hooks.beforeRun.tapPromise(this.pluginName, generateFn); + // @ts-ignore compiler.hooks.watchRun.tapPromise(this.pluginName, generateFn); } } From e3e7c9966ad2e8d8d32965b177372b2a60c91284 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 13:32:42 -0400 Subject: [PATCH 67/83] Fixes missing spinners on the Graph --- src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts | 1 + src/webviews/apps/plus/graph/graph.scss | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts b/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts index 7673cfaa1e14c..e4c868dce1a25 100644 --- a/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts +++ b/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts @@ -140,6 +140,7 @@ export class GlGraphWrapper extends SignalWatcher(LitElement) { .refsMetadata=${graphState.refsMetadata} .rows=${graphState.rows} .rowsStats=${graphState.rowsStats} + ?rowsStatsLoading=${graphState.rowsStatsLoading} .searchResults=${graphState.searchResults} .selectedRows=${graphState.selectedRows} .theming=${this.theming} diff --git a/src/webviews/apps/plus/graph/graph.scss b/src/webviews/apps/plus/graph/graph.scss index 346a8c10e815c..06fabdc2c5118 100644 --- a/src/webviews/apps/plus/graph/graph.scss +++ b/src/webviews/apps/plus/graph/graph.scss @@ -1129,6 +1129,10 @@ web-graph { margin-top: 0.1rem; } + .columns-btn.spinner { + margin-right: 0.6rem; + } + .button { background-color: var(--color-graph-actionbar-background); color: var(--color-graph-text-disabled, hsla(0deg, 0%, 100%, 0.4)); @@ -1465,3 +1469,5 @@ web-graph { height: 100%; } } + +@import '../../shared/codicons'; From 0937f6d83ac82c690a8ff708206daee39614e273 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 16:44:09 -0400 Subject: [PATCH 68/83] Tweaks logging --- src/git/models/repository.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 8a44eb4a8e459..ec2378834b323 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -692,7 +692,7 @@ export class Repository implements Disposable { // If we've come back into focus and we are dirty, fire the change events if (this._pendingRepoChange != null) { - Logger.debug(scope, `Firing pending repo changes: ${this._pendingRepoChange.toString(true)}`); + Logger.debug(scope, `Firing pending repo ${this._pendingRepoChange.toString(true)}`); this._fireChangeDebounced?.(); } @@ -878,7 +878,7 @@ export class Repository implements Disposable { this.providerService.onRepositoryChanged(this, this._pendingRepoChange); if (this._suspended) { - Logger.debug(scope, `SUSPENDED: queueing repo changes=${this._pendingRepoChange.toString(true)}`); + Logger.debug(scope, `SUSPENDED: queueing repo ${this._pendingRepoChange.toString(true)}`); return; } @@ -896,7 +896,7 @@ export class Repository implements Disposable { this._pendingRepoChange = undefined; - Logger.debug(scope, `firing repo changes=${e.toString(true)}`); + Logger.debug(scope, `firing repo ${e.toString(true)}`); try { this._onDidChange.fire(e); } finally { From a446f104344ae68559b1852e6c3c060f2bafa406 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 16:46:35 -0400 Subject: [PATCH 69/83] Changes UT to use vscode stable - Aligns with e2e tests --- .vscode-test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode-test.mjs b/.vscode-test.mjs index e894ab22db40b..5c6e0ad583b11 100644 --- a/.vscode-test.mjs +++ b/.vscode-test.mjs @@ -4,7 +4,7 @@ export default defineConfig([ { label: 'Unit Tests', files: 'out/tests/**/*.test.js', - version: 'insiders', + version: 'stable', mocha: { ui: 'tdd', timeout: 20000, From 9ccbd9f3f15ec332e92eb27e59d131a4784d093e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 16:53:14 -0400 Subject: [PATCH 70/83] Adds quick build for webviews --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 12645285c7fc1..68da74e0c8432 100644 --- a/package.json +++ b/package.json @@ -25883,6 +25883,7 @@ "build:extension": "webpack --mode development --config-name extension:node", "build:extension:browser": "webpack --mode development --config-name extension:webworker", "build:webviews": "node ./scripts/compile-composer-templates.mjs && webpack --mode development --config-name webviews:common --config-name webviews", + "build:webviews:quick": "node ./scripts/compile-composer-templates.mjs && webpack --mode development --config-name webviews:common --config-name webviews --env skipLint", "build:icons": "pnpm run icons:svgo && pnpm fantasticon && pnpm run icons:apply && pnpm run icons:export", "build:tests": "node ./scripts/esbuild.tests.mjs", "// Extracts the contributions from package.json into contributions.json": "//", From dac329decb2c9ef3a5482c027733e76466d6a122 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 18:01:41 -0400 Subject: [PATCH 71/83] Fixes stuck indicator on Visual History --- src/webviews/apps/plus/timeline/components/chart.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webviews/apps/plus/timeline/components/chart.ts b/src/webviews/apps/plus/timeline/components/chart.ts index 3207290ecb4fe..abca6d8fa95a5 100644 --- a/src/webviews/apps/plus/timeline/components/chart.ts +++ b/src/webviews/apps/plus/timeline/components/chart.ts @@ -173,7 +173,11 @@ export class GlTimelineChart extends GlElement { this.emit('gl-loading', this._loading.promise); } - if (this.dataPromise == null) return; + if (this.dataPromise == null) { + // Fulfill the loading promise since there's no data to load + this._loading?.fulfill(); + return; + } this._chartAborter?.abort(); this._chartAborter = new AbortController(); From 408ca1e4db0f629239c7e1f3257d6683e20350b2 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 18:21:32 -0400 Subject: [PATCH 72/83] Ensures immediate fire of repository close events - Hoping to address some possible deadlock issues --- src/git/models/repository.ts | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index ec2378834b323..9236790df3cd3 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -274,7 +274,14 @@ export class Repository implements Disposable { using scope = startLogScope(`${getLoggableName(this)}.closed`, false); Logger.debug(scope, `setting closed=${value}`); void this.getGitDir().then(gd => this.setupRepoWatchers(gd)); - this.fireChange(this._closed ? RepositoryChange.Closed : RepositoryChange.Opened); + + if (this._closed) { + // When closing, fire the event immediately even if suspended + // This ensures views can clean up nodes for closed repositories before VS Code tries to render them + this.fireChange(RepositoryChange.Closed, true); + } else { + this.fireChange(RepositoryChange.Opened); + } } } @@ -865,14 +872,34 @@ export class Repository implements Disposable { this._fireFileSystemChangeDebounced = undefined; } + private fireChange(...changes: RepositoryChange[]): void; + private fireChange(change: RepositoryChange, force: boolean): void; @debug() - private fireChange(...changes: RepositoryChange[]) { + private fireChange(...args: RepositoryChange[] | [RepositoryChange, boolean]): void { const scope = getLogScope(); + // Extract force flag if present (last argument is boolean) + const lastArg = args[args.length - 1]; + const force = typeof lastArg === 'boolean' ? lastArg : false; + const changes = (force ? args.slice(0, -1) : args) as RepositoryChange[]; + this._updatedAt = Date.now(); - this._fireChangeDebounced ??= debounce(this.fireChangeCore.bind(this), defaultRepositoryChangeDelay); + if (force) { + // Cancel any pending debounced fire and clear the queue + this._fireChangeDebounced?.cancel(); + this._fireChangeDebounced = undefined; + + // Set the pending change and fire immediately, bypassing suspension + this._pendingRepoChange = new RepositoryChangeEvent(this, changes); + this.providerService.onRepositoryChanged(this, this._pendingRepoChange); + this.fireChangeCore(); + + return; + } + + this._fireChangeDebounced ??= debounce(this.fireChangeCore.bind(this), defaultRepositoryChangeDelay); this._pendingRepoChange = this._pendingRepoChange?.with(changes) ?? new RepositoryChangeEvent(this, changes); this.providerService.onRepositoryChanged(this, this._pendingRepoChange); From 550ec8f86ede762a460508da8295664859fe886b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 24 Oct 2025 18:40:15 -0400 Subject: [PATCH 73/83] Adds more gate logging --- src/system/decorators/gate.ts | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/system/decorators/gate.ts b/src/system/decorators/gate.ts index c5b239ad6c726..1a80d729dc0d2 100644 --- a/src/system/decorators/gate.ts +++ b/src/system/decorators/gate.ts @@ -39,10 +39,34 @@ export function gate any>(resolver?: (...args: Parame void promise.finally(() => (this[prop] = undefined)); // Log if gate takes too long to resolve - const timeout = setTimeout(() => { - Logger.warn(`[gate] ${key} has been pending for 60+ seconds (possible deadlock)`, `prop=${prop}`); + let timeout = setTimeout(() => { + Logger.warn(`[gate] ${key} has been pending for 120+ seconds (possible deadlock)`, `prop=${prop}`); getTelementryService()?.sendEvent('op/gate/deadlock', { key: key, prop: prop, timeout: 60000 }); - }, 60000); + + timeout = setTimeout(() => { + Logger.warn( + `[gate] ${key} has still been pending for 420+ seconds (possible deadlock)`, + `prop=${prop}`, + ); + getTelementryService()?.sendEvent('op/gate/deadlock', { + key: key, + prop: prop, + timeout: 420000, + }); + + timeout = setTimeout(() => { + Logger.warn( + `[gate] ${key} has still been pending for 900+ seconds (possible deadlock)`, + `prop=${prop}`, + ); + getTelementryService()?.sendEvent('op/gate/deadlock', { + key: key, + prop: prop, + timeout: 900000, + }); + }, 480000); + }, 300000); + }, 120000); void promise.finally(() => clearTimeout(timeout)); } From d29a6bac201953eff3f3b649f083f6003ed4f759 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 25 Oct 2025 02:59:18 -0400 Subject: [PATCH 74/83] Fixes stats counts --- src/git/models/commit.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/git/models/commit.ts b/src/git/models/commit.ts index 3603991134d16..264901769fb4c 100644 --- a/src/git/models/commit.ts +++ b/src/git/models/commit.ts @@ -316,8 +316,21 @@ export class GitCommit implements GitRevisionReference { } if (options?.include?.stats) { + this._recomputeStats = true; + this.computeFileStats(); + const stats = await repo?.git.diff.getChangedFilesCount(this.sha); - this._stats = stats; + if (stats != null) { + if (this._stats != null) { + this._stats = { + ...this._stats, + additions: stats.additions, + deletions: stats.deletions, + }; + } else { + this._stats = stats; + } + } this._recomputeStats = false; } else { this._recomputeStats = true; @@ -357,11 +370,7 @@ export class GitCommit implements GitRevisionReference { if (!this._recomputeStats || this.fileset == null) return; this._recomputeStats = false; - const changedFiles = { - added: 0, - deleted: 0, - changed: 0, - }; + const changedFiles = { added: 0, deleted: 0, changed: 0 }; let additions = 0; let deletions = 0; From 42acfc8cf1b1f43377640b834d4858fdc49263ec Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 25 Oct 2025 03:19:18 -0400 Subject: [PATCH 75/83] Improves worktree status performance --- src/commands/git/worktree.ts | 6 +- src/commands/quickCommand.steps.ts | 11 +- src/git/models/status.ts | 54 +--- src/git/models/worktree.ts | 29 +- src/git/utils/-webview/worktree.quickpick.ts | 43 ++- src/git/utils/status.utils.ts | 51 +++ src/views/nodes/UncommittedFilesNode.ts | 26 +- src/views/nodes/worktreeNode.ts | 323 ++++++++++--------- 8 files changed, 290 insertions(+), 253 deletions(-) diff --git a/src/commands/git/worktree.ts b/src/commands/git/worktree.ts index 998ca16e3667e..f016b70ab8167 100644 --- a/src/commands/git/worktree.ts +++ b/src/commands/git/worktree.ts @@ -887,12 +887,12 @@ export class WorktreeGitCommand extends QuickCommand { try { if (force) { - let status; + let hasChanges; try { - status = await worktree?.getStatus(); + hasChanges = await worktree?.hasWorkingChanges(); } catch {} - if ((status?.hasChanges ?? false) && !skipHasChangesPrompt) { + if ((hasChanges ?? false) && !skipHasChangesPrompt) { const confirm: MessageItem = { title: 'Force Delete' }; const cancel: MessageItem = { title: 'Cancel', isCloseAffordance: true }; const result = await window.showWarningMessage( diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index b392e457f7062..1a277b2681c8e 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -262,10 +262,10 @@ export async function getWorktrees( if ((excludeOpened && w.opened) || filter?.(w) === false) return undefined; let missing = false; - let status; + let hasChanges; if (includeStatus) { try { - status = await w.getStatus(); + hasChanges = await w.hasWorkingChanges(); } catch (ex) { Logger.error(ex, `Worktree status failed: ${w.uri.toString(true)}`); missing = true; @@ -277,12 +277,7 @@ export async function getWorktrees( picked != null && (typeof picked === 'string' ? w.uri.toString() === picked : picked.includes(w.uri.toString())), missing, - { - buttons: buttons, - includeStatus: includeStatus, - path: true, - status: status, - }, + { buttons: buttons, hasChanges: hasChanges, includeStatus: includeStatus, path: true }, ); }), ), diff --git a/src/git/models/status.ts b/src/git/models/status.ts index c37656467c6c7..96a837fc48dc4 100644 --- a/src/git/models/status.ts +++ b/src/git/models/status.ts @@ -1,8 +1,7 @@ import type { Container } from '../../container'; import { memoize } from '../../system/decorators/memoize'; -import { pluralize } from '../../system/string'; import { formatDetachedHeadName, getRemoteNameFromBranchName, isDetachedHead } from '../utils/branch.utils'; -import { getUpstreamStatus } from '../utils/status.utils'; +import { getFormattedDiffStatus, getUpstreamStatus } from '../utils/status.utils'; import type { GitBranchStatus, GitTrackingUpstream } from './branch'; import type { GitDiffFileStats } from './diff'; import { GitFileConflictStatus, GitFileIndexStatus, GitFileWorkingTreeStatus } from './fileStatus'; @@ -175,11 +174,7 @@ export class GitStatus { @memoize() getDiffStatus(): GitDiffFileStats { - const diff = { - added: 0, - deleted: 0, - changed: 0, - }; + const diff = { added: 0, deleted: 0, changed: 0 }; if (this.files.length === 0) return diff; @@ -201,54 +196,15 @@ export class GitStatus { return diff; } - getFormattedDiffStatus({ - compact, - empty, - expand, - prefix = '', - separator = ' ', - suffix = '', - }: { + getFormattedDiffStatus(options?: { compact?: boolean; empty?: string; expand?: boolean; prefix?: string; separator?: string; suffix?: string; - } = {}): string { - const { added, changed, deleted } = this.getDiffStatus(); - if (added === 0 && changed === 0 && deleted === 0) return empty ?? ''; - - if (expand) { - let status = ''; - if (added) { - status += `${pluralize('file', added)} added`; - } - if (changed) { - status += `${status.length === 0 ? '' : separator}${pluralize('file', changed)} changed`; - } - if (deleted) { - status += `${status.length === 0 ? '' : separator}${pluralize('file', deleted)} deleted`; - } - return `${prefix}${status}${suffix}`; - } - - let status = ''; - if (compact) { - if (added !== 0) { - status += `+${added}`; - } - if (changed !== 0) { - status += `${status.length === 0 ? '' : separator}~${changed}`; - } - if (deleted !== 0) { - status += `${status.length === 0 ? '' : separator}-${deleted}`; - } - } else { - status += `+${added}${separator}~${changed}${separator}-${deleted}`; - } - - return `${prefix}${status}${suffix}`; + }): string { + return getFormattedDiffStatus(this.getDiffStatus(), options); } @memoize() diff --git a/src/git/models/worktree.ts b/src/git/models/worktree.ts index 4f3783c265456..d8fe07be3dba5 100644 --- a/src/git/models/worktree.ts +++ b/src/git/models/worktree.ts @@ -53,8 +53,9 @@ export class GitWorktree { : this.formatDateFromNow(); } + private _hasWorkingChanges: boolean | undefined; get hasChanges(): boolean | undefined { - return this._status?.hasChanges; + return this._hasWorkingChanges; } get opened(): boolean { @@ -86,7 +87,6 @@ export class GitWorktree { return this.date != null ? fromNow(this.date) : ''; } - private _status: GitStatus | undefined; private _statusPromise: Promise | undefined; async getStatus(options?: { force?: boolean }): Promise { if (this.type === 'bare') return Promise.resolve(undefined); @@ -96,7 +96,9 @@ export class GitWorktree { this._statusPromise = new Promise(async (resolve, reject) => { try { const status = await this.container.git.getRepositoryService(this.uri.fsPath).status.getStatus(); - this._status = status; + if (status != null) { + this._hasWorkingChanges = status.hasChanges; + } resolve(status); } catch (ex) { // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors @@ -106,6 +108,27 @@ export class GitWorktree { } return this._statusPromise; } + + private _hasWorkingChangesPromise: Promise | undefined; + async hasWorkingChanges(options?: { + force?: boolean; + staged?: boolean; + unstaged?: boolean; + untracked?: boolean; + }): Promise { + if (this.type === 'bare') return Promise.resolve(undefined); + + if (this._hasWorkingChangesPromise == null || options?.force) { + this._hasWorkingChangesPromise = this.container.git + .getRepositoryService(this.uri.fsPath) + .status?.hasWorkingChanges({ + staged: options?.staged, + unstaged: options?.unstaged, + untracked: options?.untracked, + }); + } + return this._hasWorkingChangesPromise; + } } export function isWorktree(worktree: any): worktree is GitWorktree { diff --git a/src/git/utils/-webview/worktree.quickpick.ts b/src/git/utils/-webview/worktree.quickpick.ts index 8f6b80564e728..50956d77947b6 100644 --- a/src/git/utils/-webview/worktree.quickpick.ts +++ b/src/git/utils/-webview/worktree.quickpick.ts @@ -4,7 +4,6 @@ import { GlyphChars } from '../../../constants'; import { Container } from '../../../container'; import type { QuickPickItemOfT } from '../../../quickpicks/items/common'; import { pad } from '../../../system/string'; -import type { GitStatus } from '../../models/status'; import type { GitWorktree } from '../../models/worktree'; import { shortenRevision } from '../revision.utils'; import { getBranchIconPath } from './icons'; @@ -22,11 +21,11 @@ export function createWorktreeQuickPickItem( alwaysShow?: boolean; buttons?: QuickInputButton[]; checked?: boolean; + hasChanges?: boolean | undefined; includeStatus?: boolean; message?: boolean; path?: boolean; type?: boolean; - status?: GitStatus; }, ): WorktreeQuickPickItem { let description = ''; @@ -38,31 +37,27 @@ export function createWorktreeQuickPickItem( if (options?.includeStatus) { let status = ''; let blank = 0; - if (options?.status != null) { - if (options.status.upstream?.missing) { - status += GlyphChars.Warning; - blank += 3; + if (worktree.branch?.upstream?.missing) { + status += GlyphChars.Warning; + blank += 3; + } else { + if (worktree.branch?.upstream?.state.behind) { + status += GlyphChars.ArrowDown; } else { - if (options.status.upstream?.state.behind) { - status += GlyphChars.ArrowDown; - } else { - blank += 2; - } + blank += 2; + } - if (options.status.upstream?.state.ahead) { - status += GlyphChars.ArrowUp; - } else { - blank += 2; - } + if (worktree.branch?.upstream?.state.ahead) { + status += GlyphChars.ArrowUp; + } else { + blank += 2; + } - if (options.status.hasChanges) { - status += '\u00B1'; - } else { - blank += 2; - } + if (options?.hasChanges) { + status += '\u00B1'; + } else { + blank += 2; } - } else { - blank += 6; } if (blank > 0) { @@ -112,8 +107,8 @@ export function createWorktreeQuickPickItem( buttons: options?.buttons, picked: picked, item: worktree, + hasChanges: options?.hasChanges, opened: worktree.opened, - hasChanges: options?.status?.hasChanges, iconPath: iconPath, }; diff --git a/src/git/utils/status.utils.ts b/src/git/utils/status.utils.ts index 6a81384a2196c..a27fe4be82f0c 100644 --- a/src/git/utils/status.utils.ts +++ b/src/git/utils/status.utils.ts @@ -1,6 +1,57 @@ import { GlyphChars } from '../../constants'; import { pluralize } from '../../system/string'; import type { GitTrackingUpstream } from '../models/branch'; +import type { GitDiffFileStats } from '../models/diff'; + +export function getFormattedDiffStatus( + stats: GitDiffFileStats, + options?: { + compact?: boolean; + empty?: string; + expand?: boolean; + prefix?: string; + separator?: string; + suffix?: string; + }, +): string { + const { added, changed, deleted } = stats; + if (added === 0 && changed === 0 && deleted === 0) return options?.empty ?? ''; + + const prefix = options?.prefix ?? ''; + const separator = options?.separator ?? ' '; + const suffix = options?.suffix ?? ''; + + if (options?.expand) { + let status = ''; + if (added) { + status += `${pluralize('file', added)} added`; + } + if (changed) { + status += `${status.length === 0 ? '' : separator}${pluralize('file', changed)} changed`; + } + if (deleted) { + status += `${status.length === 0 ? '' : separator}${pluralize('file', deleted)} deleted`; + } + return `${prefix}${status}${suffix}`; + } + + let status = ''; + if (options?.compact) { + if (added !== 0) { + status += `+${added}`; + } + if (changed !== 0) { + status += `${status.length === 0 ? '' : separator}~${changed}`; + } + if (deleted !== 0) { + status += `${status.length === 0 ? '' : separator}-${deleted}`; + } + } else { + status += `+${added}${separator}~${changed}${separator}-${deleted}`; + } + + return `${prefix}${status}${suffix}`; +} export function getUpstreamStatus( upstream: GitTrackingUpstream | undefined, diff --git a/src/views/nodes/UncommittedFilesNode.ts b/src/views/nodes/UncommittedFilesNode.ts index 6341b90055775..b6ba0176695b3 100644 --- a/src/views/nodes/UncommittedFilesNode.ts +++ b/src/views/nodes/UncommittedFilesNode.ts @@ -1,11 +1,10 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { GitUri } from '../../git/gitUri'; -import type { GitTrackingState } from '../../git/models/branch'; import type { GitFileWithCommit } from '../../git/models/file'; import type { GitStatus } from '../../git/models/status'; -import type { GitStatusFile } from '../../git/models/statusFile'; import { makeHierarchical } from '../../system/array'; import { flatMap, groupBy } from '../../system/iterable'; +import type { Lazy } from '../../system/lazy'; import { joinPaths, normalizePath } from '../../system/path'; import type { ViewsWithWorkingTree } from '../viewBase'; import { ContextValues, getViewNodeId, ViewNode } from './abstract/viewNode'; @@ -17,17 +16,11 @@ export class UncommittedFilesNode extends ViewNode<'uncommitted-files', ViewsWit constructor( view: ViewsWithWorkingTree, protected override readonly parent: ViewNode, - public readonly status: - | GitStatus - | { - readonly repoPath: string; - readonly files: GitStatusFile[]; - readonly state: GitTrackingState; - readonly upstream?: string; - }, + public readonly repoPath: string, + private readonly status: Lazy>, public readonly range: string | undefined, ) { - super('uncommitted-files', GitUri.fromRepoPath(status.repoPath), view, parent); + super('uncommitted-files', GitUri.fromRepoPath(repoPath), view, parent); this._uniqueId = getViewNodeId(this.type, this.context); } @@ -36,15 +29,14 @@ export class UncommittedFilesNode extends ViewNode<'uncommitted-files', ViewsWit return this._uniqueId; } - get repoPath(): string { - return this.status.repoPath; - } - - getChildren(): ViewNode[] { + async getChildren(): Promise { const repoPath = this.repoPath; + const status = await this.status.value; + if (status == null) return []; + const files: GitFileWithCommit[] = [ - ...flatMap(this.status.files, f => { + ...flatMap(status.files, f => { const commits = f.getPseudoCommits(this.view.container, undefined); return commits.map( c => diff --git a/src/views/nodes/worktreeNode.ts b/src/views/nodes/worktreeNode.ts index e6a88941dbdbb..9bda60c544bef 100644 --- a/src/views/nodes/worktreeNode.ts +++ b/src/views/nodes/worktreeNode.ts @@ -1,3 +1,4 @@ +import type { CancellationToken } from 'vscode'; import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, window } from 'vscode'; import type { IconPath } from '../../@types/vscode.iconpath'; import { GlyphChars } from '../../constants'; @@ -17,6 +18,8 @@ import { getBestPath } from '../../system/-webview/path'; import { gate } from '../../system/decorators/gate'; import { debug, log } from '../../system/decorators/log'; import { map } from '../../system/iterable'; +import type { Lazy } from '../../system/lazy'; +import { lazy } from '../../system/lazy'; import { Logger } from '../../system/logger'; import type { Deferred } from '../../system/promise'; import { defer, getSettledValue, pauseOnCancelOrTimeout } from '../../system/promise'; @@ -43,6 +46,7 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit limit: number | undefined; private _branch: GitBranch | undefined; + private _lazyStatus: Lazy> | undefined; constructor( uri: GitUri, @@ -194,9 +198,12 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit children.push(new LoadMoreNode(this.view, this, children[children.length - 1])); } - const { status } = await this.getStatus(); - if (status?.hasChanges) { - children.unshift(new UncommittedFilesNode(this.view, this, status, undefined)); + const { hasChanges } = await this.hasWorkingChanges(); + if (hasChanges) { + this._lazyStatus ??= lazy(() => this.worktree.getStatus()); + children.unshift( + new UncommittedFilesNode(this.view, this, this.worktree.uri.fsPath, this._lazyStatus, undefined), + ); } this.children = children; @@ -209,28 +216,13 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit async getTreeItem(): Promise { let description = ''; let icon: IconPath | undefined; - let hasChanges = false; - const tooltip = new MarkdownString('', true); - tooltip.isTrusted = true; - - const indicators = - this.worktree.isDefault || this.worktree.opened - ? ` \u00a0(${ - this.worktree.isDefault - ? `_default${this.worktree.opened ? ', active_' : '_'}` - : this.worktree.opened - ? '_active_' - : '' - })` - : ''; - - let status: GitStatus | undefined; + let hasChanges: boolean | undefined; let missing = false; - const result = await pauseOnCancelOrTimeout(this.getStatus(), undefined, 1); + const result = await pauseOnCancelOrTimeout(this.hasWorkingChanges(), undefined, 1); if (!result.paused) { - ({ status, missing } = result.value); + ({ hasChanges, missing } = result.value); } else { queueMicrotask(() => { void result.value.then(() => { @@ -239,155 +231,70 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit }); } - const folder = `\\\n$(folder) [\`${ - this.worktree.friendlyPath - }\`](command:gitlens.views.revealWorktreeInExplorer?%22${this.worktree.uri.toString()}%22 "Reveal in Explorer")`; - const { viewAs } = this.view.config.worktrees; switch (this.worktree.type) { case 'bare': icon = new ThemeIcon('folder'); - tooltip.appendMarkdown( - `${this.worktree.isDefault ? '$(pass) ' : ''}Bare Worktree${indicators}${folder}`, - ); break; case 'branch': { const { branch } = this.worktree; this._branch = branch; - tooltip.appendMarkdown( - `${this.worktree.isDefault ? '$(pass) ' : ''}Worktree for $(git-branch) \`${ - branch?.getNameWithoutRemote() ?? branch?.name - }\`${indicators}${folder}`, - ); icon = getBranchIconPath(this.view.container, branch); - if (branch != null) { - if (!branch.remote) { - if (branch.upstream != null) { - let arrows = GlyphChars.Dash; - - const remote = await branch.getRemote(); - if (!branch.upstream.missing) { - if (remote != null) { - let left; - let right; - for (const { type } of remote.urls) { - if (type === 'fetch') { - left = true; - - if (right) break; - } else if (type === 'push') { - right = true; - - if (left) break; - } - } - - if (left && right) { - arrows = GlyphChars.ArrowsRightLeft; - } else if (right) { - arrows = GlyphChars.ArrowRight; - } else if (left) { - arrows = GlyphChars.ArrowLeft; - } + if (branch != null && !branch.remote && branch.upstream != null) { + let arrows = GlyphChars.Dash; + + const remote = await branch.getRemote(); + if (!branch.upstream.missing) { + if (remote != null) { + let left; + let right; + for (const { type } of remote.urls) { + if (type === 'fetch') { + left = true; + + if (right) break; + } else if (type === 'push') { + right = true; + + if (left) break; } - } else { - arrows = GlyphChars.Warning; } - description = `${branch.getTrackingStatus({ - empty: `${viewAs !== 'name' ? ` ${branch.getNameWithoutRemote()}` : ''}${pad( - arrows, - viewAs !== 'name' ? 2 : 0, - 2, - )}`, - suffix: `${viewAs !== 'name' ? ` ${branch.getNameWithoutRemote()}` : ''}${pad( - arrows, - 2, - 2, - )}`, - })}${branch.upstream.name}`; - - tooltip.appendMarkdown( - `\n\nBranch is ${branch.getTrackingStatus({ - empty: `${ - branch.upstream.missing ? 'missing upstream' : 'up to date with' - } \\\n $(git-branch) \`${branch.upstream.name}\`${ - remote?.provider?.name ? ` on ${remote.provider.name}` : '' - }`, - expand: true, - icons: true, - separator: ', ', - suffix: `\\\n$(git-branch) \`${branch.upstream.name}\`${ - remote?.provider?.name ? ` on ${remote.provider.name}` : '' - }`, - })}`, - ); - } else { - const providerName = getHighlanderProviderName( - await this.view.container.git - .getRepositoryService(branch.repoPath) - .remotes.getRemotesWithProviders(), - ); - - tooltip.appendMarkdown( - `\n\nLocal branch, hasn't been published to ${providerName ?? 'a remote'}`, - ); + if (left && right) { + arrows = GlyphChars.ArrowsRightLeft; + } else if (right) { + arrows = GlyphChars.ArrowRight; + } else if (left) { + arrows = GlyphChars.ArrowLeft; + } } + } else { + arrows = GlyphChars.Warning; } - } - if (status != null) { - hasChanges = status.hasChanges; - tooltip.appendMarkdown( - `\n\n${status.getFormattedDiffStatus({ - prefix: 'Has Uncommitted Changes\\\n', - empty: 'No Uncommitted Changes', - expand: true, - })}`, - ); + description = `${branch.getTrackingStatus({ + empty: `${viewAs !== 'name' ? ` ${branch.getNameWithoutRemote()}` : ''}${pad( + arrows, + viewAs !== 'name' ? 2 : 0, + 2, + )}`, + suffix: `${viewAs !== 'name' ? ` ${branch.getNameWithoutRemote()}` : ''}${pad(arrows, 2, 2)}`, + })}${branch.upstream.name}`; } break; } case 'detached': { icon = new ThemeIcon('git-commit'); - tooltip.appendMarkdown( - `${this.worktree.isDefault ? '$(pass) ' : ''}Detached Worktree at $(git-commit) ${shortenRevision( - this.worktree.sha, - )}${indicators}${folder}`, - ); - - if (status != null) { - hasChanges = status.hasChanges; - tooltip.appendMarkdown( - `\n\n${status.getFormattedDiffStatus({ - prefix: 'Has Uncommitted Changes', - empty: 'No Uncommitted Changes', - expand: true, - })}`, - ); - } - break; } } const pendingPullRequest = this.getState('pendingPullRequest'); - if (pendingPullRequest != null) { - tooltip.appendMarkdown(`\n\n$(loading~spin) Loading associated pull request${GlyphChars.Ellipsis}`); - } - - if (missing) { - tooltip.appendMarkdown(`\n\n${GlyphChars.Warning} Unable to locate worktree path`); - } - - if (this.worktree.branch?.starred) { - tooltip.appendMarkdown('\n\n$(star-full) Favorited'); - } let label: string; switch (viewAs) { @@ -421,7 +328,7 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit : this.worktree.opened ? new ThemeIcon('check') : icon; - item.tooltip = tooltip; + // Tooltip will be set lazily in resolveTreeItem item.resourceUri = createViewDecorationUri('worktree', { hasChanges: hasChanges, missing: missing, @@ -431,6 +338,124 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit return item; } + override async resolveTreeItem(item: TreeItem, _token: CancellationToken): Promise { + if (item.tooltip != null) return item; + + const tooltip = new MarkdownString('', true); + tooltip.isTrusted = true; + + const indicators = + this.worktree.isDefault || this.worktree.opened + ? ` \u00a0(${ + this.worktree.isDefault + ? `_default${this.worktree.opened ? ', active_' : '_'}` + : this.worktree.opened + ? '_active_' + : '' + })` + : ''; + + const folder = `\\\n$(folder) [\`${ + this.worktree.friendlyPath + }\`](command:gitlens.views.revealWorktreeInExplorer?%22${this.worktree.uri.toString()}%22 "Reveal in Explorer")`; + + switch (this.worktree.type) { + case 'bare': + tooltip.appendMarkdown( + `${this.worktree.isDefault ? '$(pass) ' : ''}Bare Worktree${indicators}${folder}`, + ); + break; + + case 'branch': { + const { branch } = this.worktree; + tooltip.appendMarkdown( + `${this.worktree.isDefault ? '$(pass) ' : ''}Worktree for $(git-branch) \`${ + branch?.getNameWithoutRemote() ?? branch?.name + }\`${indicators}${folder}`, + ); + + if (branch != null && !branch.remote) { + if (branch.upstream != null) { + const remote = await branch.getRemote(); + tooltip.appendMarkdown( + `\n\nBranch is ${branch.getTrackingStatus({ + empty: `${ + branch.upstream.missing ? 'missing upstream' : 'up to date with' + } \\\n $(git-branch) \`${branch.upstream.name}\`${ + remote?.provider?.name ? ` on ${remote.provider.name}` : '' + }`, + expand: true, + icons: true, + separator: ', ', + suffix: `\\\n$(git-branch) \`${branch.upstream.name}\`${ + remote?.provider?.name ? ` on ${remote.provider.name}` : '' + }`, + })}`, + ); + } else { + const providerName = getHighlanderProviderName( + await this.view.container.git + .getRepositoryService(branch.repoPath) + .remotes.getRemotesWithProviders(), + ); + tooltip.appendMarkdown( + `\n\nLocal branch, hasn't been published to ${providerName ?? 'a remote'}`, + ); + } + } + + break; + } + + case 'detached': + tooltip.appendMarkdown( + `${this.worktree.isDefault ? '$(pass) ' : ''}Detached Worktree at $(git-commit) ${shortenRevision( + this.worktree.sha, + )}${indicators}${folder}`, + ); + + break; + } + + switch (this.worktree.type) { + case 'branch': + case 'detached': { + this._lazyStatus ??= lazy(() => this.worktree.getStatus()); + const status = await this._lazyStatus.value; + const stats = status?.getFormattedDiffStatus({ + prefix: 'Has Uncommitted Changes\\\n', + empty: 'No Uncommitted Changes', + expand: true, + }); + if (stats != null) { + tooltip.appendMarkdown(`\n\n${stats}`); + } + + break; + } + } + + // Add pending pull request indicator + const pendingPullRequest = this.getState('pendingPullRequest'); + if (pendingPullRequest != null) { + tooltip.appendMarkdown(`\n\n$(loading~spin) Loading associated pull request${GlyphChars.Ellipsis}`); + } + + // Add missing worktree warning + const { missing } = await this.hasWorkingChanges(); + if (missing) { + tooltip.appendMarkdown(`\n\n${GlyphChars.Warning} Unable to locate worktree path`); + } + + // Add favorited indicator + if (this.worktree.branch?.starred) { + tooltip.appendMarkdown('\n\n$(star-full) Favorited'); + } + + item.tooltip = tooltip; + return item; + } + @debug() override refresh(reset?: boolean): void | { cancel: boolean } | Promise { if (reset) { @@ -492,19 +517,19 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit return this._log; } - private _status: { status: GitStatus | undefined; missing: boolean } | undefined; - private async getStatus() { - if (this._status == null) { + private _hasWorkingChanges: { hasChanges: boolean | undefined; missing: boolean } | undefined; + private async hasWorkingChanges() { + if (this._hasWorkingChanges == null) { try { - const status = await this.worktree.getStatus(); - this._status = { status: status, missing: false }; + const hasChanges = await this.worktree.hasWorkingChanges(); + this._hasWorkingChanges = { hasChanges: hasChanges, missing: false }; } catch (ex) { - Logger.error(ex, `Worktree status failed: ${this.worktree.uri.toString(true)}`); - this._status = { status: undefined, missing: true }; + Logger.error(ex, `Worktree hasWorkingChanges failed: ${this.worktree.uri.toString(true)}`); + this._hasWorkingChanges = { hasChanges: undefined, missing: true }; } } - return this._status; + return this._hasWorkingChanges; } get hasMore(): boolean { From 5f6858455adca54bcbbe75e7290bba8a3e09b93f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 26 Oct 2025 21:40:43 -0400 Subject: [PATCH 76/83] Updates AGENTS.md --- AGENTS.md | 611 ++++++++++++++++++++++++++++++++++++++++++++---------- CLAUDE.md | 1 + 2 files changed, 506 insertions(+), 106 deletions(-) create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index c0eed5aaedd07..b0728a82d5518 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,199 +1,598 @@ -# GitLens Copilot Instructions +# GitLens Development Guide -This workspace contains **GitLens** - a VS Code extension that supercharges Git functionality. Below are key development guidelines and architecture insights. +This workspace contains **GitLens** - a powerful VS Code extension that supercharges Git functionality. It provides blame annotations, commit history visualization, repository exploration, and many advanced Git workflows. The codebase supports both desktop VS Code (Node.js) and VS Code for Web (browser/webworker) environments. -## Core Commands +## Development Commands + +### Setup + +```bash +pnpm install # Install dependencies (requires Node >= 22.12.0, pnpm >= 10.x) +``` ### Build & Development -- `pnpm run build` - Full development build -- `pnpm run build:quick` - Fast build without linting -- `pnpm run watch` - Watch mode for development -- `pnpm run watch:quick` - Fast watch mode without linting -- `pnpm run bundle` - Production bundle +```bash +pnpm run rebuild # Complete rebuild from scratch +pnpm run build # Full development build +pnpm run build:quick # Fast build without linting +pnpm run build:extension # Build only the extension (Node.js) +pnpm run build:webviews # Build only webviews +pnpm run bundle # Production bundle +pnpm run bundle:extension # Production bundle (extension only) +``` + +### Watch Mode + +```bash +pnpm run watch # Watch mode for development +pnpm run watch:quick # Fast watch mode without linting +pnpm run watch:extension # Watch extension only +pnpm run watch:webviews # Watch webviews only +pnpm run watch:tests # Watch test files +``` ### Testing & Quality -- `pnpm run test` - Run unit tests with vscode-test -- `pnpm run test:e2e` - End-to-end tests with Playwright -- `pnpm run lint` - ESLint with TypeScript rules -- `pnpm run lint:fix` - Auto-fix linting issues -- `pnpm run pretty` - Format with Prettier +```bash +pnpm run test # Run VS Code extension tests +pnpm run test:e2e # Run Playwright E2E tests +pnpm run build:tests # Build test files with esbuild +pnpm run lint # Run ESLint with TypeScript rules +pnpm run lint:fix # Auto-fix linting issues +pnpm run pretty # Format code with Prettier +pnpm run pretty:check # Check formatting +``` ### Specialized Commands -- `pnpm run build:tests` - Build test files with esbuild -- `pnpm run generate:contributions` - Generate package.json contributions from contributions.json -- `pnpm run generate:commandTypes` - Generate command types from contributions -- `pnpm run web` - Run extension in web environment for testing +```bash +pnpm run generate:contributions # Generate package.json contributions from contributions.json +pnpm run extract:contributions # Extract contributions from package.json to contributions.json +pnpm run generate:commandTypes # Generate command types from contributions +pnpm run build:icons # Build icon font from SVG sources +pnpm run web # Run extension in web environment for testing +pnpm run package # Create VSIX package +``` -## High-Level Architecture +### Debugging + +- Use **"Watch & Run"** launch configuration (F5) for desktop debugging +- Use **"Watch & Run (web)"** for webworker/browser debugging +- Press `Ctrl+Shift+P` → "Tasks: Run Task" → "watch" to start build task +- Tests are co-located with source files in `__tests__/` directories +- Webview changes can be refreshed without restarting extension -### Core Container System +## High-Level Architecture -- **Container** (`src/container.ts`) - Main dependency injection container, singleton pattern +### Directory Structure + +``` +src/ +├── extension.ts # Extension entry point, activation logic +├── container.ts # Service Locator - manages all services (singleton) +├── @types/ # TypeScript type definitions +├── annotations/ # Editor decoration providers +├── autolinks/ # Auto-linking issues/PRs in commit messages & branch names +├── codelens/ # Editor CodeLens providers +├── commands/ # 100+ command implementations +│ ├── git/ # Git-wizard sub-commands +│ └── *.ts # Individual command files +├── env/ # Environment-specific implementations +│ ├── node/ # Node.js (desktop) implementations +│ │ └── git/ +│ │ ├── git.ts # Git command execution +│ │ ├── localGitProvider.ts # Local Git provider (child_process) +│ │ ├── vslsGitProvider.ts # Local Live Share Git provider +│ │ └── sub-providers/ # Local sub-providers for specific Git operations +│ │ ├── branches.ts +│ │ ├── commits.ts +│ │ └── ... (15 total) +│ └── browser/ # Browser/webworker implementations +├── git/ # Git abstraction layer +│ ├── gitProvider.ts # Git provider interface +│ ├── gitProviderService.ts # Manages multiple Git providers +│ ├── models/ # Git model types (Branch, Commit, etc.) +│ ├── parsers/ # Output parsers for Git command results +│ ├── remotes/ # Remote provider and integration management +│ └── sub-providers/ # Shared sub-providers for specific Git operations +├── hovers/ # Editor hover providers +├── plus/ # Pro features (non-OSS, see LICENSE.plus) +│ ├── ai/ # AI features (commit messages, explanations, changelogs) +│ ├── gk/ # GitKraken-specific features (account, subscription, etc.) +│ └── integrations/ # Rich Git host & issue tracker integrations (GitHub, GitLab, Jira, etc.) +│ └── providers/ +│ └── github/ +│ ├── githubGitProvider.ts +│ └── sub-providers/ # 11 GitHub-specific sub-providers +├── quickpicks/ # Quick pick/input (quick menus) implementations +├── statusbar/ # Status bar item management +├── system/ # Utility libraries +│ ├── utils/ # Utilities usable in both host and webviews +│ └── utils/-webview/ # Extension host-specific utilities +├── telemetry/ # Usage analytics and error reporting +├── terminal/ # Terminal integration providers +├── trackers/ # Tracks document state and blames +├── uris/ # Deep link uri handling +├── views/ # Tree view providers (sidebar views) +│ ├── commitsView.ts +│ ├── branchesView.ts +│ └── ... +├── vsls/ # Live Share support +└── webviews/ # Webview implementations + ├── apps/ # Webview UI apps (Lit only) + │ ├── shared/ # Common UI components using Lit + │ ├── commitDetails/ + │ ├── rebase/ + │ ├── settings/ + │ └── plus/ # Pro webview apps + │ ├── home/ + │ ├── graph/ + │ ├── timeline/ + │ ├── patchDetails/ + │ └── composer/ + ├── protocol.ts # IPC protocol for webview communication + └── webviewController.ts # Base controller for all webviews +tests/ # E2E and Unit tests +walkthroughs/ # Welcome and tips walkthroughs +``` + +### Core Architectural Patterns + +**1. Service Locator (Container)** + +- `src/container.ts` - Main dependency injection container using singleton pattern +- Manages 30+ services with lazy initialization - All services registered in constructor and exposed as getters - Handles lifecycle, configuration changes, and service coordination - -### Major Services & Providers +- Example services: GitProviderService, SubscriptionService, TelemetryService, AIProviderService + +**2. Provider Pattern for Git Operations** + +- `GitProviderService` manages multiple Git providers (local, remote, GitHub, etc.) +- Allows environment-specific implementations: + - **LocalGitProvider** (`src/env/node/git/localGitProvider.ts`): Executes Git via `child_process` for Node.js + - **GitHubGitProvider** (`src/plus/integrations/providers/github/githubGitProvider.ts`): Uses GitHub API for browser +- Each provider implements the `GitProvider` interface + - Both providers use a shared set of sub-providers (in `src/git/sub-providers/`) for specific Git operations + - LocalGitProvider uses 15 specialized sub-providers (in `src/env/node/git/sub-providers/`): + - `branches`, `commits`, `config`, `contributors`, `diff`, `graph`, `patch`, `refs`, `remotes`, `revision`, `staging`, `stash`, `status`, `tags`, `worktrees` + - GitHubGitProvider uses 11 specialized sub-providers (in `src/plus/integrations/providers/github/sub-providers/`): + - `branches`, `commits`, `config`, `contributors`, `diff`, `graph`, `refs`, `remotes`, `revision`, `status`, `tags` + +**3. Layered Architecture** + +``` +VS Code Extension API + ↓ +Commands (100+ command handlers in src/commands/) + ↓ +Controllers (Webviews, Views, Annotations, CodeLens) + ↓ +Services (Git, Telemetry, Storage, Integrations, AI, Subscription) + ↓ +Git Providers (LocalGitProvider, GitHubGitProvider, etc.) + ↓ +Git Execution (Node: child_process | Browser: APIs (GitHub)) +``` + +**4. Webview IPC Protocol** + +- Webviews use typed message-passing with three message types: + - **Commands**: Fire-and-forget actions (no response) + - **Requests**: Request/response pairs with Promise-based handling + - **Notifications**: Extension → Webview state updates +- Protocol defined in `src/webviews/protocol.ts` +- **Host-Guest Communication**: IPC between extension host and webviews +- Webviews built with **Lit Elements only** for reactive UI components +- **State Management**: Context providers with Lit reactive patterns and signals +- **Major webviews**: + - **Community**: Commit Details, Rebase, Settings + - **Pro** (`apps/plus/`): Home (includes Launchpad), Commit Graph, Timeline, Patch Details, Commit Composer +- Webviews bundled separately from extension (separate webpack config) + +**5. Caching Strategy** + +- Multiple caching layers for performance: + - `GitCache`: Repository-level Git data caching + - `PromiseCache`: In-flight request deduplication + - `@memoize` decorator: Function result memoization + - VS Code storage API: Persistent state across sessions + +### Major Services & Components + +**Core Services** (accessed via Container) - **GitProviderService** - Core Git operations and repository management - **SubscriptionService** - GitLens Pro subscription and account management -- **IntegrationService** - GitHub/GitLab/etc integrations -- **AIProviderService** - AI features (commit messages, explanations) -- **WebviewsController** - Manages all webview panels (Graph, Home, etc) -- **AutolinksProvider** - Auto-linking issues/PRs in commit messages +- **IntegrationService** - GitHub/GitLab/Bitbucket/Azure DevOps integrations +- **AIProviderService** - AI features (commit messages, explanations, changelogs) - **TelemetryService** - Usage analytics and error reporting +- **WebviewsController** - Manages all webview panels (Graph, Home, Settings, etc.) +- **AutolinksProvider** - Auto-linking issues/PRs in commit messages +- **DocumentTracker** - Tracks file changes and editor state +- **FileAnnotationController** - Blame, heatmap, and change annotations -### VS Code Contributions +**VS Code Contributions** -- Commands, Menus, Submenus, Keybindings, and Views are defined in `contributions.json` -- Contributions are generated from `contributions.json` into `package.json` via `pnpm run generate:contributions` -- Contributions can also be extracted from `package.json` into `contributions.json` via `pnpm run extract:contributions` +- Commands, Menus, Submenus, Keybindings, and Views defined in `contributions.json` +- Generate package.json: `pnpm run generate:contributions` +- Extract from package.json: `pnpm run extract:contributions` +- All other VS Code contributions are defined in `package.json` (activation events, settings, etc.) -### Webview Architecture +**Extension Activation** (`src/extension.ts`) -- **Shared Components** (`src/webviews/apps/shared/`) - Common UI components using Lit -- **Host-Guest Communication** - IPC between extension and webviews -- **State Management** - Context providers with Lit reactive patterns -- Major webviews: Home, Commit Graph, Timeline, Launchpad, Settings +- Activates on `onStartupFinished`, file system events, or specific webview opens +- Creates the `Container` singleton +- Registers all commands, views, providers, and decorations -### Git Integration +**Commands** (`src/commands/`) -- **GitProviderService** - Abstracts Git operations across different providers -- **Repository Models** - Strongly typed Git entities (Branch, Commit, Tag, etc) -- **DocumentTracker** - Tracks file changes and editor state -- **FileAnnotationController** - Blame, heatmap, and change annotations +- 100+ commands registered in `package.json` (generated from `contributions.json`) +- Command IDs auto-generated in `src/constants.commands.generated.ts` +- Commands grouped by functionality (git operations, views, webviews, etc.) + +**Views** (`src/views/`) + +- Tree views: Commits, Branches, Remotes, Stashes, Tags, Worktrees, Contributors, Repositories +- Each view has a tree data provider implementing VS Code's `TreeDataProvider` +- Nodes are hierarchical (repository → branch → commit → file) + +### Environment Abstraction -### Plus Features (Pro) +The extension supports both Node.js (desktop) and browser (web) environments: -- **Subscription gating** - Feature access control via SubscriptionService -- **Cloud integrations** - GitHub/GitLab APIs for PRs, issues +**Node.js Environment** (`src/env/node/`) + +- Uses `child_process` to execute Git commands via `Git.execute()` +- Direct file system access +- Full Git command support +- Commands parsed by specialized parsers in `src/git/parsers/` + +**Browser Environment** (`src/env/browser/`) + +- Uses GitHub API for Git operations +- Virtual file system via VS Code's File System API +- Limited to supported Git hosting providers +- WebWorker support for browser extension compatibility + +**Build Configuration** + +- Separate entry points: `main` (Node.js) and `browser` (webworker) +- Webpack configs in `webpack.config.mjs`: + 1. `extension:node` - Extension code for Node.js + 2. `extension:webworker` - Extension code for browser + 3. `webviews:common` - Shared webview code + 4. `webviews` - Individual webview apps + 5. `images` - Icon/image processing +- Platform detection via `@env/platform` abstractions + +**Output Structure** + +``` +dist/ +├── gitlens.js # Main extension bundle (Node.js) +├── browser/ +│ └── gitlens.js # Extension bundle for browser +└── webviews/ + ├── *.js # Individual webview apps + └── media/ # Webview assets +``` + +### Pro Features (Plus) + +Files in or under directories named "plus" fall under `LICENSE.plus` (non-OSS): + +- **Commit Graph** - Visual commit history with advanced actions - **Worktrees** - Multi-branch workflow support -- **AI features** - Commit generation, explanations using various providers +- **Launchpad** - PR/issue management hub +- **Visual File History** - Timeline visualization +- **Cloud Patches** - Private code sharing +- **Code Suggest** - In-IDE code suggestions for PRs +- **AI Features** - Commit generation, explanations using various providers + +Pro features integrate with GitKraken accounts and require authentication via SubscriptionService. + +### Testing Infrastructure + +**Test Structure** + +- Tests co-located with source files in `__tests__/` directories +- Pattern: `src/path/to/__tests__/file.test.ts` +- VS Code extension tests use `@vscode/test-cli` +- E2E tests use Playwright in `tests/e2e/` +- Build tests separately: `pnpm run build:tests` + +**Running Tests** + +```bash +pnpm run test # Run extension tests +pnpm run test:e2e # Run E2E tests +pnpm run watch:tests # Watch mode for tests +``` ## Coding Standards & Style Rules ### TypeScript Configuration -- Strict TypeScript with `strictTypeChecked` ESLint config -- No `any` usage (exceptions for external APIs) -- Explicit return types for public methods -- Prefer `type` over `interface` for unions +- **Strict TypeScript** with `strictTypeChecked` ESLint config +- **No `any` usage** (exceptions only for external APIs) +- **Explicit return types** for public methods +- **Prefer `type` over `interface`** for unions +- Multiple tsconfig files for different targets (node, browser, test) ### Import Organization -- Use path aliases: `@env/` for environment-specific code -- Import order: node built-ins → external → internal → relative -- No default exports (ESLint enforced) -- Consistent type imports with `import type` +- **Use path aliases**: `@env/` for environment-specific code +- **Import order**: node built-ins → external → internal → relative +- **No default exports** (ESLint enforced) +- **Consistent type imports** with `import type` for type-only imports + +Example: + +```typescript +import type { Disposable } from 'vscode'; +import { EventEmitter } from 'vscode'; +import type { Container } from './container'; +import { configuration } from './system/configuration'; +``` ### Naming Conventions - **Classes**: PascalCase (no `I` prefix for interfaces) - **Methods/Variables**: camelCase -- **Constants**: camelCase for module-level constants -- **Private members**: Leading underscore allowed -- **Files**: camelCase.ts, camelCase.utils.ts for related utilities -- **Folders** +- **Constants**: camelCase for module-level constants (not SCREAMING_SNAKE_CASE) +- **Private members**: Leading underscore allowed (e.g., `_cache`) +- **Files**: camelCase.ts (e.g., `gitProvider.ts`, `branchProvider.utils.ts`) +- **Folders**: - Models under a `models/` sub-folder - - Utilities under a `utils/` sub-folder if they can be used in both the extension host and webviews, or `utils/-webview/` sub-folder for extension host-specific utilities + - Utilities under a `utils/` sub-folder (usable in both host and webviews) + - Extension host-specific utilities in `utils/-webview/` sub-folder - Webview apps under `webviews/apps/` -### Code Structure +### Code Structure Principles - **Single responsibility** - Each service has focused purpose - **Dependency injection** - Services injected via Container - **Event-driven** - EventEmitter pattern for service communication - **Disposable pattern** - Proper cleanup with VS Code Disposable interface +- **Immutability** - Prefer immutable operations where possible ### Error Handling -- Use custom error types extending Error -- Log errors with context using Logger.error() +- Use custom error types extending `Error` +- Log errors with context using `Logger.error()` - Graceful degradation for network/API failures - Validate external data with schema validators +- Provide user-friendly error messages + +### Decorators -### Webview Specific +Common decorators used throughout the codebase: + +- `@memoize()` - Cache function results +- `@debug()` - Add debug logging +- `@log()` - Add logging +- `@gate()` - Throttle concurrent calls +- `@command()` - Register VS Code commands + +### Webview Development - **Lit Elements** - Use for reactive UI components - **Context providers** - For sharing state across components - **Signal patterns** - For reactive state management -- **CSS custom properties** - For theming support +- **CSS custom properties** - For VS Code theming support +- Webview UI code in `src/webviews/apps/{webviewName}/` +- Use IPC protocol for communication: `postMessage()` → `onIpc()` +- Refresh webview without restarting extension during development + +## Important Patterns and Conventions + +### Configuration Management -### Environment Abstractions +- All settings defined in `package.json` contributions +- Configuration typed in `src/config.ts` +- Access via `Container.instance.config` or `configuration.get()` +- Settings are strongly typed with intellisense support -- **Platform detection** - Use `@env/platform` abstractions -- **Node vs Browser** - Environment-specific implementations in `src/env/` -- **WebWorker support** - Browser extension compatibility +### Constants Organization + +- **Command IDs**: `src/constants.commands.ts` (manual) + `constants.commands.generated.ts` (auto-generated) +- **Context keys**: `src/constants.context.ts` +- **Telemetry events**: `src/constants.telemetry.ts` +- **View IDs**: `src/constants.views.ts` +- **AI providers**: `src/constants.ai.ts` +- **Storage keys**: `src/constants.storage.ts` + +### Git Command Execution + +- All Git commands go through `Git.execute()` in `src/env/node/git/git.ts` +- Commands are parsed and formatted consistently +- Output is parsed by specialized parsers in `src/git/parsers/` +- Results cached in GitCache for performance + +### Repository Models + +Strongly typed Git entities throughout the codebase (located in `src/git/models/`): + +- **Core models**: `GitBranch`, `GitCommit`, `GitTag`, `GitRemote`, `GitWorktree` +- **Specialized models**: `GitStashCommit` (extends `GitCommit`), `GitStash`, `GitContributor`, `GitFile`, `GitDiff` +- Models provide rich methods and computed properties +- Immutable by convention ## Repository Guidelines ### Commit Messages -- Use a future-oriented manner, third-person singular present tense (e.g., 'Fixes', 'Updates', 'Improves', 'Adds', 'Removes') +- Use future-oriented manner, third-person singular present tense +- Examples: **"Fixes"**, **"Updates"**, **"Improves"**, **"Adds"**, **"Removes"** - Reference issues with `#123` syntax for auto-linking - Keep first line under 72 characters +- Example: `Adds support for custom autolinks for Jira - fixes #1234` ### Branch Workflow - Feature branches from `main` - Prefix with feature type: `feature/`, `bug/`, `debt/` -- Use descriptive names: `feature/search-natural-language` +- Use descriptive names: `feature/search-natural-language`, `bug/graph-performance` ### Code Reviews - Check TypeScript compilation and tests pass - Verify no new ESLint violations -- Test webview changes in both themes -- Validate Plus features with subscription states - -## Key Extension Points - -### Adding New Commands - -1. Define in `src/commands/` directory -2. Register in `src/commands.ts` -3. Add to `contributions.json` for package.json generation -4. Update command types with `pnpm run generate:commandTypes` - -### New Webviews - -1. Create provider in `src/webviews/` -2. Add Lit app in `src/webviews/apps/` -3. Register in WebviewsController -4. Add protocol definitions for IPC - -### Git Provider Extensions - -- Implement GitProvider interface -- Register with GitProviderService -- Handle provider-specific authentication - -### AI Provider Integration - -- Implement AIProvider interface -- Add to AIProviderService registry -- Handle authentication and rate limiting +- Test webview changes in both light and dark themes +- Validate Plus features with different subscription states +- Ensure proper error handling and logging +- Ensure proper telemetry and usage reporting +- Ensure proper caching and performance + +### Contributing Notes + +- Update `CHANGELOG.md` for all changes (in future tense) +- Add yourself to Contributors section in `README.md` for first contribution +- Follow existing code style (Prettier enforced) +- All files in `plus/` directories are non-OSS (LICENSE.plus) +- PRs with changes to `plus/` files grant GitKraken rights to modifications + +## Common Development Tasks + +### Adding a New Command + +1. Create command file in `src/commands/` (e.g., `myCommand.ts`) +2. Register command in `src/commands.ts`: + ```typescript + registerCommand(Commands.MyCommand, () => new MyCommand(container)); + ``` +3. Add to `contributions.json` for package.json generation: + ```json + { + "command": "gitlens.myCommand", + "title": "My Command", + "category": "GitLens" + } + ``` +4. Run `pnpm run generate:contributions` to update package.json +5. Run `pnpm run generate:commandTypes` to update command constants + +### Adding a New Webview + +1. Create webview provider in `src/webviews/` (e.g., `myWebviewProvider.ts`) +2. Create Lit app in appropriate location: + - For Pro features: `src/webviews/apps/plus/my-webview/` + - For community features: `src/webviews/apps/my-webview/` + - Create `my-webview.ts` (main app component with Lit Elements) + - Add HTML template + - Add CSS styles +3. Register in `WebviewsController` (in `src/webviews/webviewsController.ts`) +4. Add protocol definitions for IPC in `src/webviews/protocol.ts`: + ```typescript + export interface MyWebviewShowingArgs { ... } + ``` +5. Add webpack entry point in `webpack.config.mjs` +6. Register webview in extension activation + +### Adding a New Tree View + +1. Create tree provider in `src/views/` (e.g., `myTreeView.ts`) + - Extend `ViewBase` or `RepositoryFolderNode` + - Implement `getChildren()` method +2. Define node types for the tree hierarchy +3. Add to `contributions.json`: + ```json + { + "id": "gitlens.views.myView", + "name": "My View", + "when": "..." + } + ``` +4. Register in extension activation (`src/extension.ts`) +5. Run `pnpm run generate:contributions` + +### Modifying Git Operations + +1. Find the relevant Git provider: + - Shared Git provider interface: `src/git/gitProvider.ts` + - Shared sub-operations: `src/git/sub-providers/` + - For Local (Node.js): `src/env/node/git/localGitProvider.ts` + - For Local sub-operations: `src/env/node/git/sub-providers/` + - For GitHub (browser): `src/plus/integrations/providers/github/githubGitProvider.ts` + - For GitHub sub-operations: `src/plus/integrations/providers/github/sub-providers/` +2. Update provider method with new logic +3. Update Git command execution in `src/env/node/git/git.ts` if needed (for LocalGitProvider) +4. Update parsers in `src/git/parsers/` if output format changes +5. Update models in `src/git/models/` if data structure changes +6. Consider caching implications (update `GitCache` if needed) +7. Add tests in `__tests__/` directory + +### Working with Icons (GL Icons Font) + +1. Add SVG icons to `images/icons/` folder +2. Append entries to `images/icons/template/mapping.json`: + ```json + "icon-name": 1234 + ``` +3. Run icon build commands: + ```bash + pnpm run icons:svgo # Optimize SVGs + pnpm run build:icons # Generate font + ``` +4. Copy new `glicons.woff2?` URL from `src/webviews/apps/shared/glicons.scss` +5. Search and replace old font URL with new one across the codebase + +### Adding New AI Provider + +1. Create new AI provider in `src/plus/ai/` extending base classes (e.g., `openAICompatibleProviderBase.ts`) +2. Add to `AIProviderService` registry in `src/plus/ai/aiProviderService.ts` +3. Handle authentication and rate limiting +4. Add provider constants to `src/constants.ai.ts` +5. Update configuration in `package.json` contributions + +### Adding Git Provider Integration + +1. Implement `GitProvider` interface (e.g., `gitLabGitProvider.ts`) +2. Register with `GitProviderService` +3. Handle provider-specific authentication +4. Add integration constants to `src/constants.integrations.ts` +5. Consider adding rich integration features (PRs, issues, avatars) ## Development Environment ### Prerequisites - **Node.js** ≥ 22.12.0 -- **pnpm** ≥ 10.x (via corepack) +- **pnpm** ≥ 10.x (install via corepack: `corepack enable`) +- **Corepack** ≥ 0.31.0 (check with `corepack -v`) - **Git** ≥ 2.7.2 -### VS Code Tasks +### VS Code Setup -- **Build** - `Ctrl+Shift+P` → "Tasks: Run Task" → "watch" -- **Test** - Use VS Code's built-in test runner +- Install recommended extensions (see `.vscode/extensions.json`) +- Use provided launch configurations: + - **"Watch & Run"** - Debug desktop extension + - **"Watch & Run (web)"** - Debug browser extension +- Use VS Code tasks: + - `Ctrl+Shift+B` to start watch task + - `Ctrl+Shift+P` → "Tasks: Run Task" → select task - **Debug** - F5 to launch Extension Development Host +- **Test** - Use VS Code's built-in test runner ### Multi-target Support -- **Node.js** - Traditional VS Code extension -- **Web Worker** - Browser/web VS Code compatibility -- Shared code with environment abstractions +GitLens supports multiple environments: + +- **Node.js** - Traditional VS Code extension (desktop) +- **Web Worker** - Browser/web VS Code compatibility (vscode.dev) +- Shared code with environment abstractions in `src/env/` +- Test both environments during development + +### Performance Considerations + +- Use lazy loading for heavy services +- Leverage caching layers (GitCache, PromiseCache, @memoize) +- Debounce expensive operations +- Consider webview refresh performance +- Monitor telemetry for performance regressions + +--- -This architecture enables GitLens to provide powerful Git tooling while maintaining clean separation of concerns and extensibility for new features. +This architecture enables GitLens to provide powerful Git tooling while maintaining clean separation of concerns, extensibility for new features, and support for multiple runtime environments. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000000..43c994c2d3617 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md From dddf7ae7ccace8673009f0cf06ba25ba19b143e9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 26 Oct 2025 21:41:39 -0400 Subject: [PATCH 77/83] Updates elements manifest --- custom-elements.json | 33383 +++++++++++++++++++++++++---------------- 1 file changed, 20220 insertions(+), 13163 deletions(-) diff --git a/custom-elements.json b/custom-elements.json index 21fa5b15868d7..72ff4976b49dd 100644 --- a/custom-elements.json +++ b/custom-elements.json @@ -6,344 +6,436 @@ "kind": "javascript-module", "path": "src/webviews/apps/commitDetails/commitDetails.ts", "declarations": [ + { + "kind": "variable", + "name": "uncommittedSha", + "type": { + "text": "string" + }, + "default": "'0000000000000000000000000000000000000000'" + }, { "kind": "class", "description": "", - "name": "CommitDetailsApp", + "name": "GlCommitDetailsApp", "members": [ { "kind": "method", - "name": "onInitialize", + "name": "createStateProvider", "privacy": "protected", "return": { "type": { - "text": "void" + "text": "CommitDetailsStateProvider" } }, + "parameters": [ + { + "name": "bootstrap", + "type": { + "text": "string" + } + }, + { + "name": "ipc", + "type": { + "text": "HostIpc" + } + }, + { + "name": "logger", + "type": { + "text": "LoggerContext" + } + } + ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "field", - "name": "_api", + "name": "explain", "type": { - "text": "HostIpcApi" + "text": "ExplainState | undefined" }, - "privacy": "private", - "readonly": true, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "privacy": "private" }, { "kind": "field", - "name": "_hostIpc", + "name": "generate", "type": { - "text": "HostIpc" + "text": "GenerateState | undefined" }, - "privacy": "private", - "readonly": true, - "default": "new HostIpc(this.appName)", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "privacy": "private" }, { "kind": "field", - "name": "_logger", + "name": "draftState", "type": { - "text": "LoggerContext" + "text": "DraftState" }, "privacy": "private", - "readonly": true, - "default": "new LoggerContext(appName)", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "default": "{ inReview: false }" }, { "kind": "field", - "name": "_promos", + "name": "isUncommitted", "type": { - "text": "PromosContext" + "text": "boolean" }, "privacy": "private", - "readonly": true, - "default": "new PromosContext(this._hostIpc)", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "readonly": true }, { "kind": "field", - "name": "_telemetry", + "name": "isStash", "type": { - "text": "TelemetryContext" + "text": "boolean" }, - "privacy": "protected", - "readonly": true, - "default": "new TelemetryContext(this._hostIpc)", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "state", - "type": { - "text": "State" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "name": "wipStatus", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "placement", + "name": "indentPreference", "type": { - "text": "'editor' | 'view'" + "text": "number" }, - "privacy": "protected", - "readonly": true, - "default": "(document.body.getAttribute('data-placement') ?? 'editor')", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "privacy": "private", + "default": "16" }, { "kind": "method", - "name": "onBind", - "privacy": "protected", - "return": { - "type": { - "text": "Disposable[]" + "name": "updateDocumentProperties", + "privacy": "private" + }, + { + "kind": "method", + "name": "onSuggestChanges", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CreatePatchEventDetail" + } } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "onInitialized", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "onShowCodeSuggestion", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "{ id: string }" + } } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "onMessageReceived", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "renderTopInspect", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderTopWip", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderRepoStatusContent", + "privacy": "private", + "parameters": [ + { + "name": "_isWip", + "type": { + "text": "boolean" + } } - }, + ] + }, + { + "kind": "method", + "name": "renderWipTooltipContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderTopSection", + "privacy": "private" + }, + { + "kind": "method", + "name": "onDraftStateChanged", + "privacy": "private", "parameters": [ { - "name": "msg", + "name": "inReview", "type": { - "text": "IpcMessage" + "text": "boolean" } + }, + { + "name": "silent", + "default": "false" } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "onThemeUpdated", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "onBranchAction", + "privacy": "private", + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } } - }, + ] + }, + { + "kind": "method", + "name": "onCreatePatchFromWip", + "privacy": "private", "parameters": [ { - "name": "e", + "name": "checked", + "default": "true", "type": { - "text": "ThemeChangeEvent" + "text": "boolean | 'staged'" } } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { - "kind": "field", - "name": "_focused", - "type": { - "text": "boolean | undefined" - }, + "kind": "method", + "name": "onCommandClickedCore", "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "parameters": [ + { + "name": "action", + "optional": true, + "type": { + "text": "GlCommands | `command:${GlCommands}`" + } + } + ] }, { - "kind": "field", - "name": "_inputFocused", - "type": { - "text": "boolean | undefined" - }, + "kind": "method", + "name": "onSwitchAiModel", "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "parameters": [ + { + "name": "_e", + "type": { + "text": "MouseEvent" + } + } + ] }, { - "kind": "field", - "name": "bindDisposables", - "type": { - "text": "Disposable[] | undefined" - }, + "kind": "method", + "name": "onExplainCommit", "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + "parameters": [ + { + "name": "_e", + "type": { + "text": "MouseEvent" + } + } + ] }, { "kind": "method", - "name": "bind", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "onCreateGenerateTitle", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "CreatePatchMetadataEventDetail" + } } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "log", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "onToggleFilesLayout", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } } - }, + ] + }, + { + "kind": "method", + "name": "onExpandedChange", + "privacy": "private", "parameters": [ { - "name": "message", + "name": "e", "type": { - "text": "string" + "text": "WebviewPaneExpandedChangeEventDetail" } }, { - "name": "optionalParams", + "name": "pane", "type": { - "text": "any[]" + "text": "string" } } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "getState", - "privacy": "protected", - "return": { - "type": { - "text": "State | undefined" + "name": "onNavigate", + "privacy": "private", + "parameters": [ + { + "name": "direction", + "type": { + "text": "'back' | 'forward'" + } } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "sendCommand", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "onTogglePin", + "privacy": "private" + }, + { + "kind": "method", + "name": "onPickCommit", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "MouseEvent" + } } - }, + ] + }, + { + "kind": "method", + "name": "onSearchCommit", + "privacy": "private", "parameters": [ { - "name": "command", + "name": "_e", "type": { - "text": "TCommand" + "text": "MouseEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onSwitchMode", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "MouseEvent" } }, { - "name": "params", + "name": "mode", "type": { - "text": "IpcCallParamsType" + "text": "Mode" } } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "sendRequest", - "privacy": "protected", - "return": { - "type": { - "text": "Promise>" + "name": "onOpenFileOnRemote", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } } - }, + ] + }, + { + "kind": "method", + "name": "onOpenFile", + "privacy": "private", "parameters": [ { - "name": "requestType", + "name": "e", "type": { - "text": "T" + "text": "FileChangeListItemDetail" } - }, + } + ] + }, + { + "kind": "method", + "name": "onCompareFileWithWorking", + "privacy": "private", + "parameters": [ { - "name": "params", + "name": "e", "type": { - "text": "IpcCallParamsType" + "text": "FileChangeListItemDetail" } } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } + ] }, { "kind": "method", - "name": "setState", - "privacy": "protected", + "name": "onCompareFileWithPrevious", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } + } + ] + }, + { + "kind": "method", + "name": "onFileMoreActions", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } + } + ] + }, + { + "kind": "method", + "name": "onStageFile", + "privacy": "private", "return": { "type": { "text": "void" @@ -351,219 +443,43 @@ }, "parameters": [ { - "name": "state", + "name": "e", "type": { - "text": "Partial" + "text": "FileChangeListItemDetail" } } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "field", - "name": "bootstrap", - "default": "undefined", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - } - ], - "superclass": { - "name": "App", - "module": "/src/webviews/apps/shared/appBase" - } - } - ], - "exports": [ - { - "kind": "js", - "name": "CommitDetailsApp", - "declaration": { - "name": "CommitDetailsApp", - "module": "src/webviews/apps/commitDetails/commitDetails.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/home/context.ts", - "declarations": [ - { - "kind": "variable", - "name": "stateContext" - } - ], - "exports": [ - { - "kind": "js", - "name": "stateContext", - "declaration": { - "name": "stateContext", - "module": "src/webviews/apps/home/context.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/home/home.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "homeBaseStyles", - "default": "css` * { box-sizing: border-box; } :not(:defined) { visibility: hidden; } [hidden] { display: none !important; } /* roll into shared focus style */ :focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } b { font-weight: 600; } p { margin-top: 0; } ul { margin-top: 0; padding-left: 1.2em; } `" - }, - { - "kind": "variable", - "name": "homeStyles", - "default": "css` .home { padding: 0; height: 100vh; display: flex; flex-direction: column; gap: 0.4rem; overflow: hidden; } .home__alerts { flex: none; padding: 0 2rem; position: relative; } .home__alerts:not([has-alerts]) { display: none; } .home__main { flex: 1; overflow: auto; padding: 0.8rem 1.2rem; } .home__main > *:last-child { margin-bottom: 0; } .home__aux, .home__header { flex: none; } .home__header { border-top: 1px solid var(--vscode-sideBarSectionHeader-border); border-bottom: 1px solid var(--vscode-sideBarSectionHeader-border); padding: 0.4rem; } .home__aux:has(gl-promo-banner:has(gl-promo:not([has-promo])):only-child) { display: none; } summary { font-size: 1.3rem; font-weight: normal; text-transform: uppercase; color: var(--vscode-foreground); cursor: pointer; } details[open] summary { margin-block-end: 0.8rem; } gl-home-header { margin: 0; } gl-repo-alerts:not([has-alerts]) { display: none; } `" - }, - { - "kind": "variable", - "name": "buttonStyles", - "default": "css` .button-container { margin: 1rem auto 0; text-align: left; max-width: 30rem; transition: max-width 0.2s ease-out; } @media (min-width: 640px) { .button-container { max-width: 100%; } } .button-container--trio > gl-button:first-child { margin-bottom: 0.4rem; } .button-group { display: inline-flex; gap: 0.4rem; } .button-group--single { width: 100%; max-width: 30rem; } .button-group gl-button { margin-top: 0; } .button-group gl-button:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group gl-button:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; } `" - }, - { - "kind": "variable", - "name": "alertStyles", - "default": "css` .alert { position: relative; padding: 0.8rem 1.2rem; line-height: 1.2; margin-bottom: 1.2rem; background-color: var(--color-alert-neutralBackground); border-left: 0.3rem solid var(--color-alert-neutralBorder); color: var(--color-alert-foreground); } .alert__title { font-size: 1.4rem; margin: 0; } .alert__description { font-size: 1.2rem; margin: 0.4rem 0 0; } .alert__description > :first-child { margin-top: 0; } .alert__description > :last-child { margin-bottom: 0; } .alert__close { position: absolute; top: 0.8rem; right: 0.8rem; color: inherit; opacity: 0.64; } .alert__close:hover { color: inherit; opacity: 1; } .alert.is-collapsed { cursor: pointer; } .alert.is-collapsed:hover { background-color: var(--color-alert-neutralHoverBackground); } .alert.is-collapsed .alert__description, .alert.is-collapsed .alert__close gl-tooltip:first-child, .alert:not(.is-collapsed) .alert__close gl-tooltip:last-child { display: none; } .alert--info { background-color: var(--color-alert-infoBackground); border-left-color: var(--color-alert-infoBorder); } .alert--warning { background-color: var(--color-alert-warningBackground); border-left-color: var(--color-alert-warningBorder); } .alert--danger { background-color: var(--color-alert-errorBackground); border-left-color: var(--color-alert-errorBorder); } `" - }, - { - "kind": "variable", - "name": "navListStyles", - "default": "css` .nav-list { margin-left: -1.2rem; margin-right: -1.2rem; display: flex; flex-direction: column; gap: 0.1rem; align-items: stretch; margin-bottom: 1.6rem; } .nav-list__item { display: flex; flex-direction: row; align-items: center; gap: 0.8rem; padding: 0.4rem 2rem; } .nav-list__item:hover, .nav-list__item:focus-within { background-color: var(--vscode-list-hoverBackground); color: var(--vscode-list-hoverForeground); } .nav-list__item:has(:first-child:focus) { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } .nav-list__item:has(:active) { background-color: var(--vscode-list-activeSelectionBackground); color: var(--vscode-list-activeSelectionForeground); } .nav-list__item:has(.is-disabled) { cursor: not-allowed; } .nav-list__link { flex: 1; display: flex; flex-direction: row; align-items: center; gap: 0.8rem; color: inherit; } .nav-list__link:hover, .nav-list__link:focus { color: inherit; text-decoration: none; } .nav-list__link:focus { outline: none; } .nav-list__link.is-disabled, .nav-list__link.is-disabled:hover { opacity: 0.5; pointer-events: none; text-decoration: none; } .nav-list__icon { flex: none; opacity: 0.5; } .nav-list__label { flex: 1; font-weight: 600; } .nav-list__desc { color: var(--color-foreground--65); font-variant: all-small-caps; margin-left: 1rem; } .nav-list__group { width: 100%; display: flex; justify-content: flex-start; } .nav-list__group .nav-list__label { width: auto; } .nav-list__access { flex: none; position: relative; left: 1.2rem; font-size: x-small; outline: none; white-space: nowrap; --gl-feature-badge-color: color-mix(in srgb, transparent 40%, currentColor); --gl-feature-badge-border-color: color-mix(in srgb, transparent 40%, var(--color-foreground--50)); } .nav-list__item:hover .nav-list__label { text-decoration: underline; } .nav-list__item:hover .is-disabled .nav-list__label { text-decoration: none; } .nav-list__item:hover .nav-list__desc { color: var(--color-foreground); } .nav-list__item:focus-within .nav-list__access, .nav-list__item:hover .nav-list__access { --gl-feature-badge-color: currentColor; --gl-feature-badge-border-color: var(--color-foreground--50); } .nav-list__title { padding: 0 2rem; } .t-eyebrow { text-transform: uppercase; font-size: 1rem; font-weight: 600; color: var(--color-foreground--50); margin: 0; } .t-eyebrow.sticky { top: -8px; } `" - }, - { - "kind": "variable", - "name": "walkthroughProgressStyles", - "default": "css` a, a:hover, a:focus, a:active { text-decoration: none; } .walkthrough-progress { display: flex; flex-direction: column; gap: 2px; padding: 2px 4px 4px; margin-top: 4px; align-items: stretch; cursor: pointer; border-radius: 4px; } .walkthrough-progress:focus-within, .walkthrough-progress:hover { background-color: var(--gl-walkthrough-hover-background); } .walkthrough-progress__title { display: flex; justify-content: space-between; align-items: center; color: var(--color-foreground--85); } .walkthrough-progress__button { --button-padding: 1px 2px 0px 2px; position: absolute; right: 0.4rem; } .walkthrough-progress__bar::-webkit-progress-bar { border-radius: 2px; background: var(--color-alert-neutralBackground); } .walkthrough-progress__bar::-webkit-progress-value { background: var(--vscode-progressBar-background, blue); transition: 0.1s ease-in; border-radius: 2px; } .walkthrough-progress__bar { pointer-events: none; border-radius: 2px; width: 100%; background: unset; height: 4px; flex-shrink: 0; z-index: 2; } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "homeBaseStyles", - "declaration": { - "name": "homeBaseStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - }, - { - "kind": "js", - "name": "homeStyles", - "declaration": { - "name": "homeStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - }, - { - "kind": "js", - "name": "buttonStyles", - "declaration": { - "name": "buttonStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - }, - { - "kind": "js", - "name": "alertStyles", - "declaration": { - "name": "alertStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - }, - { - "kind": "js", - "name": "navListStyles", - "declaration": { - "name": "navListStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - }, - { - "kind": "js", - "name": "walkthroughProgressStyles", - "declaration": { - "name": "walkthroughProgressStyles", - "module": "src/webviews/apps/home/home.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/home/home.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlHomeApp", - "members": [ - { - "kind": "field", - "name": "_activeOverviewState", - "type": { - "text": "ActiveOverviewState" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "_inactiveOverviewState", - "type": { - "text": "InactiveOverviewState" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "_header", - "type": { - "text": "GlHomeHeader" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "badgeSource", - "type": { - "text": "object" - }, - "privacy": "private", - "default": "{ source: 'home', detail: 'badge' }" + ] }, { "kind": "method", - "name": "createStateProvider", - "privacy": "protected", + "name": "onUnstageFile", + "privacy": "private", "return": { "type": { - "text": "HomeStateProvider" + "text": "void" } }, "parameters": [ { - "name": "state", + "name": "e", "type": { - "text": "State" + "text": "FileChangeListItemDetail" } - }, + } + ] + }, + { + "kind": "method", + "name": "onCommitActions", + "privacy": "private", + "parameters": [ { - "name": "ipc", + "name": "e", "type": { - "text": "HostIpc" + "text": "CustomEvent<{ action: string; alt: boolean }>" } } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + ] }, { "kind": "field", @@ -655,7 +571,7 @@ "kind": "field", "name": "bootstrap", "type": { - "text": "State" + "text": "string" }, "privacy": "private", "attribute": "bootstrap", @@ -752,31 +668,9 @@ "kind": "field", "name": "_stateProvider", "type": { - "text": "StateProvider" + "text": "Provider" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - }, - { - "kind": "method", - "name": "onPersistState", "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "state", - "type": { - "text": "State" - } - } - ], "inheritedFrom": { "name": "GlAppHost", "module": "src/webviews/apps/shared/appHost.ts" @@ -883,7 +777,7 @@ "name": "GlAppHost", "module": "/src/webviews/apps/shared/appHost" }, - "tagName": "gl-home-app", + "tagName": "gl-commit-details-app", "customElement": true, "attributes": [ { @@ -912,7 +806,7 @@ { "name": "bootstrap", "type": { - "text": "State" + "text": "string" }, "fieldName": "bootstrap", "inheritedFrom": { @@ -926,179 +820,92 @@ "exports": [ { "kind": "js", - "name": "GlHomeApp", + "name": "uncommittedSha", "declaration": { - "name": "GlHomeApp", - "module": "src/webviews/apps/home/home.ts" + "name": "uncommittedSha", + "module": "src/webviews/apps/commitDetails/commitDetails.ts" + } + }, + { + "kind": "js", + "name": "GlCommitDetailsApp", + "declaration": { + "name": "GlCommitDetailsApp", + "module": "src/webviews/apps/commitDetails/commitDetails.ts" } }, { "kind": "custom-element-definition", - "name": "gl-home-app", + "name": "gl-commit-details-app", "declaration": { - "name": "GlHomeApp", - "module": "src/webviews/apps/home/home.ts" + "name": "GlCommitDetailsApp", + "module": "src/webviews/apps/commitDetails/commitDetails.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/home/stateProvider.ts", + "path": "src/webviews/apps/commitDetails/context.ts", "declarations": [ { - "kind": "class", - "description": "", - "name": "HomeStateProvider", - "members": [ - { - "kind": "field", - "name": "disposable", - "type": { - "text": "Disposable" - }, - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "provider", - "type": { - "text": "ContextProvider<{ __context__: State }, ReactiveElementHost>" - }, - "privacy": "private", - "readonly": true, - "default": "new ContextProvider(host, { context: stateContext, initialValue: state })" - }, - { - "kind": "field", - "name": "_state", - "type": { - "text": "State" - }, - "privacy": "private", - "readonly": true, - "default": "state" - }, - { - "kind": "field", - "name": "state", - "type": { - "text": "State" - }, - "readonly": true - }, - { - "kind": "method", - "name": "dispose", - "return": { - "type": { - "text": "void" - } - } - } - ] + "kind": "variable", + "name": "stateContext" } ], "exports": [ { "kind": "js", - "name": "HomeStateProvider", + "name": "stateContext", "declaration": { - "name": "HomeStateProvider", - "module": "src/webviews/apps/home/stateProvider.ts" + "name": "stateContext", + "module": "src/webviews/apps/commitDetails/context.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/rebase/rebase.ts", - "declarations": [], - "exports": [] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/settings/settings.ts", + "path": "src/webviews/apps/commitDetails/stateProvider.ts", "declarations": [ { "kind": "class", "description": "", - "name": "SettingsApp", + "name": "CommitDetailsStateProvider", "members": [ { "kind": "field", - "name": "_scopes", - "type": { - "text": "HTMLSelectElement | null" - }, - "privacy": "private", - "default": "null" - }, - { - "kind": "field", - "name": "_observer", - "type": { - "text": "IntersectionObserver | undefined" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "_activeSection", - "type": { - "text": "string | undefined" - }, - "privacy": "private", - "default": "'general'" - }, - { - "kind": "field", - "name": "_changes", - "privacy": "private", - "default": "Object.create(null)" - }, - { - "kind": "field", - "name": "_sections", - "privacy": "private", - "default": "new Map()" - }, - { - "kind": "field", - "name": "_updating", + "name": "deferBootstrap", "type": { "text": "boolean" }, - "privacy": "private", - "default": "false" - }, - { - "kind": "method", - "name": "onInitialize", "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "readonly": true, "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onBind", + "name": "createContextProvider", "privacy": "protected", "return": { "type": { - "text": "Disposable[]" + "text": "ContextProvider" } }, + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { @@ -1119,455 +926,448 @@ } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "applyChanges", - "privacy": "private" - }, - { - "kind": "method", - "name": "getSettingsScope", - "privacy": "private", - "return": { - "type": { - "text": "'user' | 'workspace'" - } + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onInputBlurred", - "privacy": "private", - "parameters": [ - { - "name": "element", - "type": { - "text": "HTMLInputElement" - } - } - ] - }, - { - "kind": "method", - "name": "onButtonClicked", - "privacy": "private", - "parameters": [ - { - "name": "element", - "type": { - "text": "HTMLButtonElement" - } - } - ] - }, - { - "kind": "method", - "name": "onInputChanged", + "name": "onDraftStateChanged", "privacy": "private", "parameters": [ { - "name": "element", + "name": "host", "type": { - "text": "HTMLInputElement" + "text": "ReactiveElementHost" } - } - ] - }, - { - "kind": "method", - "name": "onInputChecked", - "privacy": "private", - "parameters": [ + }, { - "name": "element", + "name": "inReview", "type": { - "text": "HTMLInputElement" + "text": "boolean" } - } - ] - }, - { - "kind": "method", - "name": "onInputFocused", - "privacy": "private", - "parameters": [ + }, { - "name": "element", - "type": { - "text": "HTMLInputElement" - } + "name": "silent", + "default": "false" } ] }, { "kind": "method", - "name": "onInputSelected", - "privacy": "private", + "name": "switchMode", "parameters": [ { - "name": "element", + "name": "mode", "type": { - "text": "HTMLSelectElement" + "text": "State['mode']" } } ] }, { "kind": "method", - "name": "onTokenMouseDown", - "privacy": "private", + "name": "updatePreferences", "parameters": [ { - "name": "element", - "type": { - "text": "HTMLElement" - } - }, - { - "name": "e", + "name": "preferenceChange", "type": { - "text": "MouseEvent" + "text": "UpdateablePreferences" } } ] }, { - "kind": "method", - "name": "scrollToAnchor", - "privacy": "private", - "parameters": [ - { - "name": "anchor", - "type": { - "text": "string" - } - }, - { - "name": "behavior", - "type": { - "text": "ScrollBehavior" - } - }, - { - "name": "offset", - "optional": true, - "type": { - "text": "number" - } - } - ] + "kind": "field", + "name": "disposable", + "type": { + "text": "Disposable" + }, + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_scrollTimer", + "name": "provider", "type": { - "text": "ReturnType | undefined" + "text": "ContextProvider" }, - "privacy": "private" + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "method", - "name": "scrollTo", - "privacy": "private", - "parameters": [ - { - "name": "el", - "type": { - "text": "HTMLElement" - } - }, - { - "name": "behavior", - "type": { - "text": "ScrollBehavior" - } - }, - { - "name": "offset", - "optional": true, - "type": { - "text": "number" - } - } - ] + "kind": "field", + "name": "_state", + "type": { + "text": "State" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "webviewId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "webviewInstanceId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "timestamp", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "evaluateStateExpression", - "privacy": "private", + "name": "dispose", "return": { "type": { - "text": "boolean" + "text": "void" } }, - "parameters": [ - { - "name": "expression", - "type": { - "text": "string" - } - }, - { - "name": "changes", - "type": { - "text": "Record" - } - } - ] + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "getCustomSettingValue", - "privacy": "private", + "name": "initializeState", + "privacy": "protected", "return": { "type": { - "text": "boolean | undefined" + "text": "Promise" } }, - "parameters": [ - { - "name": "path", - "type": { - "text": "string" - } - } - ] + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "getSettingValue", - "privacy": "private", + "name": "onPersistState", + "privacy": "protected", "return": { "type": { - "text": "T | undefined" + "text": "void" } }, "parameters": [ { - "name": "path", + "name": "state", "type": { - "text": "string" + "text": "State" } } - ] - }, + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + } + ], + "superclass": { + "name": "StateProviderBase", + "module": "/src/webviews/apps/shared/stateProviderBase" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "CommitDetailsStateProvider", + "declaration": { + "name": "CommitDetailsStateProvider", + "module": "src/webviews/apps/commitDetails/stateProvider.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/home/context.ts", + "declarations": [ + { + "kind": "variable", + "name": "stateContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "stateContext", + "declaration": { + "name": "stateContext", + "module": "src/webviews/apps/home/context.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/home/home.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "homeBaseStyles", + "default": "css` * { box-sizing: border-box; } :not(:defined) { visibility: hidden; } [hidden] { display: none !important; } /* roll into shared focus style */ :focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } b { font-weight: 600; } p { margin-top: 0; } ul { margin-top: 0; padding-left: 1.2em; } `" + }, + { + "kind": "variable", + "name": "homeStyles", + "default": "css` .home { padding: 0; height: 100vh; display: flex; flex-direction: column; gap: 0.4rem; overflow: hidden; } .home__alerts { flex: none; padding: 0 2rem; position: relative; } .home__alerts:not([has-alerts]) { display: none; } .home__main { flex: 1; overflow: auto; padding: 0.8rem 1.2rem; } .home__main > *:last-child { margin-bottom: 0; } .home__aux, .home__header { flex: none; } .home__header { border-top: 1px solid var(--vscode-sideBarSectionHeader-border); border-bottom: 1px solid var(--vscode-sideBarSectionHeader-border); padding: 0.4rem; } .home__aux:has(gl-promo-banner:has(gl-promo:not([has-promo])):only-child) { display: none; } summary { font-size: 1.3rem; font-weight: normal; text-transform: uppercase; color: var(--vscode-foreground); cursor: pointer; } details[open] summary { margin-block-end: 0.8rem; } gl-home-header { margin: 0; } gl-repo-alerts:not([has-alerts]) { display: none; } `" + }, + { + "kind": "variable", + "name": "buttonStyles", + "default": "css` .button-container { margin: 1rem auto 0; text-align: left; max-width: 30rem; transition: max-width 0.2s ease-out; } @media (min-width: 640px) { .button-container { max-width: 100%; } } .button-container--trio > gl-button:first-child { margin-bottom: 0.4rem; } .button-group { display: inline-flex; gap: 0.4rem; } .button-group--single { width: 100%; max-width: 30rem; } .button-group gl-button { margin-top: 0; } .button-group gl-button:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group gl-button:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; } `" + }, + { + "kind": "variable", + "name": "alertStyles", + "default": "css` .alert { position: relative; padding: 0.8rem 1.2rem; line-height: 1.2; margin-bottom: 1.2rem; background-color: var(--color-alert-neutralBackground); border-left: 0.3rem solid var(--color-alert-neutralBorder); color: var(--color-alert-foreground); } .alert__title { font-size: 1.4rem; margin: 0; } .alert__description { font-size: 1.2rem; margin: 0.4rem 0 0; } .alert__description > :first-child { margin-top: 0; } .alert__description > :last-child { margin-bottom: 0; } .alert__close { position: absolute; top: 0.8rem; right: 0.8rem; color: inherit; opacity: 0.64; } .alert__close:hover { color: inherit; opacity: 1; } .alert.is-collapsed { cursor: pointer; } .alert.is-collapsed:hover { background-color: var(--color-alert-neutralHoverBackground); } .alert.is-collapsed .alert__description, .alert.is-collapsed .alert__close gl-tooltip:first-child, .alert:not(.is-collapsed) .alert__close gl-tooltip:last-child { display: none; } .alert--info { --color-alert-foreground: var(--color-alert-infoForeground); background-color: var(--color-alert-infoBackground); border-left-color: var(--color-alert-infoBorder); } .alert--warning { --color-alert-foreground: var(--color-alert-warningForeground); background-color: var(--color-alert-warningBackground); border-left-color: var(--color-alert-warningBorder); } .alert--danger { --color-alert-foreground: var(--color-alert-errorForeground); background-color: var(--color-alert-errorBackground); border-left-color: var(--color-alert-errorBorder); } .alert a:not(:hover) { color: color-mix(in srgb, var(--color-alert-foreground) 50%, var(--vscode-textLink-foreground)); } .alert a:hover { color: color-mix(in srgb, var(--color-alert-foreground) 50%, var(--vscode-textLink-activeForeground)); } `" + }, + { + "kind": "variable", + "name": "navListStyles", + "default": "css` .nav-list { margin-left: -1.2rem; margin-right: -1.2rem; display: flex; flex-direction: column; gap: 0.1rem; align-items: stretch; margin-bottom: 1.6rem; } .nav-list__item { display: flex; flex-direction: row; align-items: center; gap: 0.8rem; padding: 0.4rem 2rem; } .nav-list__item:hover, .nav-list__item:focus-within { background-color: var(--vscode-list-hoverBackground); color: var(--vscode-list-hoverForeground); } .nav-list__item:has(:first-child:focus) { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } .nav-list__item:has(:active) { background-color: var(--vscode-list-activeSelectionBackground); color: var(--vscode-list-activeSelectionForeground); } .nav-list__item:has(.is-disabled) { cursor: not-allowed; } .nav-list__link { flex: 1; display: flex; flex-direction: row; align-items: center; gap: 0.8rem; color: inherit; } .nav-list__link:hover, .nav-list__link:focus { color: inherit; text-decoration: none; } .nav-list__link:focus { outline: none; } .nav-list__link.is-disabled, .nav-list__link.is-disabled:hover { opacity: 0.5; pointer-events: none; text-decoration: none; } .nav-list__icon { flex: none; opacity: 0.5; } .nav-list__label { flex: 1; font-weight: 600; } .nav-list__desc { color: var(--color-foreground--65); font-variant: all-small-caps; margin-left: 1rem; } .nav-list__group { width: 100%; display: flex; justify-content: flex-start; } .nav-list__group .nav-list__label { width: auto; } .nav-list__access { flex: none; position: relative; left: 1.2rem; font-size: x-small; outline: none; white-space: nowrap; --gl-feature-badge-color: color-mix(in srgb, transparent 40%, currentColor); --gl-feature-badge-border-color: color-mix(in srgb, transparent 40%, var(--color-foreground--50)); } .nav-list__item:hover .nav-list__label { text-decoration: underline; } .nav-list__item:hover .is-disabled .nav-list__label { text-decoration: none; } .nav-list__item:hover .nav-list__desc { color: var(--color-foreground); } .nav-list__item:focus-within .nav-list__access, .nav-list__item:hover .nav-list__access { --gl-feature-badge-color: currentColor; --gl-feature-badge-border-color: var(--color-foreground--50); } .nav-list__title { padding: 0 2rem; } .t-eyebrow { text-transform: uppercase; font-size: 1rem; font-weight: 600; color: var(--color-foreground--50); margin: 0; } .t-eyebrow.sticky { top: -8px; } `" + }, + { + "kind": "variable", + "name": "walkthroughProgressStyles", + "default": "css` a, a:hover, a:focus, a:active { text-decoration: none; } .walkthrough-progress { display: flex; flex-direction: column; gap: 2px; padding: 2px 4px 4px; margin-top: 4px; align-items: stretch; cursor: pointer; border-radius: 4px; } .walkthrough-progress:focus-within, .walkthrough-progress:hover { background-color: var(--gl-walkthrough-hover-background); } .walkthrough-progress__title { display: flex; justify-content: space-between; align-items: center; color: var(--color-foreground--85); } .walkthrough-progress__button { --button-padding: 1px 2px 0px 2px; position: absolute; right: 0.4rem; } .walkthrough-progress__bar::-webkit-progress-bar { border-radius: 2px; background: var(--color-alert-neutralBackground); } .walkthrough-progress__bar::-webkit-progress-value { background: var(--vscode-progressBar-background, blue); transition: 0.1s ease-in; border-radius: 2px; } .walkthrough-progress__bar { pointer-events: none; border-radius: 2px; width: 100%; background: unset; height: 4px; flex-shrink: 0; z-index: 2; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "homeBaseStyles", + "declaration": { + "name": "homeBaseStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + }, + { + "kind": "js", + "name": "homeStyles", + "declaration": { + "name": "homeStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + }, + { + "kind": "js", + "name": "buttonStyles", + "declaration": { + "name": "buttonStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + }, + { + "kind": "js", + "name": "alertStyles", + "declaration": { + "name": "alertStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + }, + { + "kind": "js", + "name": "navListStyles", + "declaration": { + "name": "navListStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + }, + { + "kind": "js", + "name": "walkthroughProgressStyles", + "declaration": { + "name": "walkthroughProgressStyles", + "module": "src/webviews/apps/home/home.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/home/home.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlHomeApp", + "members": [ { - "kind": "method", - "name": "updateState", + "kind": "field", + "name": "_activeOverviewState", + "type": { + "text": "ActiveOverviewState" + }, "privacy": "private" }, { - "kind": "method", - "name": "setAdditionalSettings", - "privacy": "private", - "parameters": [ - { - "name": "expression", - "type": { - "text": "string | undefined" - } - } - ] - }, - { - "kind": "method", - "name": "setEnablement", - "privacy": "private", - "parameters": [ - { - "name": "state", - "type": { - "text": "Record" - } - } - ] - }, - { - "kind": "method", - "name": "setVisibility", - "privacy": "private", - "parameters": [ - { - "name": "state", - "type": { - "text": "Record" - } - } - ] + "kind": "field", + "name": "_inactiveOverviewState", + "type": { + "text": "InactiveOverviewState" + }, + "privacy": "private" }, { - "kind": "method", - "name": "updatePreview", - "privacy": "private", - "parameters": [ - { - "name": "el", - "type": { - "text": "HTMLSpanElement" - } - }, - { - "name": "value", - "optional": true, - "type": { - "text": "string" - } - } - ] + "kind": "field", + "name": "_header", + "type": { + "text": "GlHomeHeader" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onObserver", - "privacy": "private", - "parameters": [ - { - "name": "entries", - "type": { - "text": "IntersectionObserverEntry[]" - } - }, - { - "name": "_observer", - "type": { - "text": "IntersectionObserver" - } - } - ] + "kind": "field", + "name": "allAccessPromoBanner", + "type": { + "text": "GlAiAllAccessBanner" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onActionLinkClicked", + "kind": "field", + "name": "badgeSource", + "type": { + "text": "object" + }, "privacy": "private", - "parameters": [ - { - "name": "element", - "type": { - "text": "HTMLElement" - } - }, - { - "name": "e", - "type": { - "text": "MouseEvent" - } - } - ] + "default": "{ source: 'home', detail: 'badge' }" }, { "kind": "method", - "name": "onJumpToLinkClicked", - "privacy": "private", - "parameters": [ - { - "name": "element", - "type": { - "text": "HTMLAnchorElement" - } - }, - { - "name": "e", - "type": { - "text": "MouseEvent" - } + "name": "createStateProvider", + "privacy": "protected", + "return": { + "type": { + "text": "HomeStateProvider" } - ] - }, - { - "kind": "method", - "name": "onSectionHeaderClicked", - "privacy": "private", + }, "parameters": [ { - "name": "element", + "name": "bootstrap", "type": { - "text": "HTMLElement" + "text": "string" } }, { - "name": "e", - "type": { - "text": "MouseEvent" - } - } - ] - }, - { - "kind": "method", - "name": "onSettingExpanderCicked", - "privacy": "private", - "parameters": [ - { - "name": "element", + "name": "ipc", "type": { - "text": "HTMLElement" + "text": "HostIpc" } }, { - "name": "_e", + "name": "logger", "type": { - "text": "MouseEvent" + "text": "LoggerContext" } } - ] + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "method", - "name": "toggleJumpLink", - "privacy": "private", - "parameters": [ - { - "name": "anchor", - "type": { - "text": "string" - } - }, - { - "name": "active", - "type": { - "text": "boolean" - } + "name": "refreshAiAllAccessPromo", + "return": { + "type": { + "text": "void" } - ] + } }, { - "kind": "method", - "name": "renderAutolinkIntegration", - "privacy": "private" + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "renderAutolinks", - "privacy": "private" + "kind": "field", + "name": "name", + "type": { + "text": "string" + }, + "attribute": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "_api", + "name": "placement", "type": { - "text": "HostIpcApi" + "text": "'editor' | 'view'" }, - "privacy": "private", - "readonly": true, + "default": "'editor'", + "attribute": "placement", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "field", - "name": "_hostIpc", + "name": "_ipc", "type": { "text": "HostIpc" }, - "privacy": "private", - "readonly": true, - "default": "new HostIpc(this.appName)", + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1576,12 +1376,10 @@ "type": { "text": "LoggerContext" }, - "privacy": "private", - "readonly": true, - "default": "new LoggerContext(appName)", + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1590,12 +1388,10 @@ "type": { "text": "PromosContext" }, - "privacy": "private", - "readonly": true, - "default": "new PromosContext(this._hostIpc)", + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1605,51 +1401,22 @@ "text": "TelemetryContext" }, "privacy": "protected", - "readonly": true, - "default": "new TelemetryContext(this._hostIpc)", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "field", - "name": "state", + "name": "bootstrap", "type": { - "text": "State" + "text": "string" }, - "privacy": "protected", + "privacy": "private", + "attribute": "bootstrap", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "field", - "name": "placement", - "type": { - "text": "'editor' | 'view'" - }, - "privacy": "protected", - "readonly": true, - "default": "(document.body.getAttribute('data-placement') ?? 'editor')", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "onInitialized", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1670,8 +1437,34 @@ } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "disposables", + "type": { + "text": "Disposable[]" + }, + "privacy": "protected", + "readonly": true, + "default": "[]", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1682,8 +1475,8 @@ }, "privacy": "private", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { @@ -1694,39 +1487,37 @@ }, "privacy": "private", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "field", - "name": "bindDisposables", + "name": "_sendWebviewFocusChangedCommandDebounced", "type": { - "text": "Disposable[] | undefined" + "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" }, "privacy": "private", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "kind": "method", - "name": "bind", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "_stateProvider", + "type": { + "text": "Provider" }, + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "method", - "name": "log", + "name": "onWebviewFocusChanged", "privacy": "protected", "return": { "type": { @@ -1735,40 +1526,20 @@ }, "parameters": [ { - "name": "message", - "type": { - "text": "string" - } - }, - { - "name": "optionalParams", + "name": "focused", "type": { - "text": "any[]" + "text": "boolean" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "getState", - "privacy": "protected", - "return": { - "type": { - "text": "State | undefined" - } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "method", - "name": "sendCommand", + "name": "onWebviewVisibilityChanged", "privacy": "protected", "return": { "type": { @@ -1777,157 +1548,223 @@ }, "parameters": [ { - "name": "command", - "type": { - "text": "TCommand" - } - }, - { - "name": "params", + "name": "visible", "type": { - "text": "IpcCallParamsType" + "text": "boolean" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "onFocusIn", + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "onFocusOut", + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "method", - "name": "sendRequest", - "privacy": "protected", + "name": "emit", "return": { "type": { - "text": "Promise>" + "text": "CustomEventType" } }, "parameters": [ { - "name": "requestType", + "name": "name", "type": { "text": "T" } }, { - "name": "params", + "name": "detail", "type": { - "text": "IpcCallParamsType" + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "superclass": { + "name": "GlAppHost", + "module": "/src/webviews/apps/shared/appHost" + }, + "tagName": "gl-home-app", + "customElement": true, + "attributes": [ + { + "name": "name", + "type": { + "text": "string" + }, + "fieldName": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "kind": "method", - "name": "setState", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "name": "placement", + "type": { + "text": "'editor' | 'view'" }, - "parameters": [ - { - "name": "state", - "type": { - "text": "Partial" - } - } - ], + "default": "'editor'", + "fieldName": "placement", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "kind": "field", "name": "bootstrap", - "default": "undefined", + "type": { + "text": "string" + }, + "fieldName": "bootstrap", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } } - ], - "superclass": { - "name": "App", - "module": "/src/webviews/apps/shared/appBase" - } + ] } ], "exports": [ { "kind": "js", - "name": "SettingsApp", + "name": "GlHomeApp", "declaration": { - "name": "SettingsApp", - "module": "src/webviews/apps/settings/settings.ts" + "name": "GlHomeApp", + "module": "src/webviews/apps/home/home.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-home-app", + "declaration": { + "name": "GlHomeApp", + "module": "src/webviews/apps/home/home.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/appBase.ts", + "path": "src/webviews/apps/home/stateProvider.ts", "declarations": [ { "kind": "class", "description": "", - "name": "App", + "name": "HomeStateProvider", "members": [ { - "kind": "field", - "name": "_api", - "type": { - "text": "HostIpcApi" + "kind": "method", + "name": "createContextProvider", + "privacy": "protected", + "return": { + "type": { + "text": "ContextProvider" + } }, - "privacy": "private", - "readonly": true + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "field", - "name": "_hostIpc", - "type": { - "text": "HostIpc" + "kind": "method", + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "privacy": "private", - "readonly": true, - "default": "new HostIpc(this.appName)" + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_logger", + "name": "disposable", "type": { - "text": "LoggerContext" + "text": "Disposable" }, - "privacy": "private", + "privacy": "protected", "readonly": true, - "default": "new LoggerContext(appName)" + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_promos", + "name": "provider", "type": { - "text": "PromosContext" + "text": "ContextProvider" }, - "privacy": "private", + "privacy": "protected", "readonly": true, - "default": "new PromosContext(this._hostIpc)" + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_telemetry", + "name": "_state", "type": { - "text": "TelemetryContext" + "text": "State" }, "privacy": "protected", - "readonly": true, - "default": "new TelemetryContext(this._hostIpc)" + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", @@ -1935,69 +1772,82 @@ "type": { "text": "State" }, - "privacy": "protected" + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "placement", - "type": { - "text": "'editor' | 'view'" - }, - "privacy": "protected", + "name": "webviewId", "readonly": true, - "default": "(document.body.getAttribute('data-placement') ?? 'editor')" + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "method", - "name": "onInitialize", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "webviewInstanceId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { - "kind": "method", - "name": "onBind", - "privacy": "protected", - "return": { - "type": { - "text": "Disposable[]" - } + "kind": "field", + "name": "timestamp", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onInitialized", - "privacy": "protected", + "name": "dispose", "return": { "type": { "text": "void" } + }, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "deferBootstrap", + "type": { + "text": "boolean" + }, + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onMessageReceived", + "name": "initializeState", "privacy": "protected", "return": { "type": { - "text": "void" + "text": "Promise" } }, - "parameters": [ - { - "name": "msg", - "type": { - "text": "IpcMessage" - } - } - ] + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "onThemeUpdated", + "name": "onPersistState", "privacy": "protected", "return": { "type": { @@ -2006,74 +1856,128 @@ }, "parameters": [ { - "name": "e", + "name": "state", "type": { - "text": "ThemeChangeEvent" + "text": "State" } } - ] + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + } + ], + "superclass": { + "name": "StateProviderBase", + "module": "/src/webviews/apps/shared/stateProviderBase" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "HomeStateProvider", + "declaration": { + "name": "HomeStateProvider", + "module": "src/webviews/apps/home/stateProvider.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/rebase/rebase.ts", + "declarations": [], + "exports": [] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/settings/settings.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "SettingsApp", + "members": [ + { + "kind": "field", + "name": "_scopes", + "type": { + "text": "HTMLSelectElement | null" + }, + "privacy": "private", + "default": "null" }, { "kind": "field", - "name": "_focused", + "name": "_observer", "type": { - "text": "boolean | undefined" + "text": "IntersectionObserver | undefined" }, "privacy": "private" }, { "kind": "field", - "name": "_inputFocused", + "name": "_activeSection", "type": { - "text": "boolean | undefined" + "text": "string | undefined" }, - "privacy": "private" + "privacy": "private", + "default": "'general'" }, { "kind": "field", - "name": "bindDisposables", + "name": "_changes", + "privacy": "private", + "default": "Object.create(null)" + }, + { + "kind": "field", + "name": "_sections", + "privacy": "private", + "default": "new Map()" + }, + { + "kind": "field", + "name": "_updating", "type": { - "text": "Disposable[] | undefined" + "text": "boolean" }, - "privacy": "private" + "privacy": "private", + "default": "false" }, { "kind": "method", - "name": "bind", + "name": "onInitialize", "privacy": "protected", "return": { "type": { "text": "void" } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { "kind": "method", - "name": "log", + "name": "onBind", "privacy": "protected", "return": { "type": { - "text": "void" + "text": "Disposable[]" } }, - "parameters": [ - { - "name": "message", - "type": { - "text": "string" - } - }, - { - "name": "optionalParams", - "type": { - "text": "any[]" - } - } - ] + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "method", - "name": "log", + "name": "onMessageReceived", "privacy": "protected", "return": { "type": { @@ -2082,903 +1986,969 @@ }, "parameters": [ { - "name": "scope", - "type": { - "text": "LogScope | undefined" - } - }, - { - "name": "message", - "type": { - "text": "string" - } - }, - { - "name": "optionalParams", + "name": "msg", "type": { - "text": "any[]" + "text": "IpcMessage" } } - ] + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "method", - "name": "log", - "privacy": "protected", - "return": { - "type": { - "text": "void" + "name": "applyChanges", + "privacy": "private" + }, + { + "kind": "method", + "name": "getSettingsScope", + "privacy": "private", + "return": { + "type": { + "text": "'user' | 'workspace'" } - }, + } + }, + { + "kind": "method", + "name": "onInputBlurred", + "privacy": "private", "parameters": [ { - "name": "scopeOrMessage", + "name": "element", "type": { - "text": "LogScope | string | undefined" + "text": "HTMLInputElement" } - }, + } + ] + }, + { + "kind": "method", + "name": "onButtonClicked", + "privacy": "private", + "parameters": [ { - "name": "optionalParams", + "name": "element", "type": { - "text": "any[]" + "text": "HTMLButtonElement" } } ] }, { "kind": "method", - "name": "getState", - "privacy": "protected", - "return": { - "type": { - "text": "State | undefined" + "name": "onInputChanged", + "privacy": "private", + "parameters": [ + { + "name": "element", + "type": { + "text": "HTMLInputElement" + } } - } + ] }, { "kind": "method", - "name": "sendCommand", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onInputChecked", + "privacy": "private", "parameters": [ { - "name": "command", + "name": "element", "type": { - "text": "TCommand" + "text": "HTMLInputElement" } - }, + } + ] + }, + { + "kind": "method", + "name": "onInputFocused", + "privacy": "private", + "parameters": [ { - "name": "params", + "name": "element", "type": { - "text": "IpcCallParamsType" + "text": "HTMLInputElement" } } ] }, { "kind": "method", - "name": "sendRequest", - "privacy": "protected", - "return": { - "type": { - "text": "Promise>" + "name": "onInputSelected", + "privacy": "private", + "parameters": [ + { + "name": "element", + "type": { + "text": "HTMLSelectElement" + } } - }, + ] + }, + { + "kind": "method", + "name": "onTokenMouseDown", + "privacy": "private", "parameters": [ { - "name": "requestType", + "name": "element", "type": { - "text": "T" + "text": "HTMLElement" } }, { - "name": "params", + "name": "e", "type": { - "text": "IpcCallParamsType" + "text": "MouseEvent" } } ] }, { "kind": "method", - "name": "setState", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "scrollToAnchor", + "privacy": "private", "parameters": [ { - "name": "state", + "name": "anchor", "type": { - "text": "Partial" + "text": "string" + } + }, + { + "name": "behavior", + "type": { + "text": "ScrollBehavior" + } + }, + { + "name": "offset", + "optional": true, + "type": { + "text": "number" } } ] }, { "kind": "field", - "name": "bootstrap", - "default": "undefined" - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "App", - "declaration": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/appHost.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlAppHost", - "members": [ - { - "kind": "field", - "name": "shadowRootOptions", - "type": { - "text": "ShadowRootInit" - }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" - }, - { - "kind": "field", - "name": "name", - "type": { - "text": "string" - }, - "attribute": "name" - }, - { - "kind": "field", - "name": "placement", - "type": { - "text": "'editor' | 'view'" - }, - "default": "'editor'", - "attribute": "placement" - }, - { - "kind": "field", - "name": "_ipc", - "type": { - "text": "HostIpc" - }, - "privacy": "protected" - }, - { - "kind": "field", - "name": "_logger", - "type": { - "text": "LoggerContext" - }, - "privacy": "protected" - }, - { - "kind": "field", - "name": "_promos", - "type": { - "text": "PromosContext" - }, - "privacy": "protected" - }, - { - "kind": "field", - "name": "_telemetry", + "name": "_scrollTimer", "type": { - "text": "TelemetryContext" + "text": "ReturnType | undefined" }, - "privacy": "protected" + "privacy": "private" }, { - "kind": "field", - "name": "bootstrap", - "type": { - "text": "State" - }, + "kind": "method", + "name": "scrollTo", "privacy": "private", - "attribute": "bootstrap" + "parameters": [ + { + "name": "el", + "type": { + "text": "HTMLElement" + } + }, + { + "name": "behavior", + "type": { + "text": "ScrollBehavior" + } + }, + { + "name": "offset", + "optional": true, + "type": { + "text": "number" + } + } + ] }, { "kind": "method", - "name": "onThemeUpdated", - "privacy": "protected", + "name": "evaluateStateExpression", + "privacy": "private", "return": { "type": { - "text": "void" + "text": "boolean" } }, "parameters": [ { - "name": "e", + "name": "expression", "type": { - "text": "ThemeChangeEvent" + "text": "string" + } + }, + { + "name": "changes", + "type": { + "text": "Record" } } ] }, { - "kind": "field", - "name": "state", - "type": { - "text": "State" + "kind": "method", + "name": "getCustomSettingValue", + "privacy": "private", + "return": { + "type": { + "text": "boolean | undefined" + } }, - "readonly": true + "parameters": [ + { + "name": "path", + "type": { + "text": "string" + } + } + ] }, { - "kind": "field", - "name": "disposables", - "type": { - "text": "Disposable[]" + "kind": "method", + "name": "getSettingValue", + "privacy": "private", + "return": { + "type": { + "text": "T | undefined" + } }, - "privacy": "protected", - "readonly": true, - "default": "[]" + "parameters": [ + { + "name": "path", + "type": { + "text": "string" + } + } + ] }, { - "kind": "field", - "name": "_focused", - "type": { - "text": "boolean | undefined" - }, + "kind": "method", + "name": "updateState", "privacy": "private" }, { - "kind": "field", - "name": "_inputFocused", - "type": { - "text": "boolean | undefined" - }, - "privacy": "private" + "kind": "method", + "name": "setAdditionalSettings", + "privacy": "private", + "parameters": [ + { + "name": "expression", + "type": { + "text": "string | undefined" + } + } + ] }, { - "kind": "field", - "name": "_sendWebviewFocusChangedCommandDebounced", - "type": { - "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" - }, - "privacy": "private" + "kind": "method", + "name": "setEnablement", + "privacy": "private", + "parameters": [ + { + "name": "state", + "type": { + "text": "Record" + } + } + ] }, { - "kind": "field", - "name": "_stateProvider", - "type": { - "text": "StateProvider" - }, - "privacy": "private" + "kind": "method", + "name": "setVisibility", + "privacy": "private", + "parameters": [ + { + "name": "state", + "type": { + "text": "Record" + } + } + ] }, { "kind": "method", - "name": "createStateProvider", - "privacy": "protected", - "return": { - "type": { - "text": "StateProvider" - } - }, + "name": "updatePreview", + "privacy": "private", "parameters": [ { - "name": "state", + "name": "el", "type": { - "text": "State" + "text": "HTMLSpanElement" } }, { - "name": "ipc", + "name": "value", + "optional": true, "type": { - "text": "HostIpc" + "text": "string" } } ] }, { "kind": "method", - "name": "onPersistState", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onObserver", + "privacy": "private", "parameters": [ { - "name": "state", + "name": "entries", "type": { - "text": "State" + "text": "IntersectionObserverEntry[]" + } + }, + { + "name": "_observer", + "type": { + "text": "IntersectionObserver" } } ] }, { "kind": "method", - "name": "onWebviewFocusChanged", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onActionLinkClicked", + "privacy": "private", "parameters": [ { - "name": "focused", + "name": "element", "type": { - "text": "boolean" + "text": "HTMLElement" + } + }, + { + "name": "e", + "type": { + "text": "MouseEvent" } } ] }, { "kind": "method", - "name": "onWebviewVisibilityChanged", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onJumpToLinkClicked", + "privacy": "private", "parameters": [ { - "name": "visible", + "name": "element", "type": { - "text": "boolean" + "text": "HTMLAnchorElement" + } + }, + { + "name": "e", + "type": { + "text": "MouseEvent" } } ] }, { - "kind": "field", - "name": "onFocusIn", - "privacy": "private" - }, - { - "kind": "field", - "name": "onFocusOut", - "privacy": "private" + "kind": "method", + "name": "onSectionHeaderClicked", + "privacy": "private", + "parameters": [ + { + "name": "element", + "type": { + "text": "HTMLElement" + } + }, + { + "name": "e", + "type": { + "text": "MouseEvent" + } + } + ] }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, + "name": "onSettingExpanderCicked", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "element", "type": { - "text": "T" + "text": "HTMLElement" } }, { - "name": "detail", + "name": "_e", "type": { - "text": "CustomEventDetailType" + "text": "MouseEvent" + } + } + ] + }, + { + "kind": "method", + "name": "toggleJumpLink", + "privacy": "private", + "parameters": [ + { + "name": "anchor", + "type": { + "text": "string" } }, { - "name": "options", - "optional": true, + "name": "active", "type": { - "text": "Omit>, 'detail'>" + "text": "boolean" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ + ] + }, { - "name": "name", - "type": { - "text": "string" - }, - "fieldName": "name" + "kind": "method", + "name": "renderAutolinkIntegration", + "privacy": "private" }, { - "name": "placement", - "type": { - "text": "'editor' | 'view'" - }, - "default": "'editor'", - "fieldName": "placement" + "kind": "method", + "name": "renderAutolinks", + "privacy": "private" }, { - "name": "bootstrap", + "kind": "field", + "name": "_api", "type": { - "text": "State" + "text": "HostIpcApi" }, - "fieldName": "bootstrap" - } - ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } - } - ], - "exports": [ - { - "kind": "js", - "name": "GlAppHost", - "declaration": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/date.ts", - "declarations": [], - "exports": [ - { - "kind": "js", - "name": "*", - "declaration": { - "name": "*", - "package": "../../../system/date" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/dom.ts", - "declarations": [ - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ - { - "name": "window", - "type": { - "text": "Window" + "privacy": "private", + "readonly": true, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "name", + "kind": "field", + "name": "_hostIpc", "type": { - "text": "K" + "text": "HostIpc" + }, + "privacy": "private", + "readonly": true, + "default": "new HostIpc(this.appName)", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "listener", + "kind": "field", + "name": "_logger", "type": { - "text": "(e: WindowEventMap[K], target: Window) => void" + "text": "LoggerContext" + }, + "privacy": "private", + "readonly": true, + "default": "new LoggerContext(appName)", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "options", - "optional": true, - "type": { - "text": "boolean | AddEventListenerOptions" - } - } - ] - }, - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ - { - "name": "document", + "kind": "field", + "name": "_promos", "type": { - "text": "Document" + "text": "PromosContext" + }, + "privacy": "private", + "readonly": true, + "default": "new PromosContext(this._hostIpc)", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "name", + "kind": "field", + "name": "_telemetry", "type": { - "text": "K" + "text": "TelemetryContext" + }, + "privacy": "protected", + "readonly": true, + "default": "new TelemetryContext(this._hostIpc)", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "listener", + "kind": "field", + "name": "state", "type": { - "text": "(e: DocumentEventMap[K], target: Document) => void" + "text": "State" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "options", - "optional": true, + "kind": "field", + "name": "placement", "type": { - "text": "boolean | AddEventListenerOptions" + "text": "'editor' | 'view'" + }, + "privacy": "protected", + "readonly": true, + "default": "(document.body.getAttribute('data-placement') ?? 'editor')", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } - } - ] - }, - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ + }, { - "name": "element", - "type": { - "text": "T" + "kind": "method", + "name": "onInitialized", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "name", - "type": { - "text": "K" + "kind": "method", + "name": "onThemeUpdated", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "ThemeChangeEvent" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "listener", + "kind": "field", + "name": "_focused", "type": { - "text": "(e: DocumentEventMap[K] & { target: HTMLElement | null }, target: T) => void" + "text": "boolean | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "options", - "optional": true, + "kind": "field", + "name": "_inputFocused", "type": { - "text": "boolean | AddEventListenerOptions" + "text": "boolean | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } - } - ] - }, - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ + }, { - "name": "element", + "kind": "field", + "name": "bindDisposables", "type": { - "text": "T" + "text": "Disposable[] | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "name", - "type": { - "text": "string" + "kind": "method", + "name": "bind", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "listener", - "type": { - "text": "(e: CustomEvent & { target: HTMLElement | null }, target: T) => void" + "kind": "method", + "name": "log", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "message", + "type": { + "text": "string" + } + }, + { + "name": "optionalParams", + "type": { + "text": "any[]" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "options", - "optional": true, - "type": { - "text": "boolean | AddEventListenerOptions" + "kind": "method", + "name": "getState", + "privacy": "protected", + "return": { + "type": { + "text": "State | undefined" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } - } - ] - }, - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ + }, { - "name": "selector", - "type": { - "text": "string" + "kind": "method", + "name": "sendCommand", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "TCommand" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "name", - "type": { - "text": "K" + "kind": "method", + "name": "sendRequest", + "privacy": "protected", + "return": { + "type": { + "text": "Promise>" + } + }, + "parameters": [ + { + "name": "requestType", + "type": { + "text": "T" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "listener", - "type": { - "text": "(e: DocumentEventMap[K] & { target: HTMLElement | null }, target: T) => void" + "kind": "method", + "name": "setState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "state", + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "options", - "optional": true, - "type": { - "text": "boolean | AddEventListenerOptions" + "kind": "field", + "name": "bootstrap", + "default": "undefined", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } } - ] - }, + ], + "superclass": { + "name": "App", + "module": "/src/webviews/apps/shared/appBase" + } + } + ], + "exports": [ { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ + "kind": "js", + "name": "SettingsApp", + "declaration": { + "name": "SettingsApp", + "module": "src/webviews/apps/settings/settings.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/appBase.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "App", + "members": [ { - "name": "selector", + "kind": "field", + "name": "_api", "type": { - "text": "string" - } + "text": "HostIpcApi" + }, + "privacy": "private", + "readonly": true }, { - "name": "name", + "kind": "field", + "name": "_hostIpc", "type": { - "text": "string" - } + "text": "HostIpc" + }, + "privacy": "private", + "readonly": true, + "default": "new HostIpc(this.appName)" }, { - "name": "listener", + "kind": "field", + "name": "_logger", "type": { - "text": "(e: CustomEvent & { target: HTMLElement | null }, target: T) => void" - } + "text": "LoggerContext" + }, + "privacy": "private", + "readonly": true, + "default": "new LoggerContext(appName)" }, { - "name": "options", - "optional": true, - "type": { - "text": "boolean | AddEventListenerOptions" - } - } - ] - }, - { - "kind": "function", - "name": "on", - "return": { - "type": { - "text": "Disposable" - } - }, - "parameters": [ - { - "name": "sourceOrSelector", + "kind": "field", + "name": "_promos", "type": { - "text": "string | Window | Document | Element" - } + "text": "PromosContext" + }, + "privacy": "private", + "readonly": true, + "default": "new PromosContext(this._hostIpc)" }, { - "name": "name", + "kind": "field", + "name": "_telemetry", "type": { - "text": "K" - } + "text": "TelemetryContext" + }, + "privacy": "protected", + "readonly": true, + "default": "new TelemetryContext(this._hostIpc)" }, { - "name": "listener", - "type": { - "text": "(e: (DocumentEventMap | WindowEventMap)[K] | CustomEvent, target: T) => void" - } + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "privacy": "protected" }, { - "name": "options", - "optional": true, + "kind": "field", + "name": "placement", "type": { - "text": "boolean | AddEventListenerOptions" - } - } - ] - }, - { - "kind": "function", - "name": "parseDuration", - "return": { - "type": { - "text": "number" - } - }, - "parameters": [ + "text": "'editor' | 'view'" + }, + "privacy": "protected", + "readonly": true, + "default": "(document.body.getAttribute('data-placement') ?? 'editor')" + }, { - "name": "delay", - "type": { - "text": "number | string" + "kind": "method", + "name": "onInitialize", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } } - } - ], - "description": "Parses a CSS duration and returns the number of milliseconds." - }, - { - "kind": "function", - "name": "waitForEvent", - "return": { - "type": { - "text": "Promise" - } - }, - "parameters": [ + }, { - "name": "el", - "type": { - "text": "HTMLElement" + "kind": "method", + "name": "onBind", + "privacy": "protected", + "return": { + "type": { + "text": "Disposable[]" + } } }, { - "name": "eventName", - "type": { - "text": "string" + "kind": "method", + "name": "onInitialized", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } } - } - ], - "description": "Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements." - } - ], - "exports": [ - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "on", - "declaration": { - "name": "on", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "parseDuration", - "declaration": { - "name": "parseDuration", - "module": "src/webviews/apps/shared/dom.ts" - } - }, - { - "kind": "js", - "name": "waitForEvent", - "declaration": { - "name": "waitForEvent", - "module": "src/webviews/apps/shared/dom.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/events.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "Emitter", - "members": [ + }, { - "kind": "field", - "name": "_noop", - "privacy": "private", - "static": true, - "readonly": true, - "default": "function (this: void) { /* noop */ }" + "kind": "method", + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ] }, { - "kind": "field", - "name": "_disposed", - "type": { - "text": "boolean" + "kind": "method", + "name": "onThemeUpdated", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "privacy": "private", - "default": "false" + "parameters": [ + { + "name": "e", + "type": { + "text": "ThemeChangeEvent" + } + } + ] }, { "kind": "field", - "name": "_event", + "name": "_focused", "type": { - "text": "Event | undefined" + "text": "boolean | undefined" }, "privacy": "private" }, { "kind": "field", - "name": "_deliveryQueue", + "name": "_inputFocused", "type": { - "text": "LinkedList<[Listener, T]> | undefined" + "text": "boolean | undefined" }, "privacy": "private" }, { "kind": "field", - "name": "listeners", + "name": "bindDisposables", "type": { - "text": "LinkedList> | undefined" + "text": "Disposable[] | undefined" }, - "privacy": "protected" + "privacy": "private" }, { - "kind": "field", - "name": "event", - "type": { - "text": "Event" + "kind": "method", + "name": "bind", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "method", + "name": "log", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "description": "For the public to allow to subscribe\nto events from this Emitter", - "readonly": true + "parameters": [ + { + "name": "message", + "type": { + "text": "string" + } + }, + { + "name": "optionalParams", + "type": { + "text": "any[]" + } + } + ] }, { "kind": "method", - "name": "fire", + "name": "log", + "privacy": "protected", "return": { "type": { "text": "void" @@ -2986,22 +2956,129 @@ }, "parameters": [ { - "name": "event", + "name": "scope", "type": { - "text": "T" + "text": "LogScope | undefined" + } + }, + { + "name": "message", + "type": { + "text": "string" + } + }, + { + "name": "optionalParams", + "type": { + "text": "any[]" } } - ], - "description": "To be kept private to fire an event to\nsubscribers" + ] }, { "kind": "method", - "name": "dispose", + "name": "log", + "privacy": "protected", "return": { "type": { "text": "void" } + }, + "parameters": [ + { + "name": "scopeOrMessage", + "type": { + "text": "LogScope | string | undefined" + } + }, + { + "name": "optionalParams", + "type": { + "text": "any[]" + } + } + ] + }, + { + "kind": "method", + "name": "getState", + "privacy": "protected", + "return": { + "type": { + "text": "State | undefined" + } } + }, + { + "kind": "method", + "name": "sendCommand", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "TCommand" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ] + }, + { + "kind": "method", + "name": "sendRequest", + "privacy": "protected", + "return": { + "type": { + "text": "Promise>" + } + }, + "parameters": [ + { + "name": "requestType", + "type": { + "text": "T" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ] + }, + { + "kind": "method", + "name": "setState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "state", + "type": { + "text": "Partial" + } + } + ] + }, + { + "kind": "field", + "name": "bootstrap", + "default": "undefined" } ] } @@ -3009,341 +3086,192 @@ "exports": [ { "kind": "js", - "name": "Emitter", + "name": "App", "declaration": { - "name": "Emitter", - "module": "src/webviews/apps/shared/events.ts" + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/git-utils.ts", + "path": "src/webviews/apps/shared/appHost.ts", "declarations": [ { - "kind": "function", - "name": "getRemoteNameSlashIndex", - "return": { - "type": { - "text": "number" - } - }, - "parameters": [ + "kind": "class", + "description": "", + "name": "GlAppHost", + "members": [ { - "name": "name", + "kind": "field", + "name": "shadowRootOptions", "type": { - "text": "string" - } - } - ] - }, - { - "kind": "function", - "name": "getBranchNameWithoutRemote", - "return": { - "type": { - "text": "string" - } - }, - "parameters": [ + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, { + "kind": "field", "name": "name", "type": { "text": "string" - } - } - ] - }, - { - "kind": "function", - "name": "getRemoteNameFromBranchName", - "return": { - "type": { - "text": "string" - } - }, - "parameters": [ + }, + "attribute": "name" + }, { - "name": "name", + "kind": "field", + "name": "placement", "type": { - "text": "string" - } - } - ] - }, - { - "kind": "function", - "name": "isRevisionRange", - "return": { - "type": { - "text": "ref is GitRevisionRange" - } - }, - "parameters": [ + "text": "'editor' | 'view'" + }, + "default": "'editor'", + "attribute": "placement" + }, { - "name": "ref", + "kind": "field", + "name": "_ipc", "type": { - "text": "string | undefined" - } + "text": "HostIpc" + }, + "privacy": "protected" }, { - "name": "rangeType", - "default": "'any'", + "kind": "field", + "name": "_logger", "type": { - "text": "'any' | 'qualified' | 'qualified-double-dot' | 'qualified-triple-dot'" - } - } - ] - }, - { - "kind": "function", - "name": "isShaParent", - "return": { - "type": { - "text": "boolean" - } - }, - "parameters": [ + "text": "LoggerContext" + }, + "privacy": "protected" + }, { - "name": "ref", + "kind": "field", + "name": "_promos", "type": { - "text": "string" - } - } - ] - }, - { - "kind": "function", - "name": "isStashReference", - "return": { - "type": { - "text": "ref is GitStashReference" - } - }, - "parameters": [ + "text": "PromosContext" + }, + "privacy": "protected" + }, { - "name": "ref", - "type": { - "text": "GitReference | undefined" - } - } - ] - }, - { - "kind": "function", - "name": "getReferenceLabel", - "return": { - "type": { - "text": "string" - } - }, - "parameters": [ - { - "name": "refs", + "kind": "field", + "name": "_telemetry", "type": { - "text": "GitReference | undefined" - } + "text": "TelemetryContext" + }, + "privacy": "protected" }, - { - "name": "options", - "optional": true, - "type": { - "text": "{ capitalize?: boolean; expand?: boolean; icon?: boolean; label?: boolean; quoted?: boolean } | false" - } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "getRemoteNameSlashIndex", - "declaration": { - "name": "getRemoteNameSlashIndex", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "getBranchNameWithoutRemote", - "declaration": { - "name": "getBranchNameWithoutRemote", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "getRemoteNameFromBranchName", - "declaration": { - "name": "getRemoteNameFromBranchName", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "isRevisionRange", - "declaration": { - "name": "isRevisionRange", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "isShaParent", - "declaration": { - "name": "isShaParent", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "isStashReference", - "declaration": { - "name": "isStashReference", - "module": "src/webviews/apps/shared/git-utils.ts" - } - }, - { - "kind": "js", - "name": "getReferenceLabel", - "declaration": { - "name": "getReferenceLabel", - "module": "src/webviews/apps/shared/git-utils.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/ipc.ts", - "declarations": [ - { - "kind": "function", - "name": "getHostIpcApi", - "return": { - "type": { - "text": "HostIpcApi" - } - } - }, - { - "kind": "class", - "description": "", - "name": "HostIpc", - "members": [ { "kind": "field", - "name": "_onReceiveMessage", + "name": "bootstrap", + "type": { + "text": "string" + }, "privacy": "private", - "default": "new Emitter()" + "attribute": "bootstrap" }, { - "kind": "field", - "name": "onReceiveMessage", - "type": { - "text": "Event" + "kind": "method", + "name": "onThemeUpdated", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "readonly": true + "parameters": [ + { + "name": "e", + "type": { + "text": "ThemeChangeEvent" + } + } + ] }, { "kind": "field", - "name": "_api", + "name": "state", "type": { - "text": "HostIpcApi" + "text": "State" }, - "privacy": "private", "readonly": true }, { "kind": "field", - "name": "_disposable", + "name": "disposables", "type": { - "text": "Disposable" + "text": "Disposable[]" }, - "privacy": "private", - "readonly": true + "privacy": "protected", + "readonly": true, + "default": "[]" }, { "kind": "field", - "name": "_pendingHandlers", - "privacy": "private", - "default": "new Map()" + "name": "_focused", + "type": { + "text": "boolean | undefined" + }, + "privacy": "private" }, { "kind": "field", - "name": "_textDecoder", + "name": "_inputFocused", "type": { - "text": "TextDecoder | undefined" + "text": "boolean | undefined" }, "privacy": "private" }, { - "kind": "method", - "name": "dispose", - "return": { - "type": { - "text": "void" - } - } + "kind": "field", + "name": "_sendWebviewFocusChangedCommandDebounced", + "type": { + "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onMessageReceived", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MessageEvent" - } - } - ] + "kind": "field", + "name": "_stateProvider", + "type": { + "text": "Provider" + }, + "privacy": "protected" }, { "kind": "method", - "name": "replaceIpcPromisesWithPromises", + "name": "createStateProvider", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "Provider" } }, "parameters": [ { - "name": "data", + "name": "bootstrap", "type": { - "text": "unknown" + "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "sendCommand", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ + }, { - "name": "commandType", + "name": "ipc", "type": { - "text": "T" + "text": "HostIpc" } }, { - "name": "params", - "optional": true, + "name": "logger", "type": { - "text": "never" + "text": "LoggerContext" } } ] }, { "kind": "method", - "name": "sendCommand", + "name": "onWebviewFocusChanged", + "privacy": "protected", "return": { "type": { "text": "void" @@ -3351,22 +3279,17 @@ }, "parameters": [ { - "name": "commandType", - "type": { - "text": "T" - } - }, - { - "name": "params", + "name": "focused", "type": { - "text": "IpcCallParamsType" + "text": "boolean" } } ] }, { "kind": "method", - "name": "sendCommand", + "name": "onWebviewVisibilityChanged", + "privacy": "protected", "return": { "type": { "text": "void" @@ -3374,766 +3297,996 @@ }, "parameters": [ { - "name": "commandType", - "type": { - "text": "T" - } - }, - { - "name": "params", - "optional": true, + "name": "visible", "type": { - "text": "IpcCallParamsType" + "text": "boolean" } } ] }, + { + "kind": "field", + "name": "onFocusIn", + "privacy": "private" + }, + { + "kind": "field", + "name": "onFocusOut", + "privacy": "private" + }, { "kind": "method", - "name": "sendRequest", + "name": "emit", "return": { "type": { - "text": "Promise>" + "text": "CustomEventType" } }, "parameters": [ { - "name": "requestType", + "name": "name", "type": { "text": "T" } }, { - "name": "params", - "type": { - "text": "IpcCallParamsType" - } - } - ] - }, - { - "kind": "method", - "name": "getResponsePromise", - "privacy": "private", - "parameters": [ - { - "name": "method", + "name": "detail", "type": { - "text": "string" + "text": "CustomEventDetailType" } }, { - "name": "id", + "name": "options", + "optional": true, "type": { - "text": "string" + "text": "Omit>, 'detail'>" } } - ] - }, + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ { - "kind": "method", - "name": "setPersistedState", - "return": { - "type": { - "text": "void" - } + "name": "name", + "type": { + "text": "string" }, - "parameters": [ - { - "name": "state", - "type": { - "text": "Partial" - } - } - ] + "fieldName": "name" }, { - "kind": "method", - "name": "updatePersistedState", - "return": { - "type": { - "text": "void" - } + "name": "placement", + "type": { + "text": "'editor' | 'view'" }, - "parameters": [ - { - "name": "update", - "type": { - "text": "Partial" - } - } - ] + "default": "'editor'", + "fieldName": "placement" }, { - "kind": "method", - "name": "postMessage", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "IpcMessage" - } - } - ] - } - ] - }, - { - "kind": "function", - "name": "assertsSerialized", - "return": { - "type": { - "text": "asserts obj is Serialized" - } - }, - "parameters": [ - { - "name": "obj", + "name": "bootstrap", "type": { - "text": "unknown" - } + "text": "string" + }, + "fieldName": "bootstrap" } - ] + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } } ], "exports": [ { "kind": "js", - "name": "getHostIpcApi", - "declaration": { - "name": "getHostIpcApi", - "module": "src/webviews/apps/shared/ipc.ts" - } - }, - { - "kind": "js", - "name": "HostIpc", + "name": "GlAppHost", "declaration": { - "name": "HostIpc", - "module": "src/webviews/apps/shared/ipc.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } - }, + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/date.ts", + "declarations": [], + "exports": [ { "kind": "js", - "name": "assertsSerialized", + "name": "*", "declaration": { - "name": "assertsSerialized", - "module": "src/webviews/apps/shared/ipc.ts" + "name": "*", + "module": "src/system/date" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/telemetry.ts", + "path": "src/webviews/apps/shared/dom.ts", "declarations": [ - { - "kind": "variable", - "name": "telemetryEventName", - "type": { - "text": "string" - }, - "default": "'gl-telemetry-fired'" - }, { "kind": "function", - "name": "emitTelemetrySentEvent", + "name": "on", "return": { "type": { - "text": "void" + "text": "Disposable" } }, "parameters": [ { - "name": "el", + "name": "window", "type": { - "text": "EventTarget" + "text": "Window" } }, { - "name": "params", + "name": "name", "type": { - "text": "TelemetrySendEventParams" + "text": "K" + } + }, + { + "name": "listener", + "type": { + "text": "(e: WindowEventMap[K], target: Window) => void" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "boolean | AddEventListenerOptions" } } ] - } - ], - "exports": [ - { - "kind": "js", - "name": "telemetryEventName", - "declaration": { - "name": "telemetryEventName", - "module": "src/webviews/apps/shared/telemetry.ts" - } - }, - { - "kind": "js", - "name": "emitTelemetrySentEvent", - "declaration": { - "name": "emitTelemetrySentEvent", - "module": "src/webviews/apps/shared/telemetry.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/theme.ts", - "declarations": [ - { - "kind": "variable", - "name": "onDidChangeTheme", - "type": { - "text": "Event" - } }, { "kind": "function", - "name": "computeThemeColors", + "name": "on", "return": { "type": { - "text": "ThemeChangeEvent" + "text": "Disposable" } }, "parameters": [ { - "name": "mutations", + "name": "document", + "type": { + "text": "Document" + } + }, + { + "name": "name", + "type": { + "text": "K" + } + }, + { + "name": "listener", + "type": { + "text": "(e: DocumentEventMap[K], target: Document) => void" + } + }, + { + "name": "options", "optional": true, "type": { - "text": "MutationRecord[]" + "text": "boolean | AddEventListenerOptions" } } ] }, { "kind": "function", - "name": "watchThemeColors", + "name": "on", "return": { "type": { "text": "Disposable" } - } - } - ], - "exports": [ - { - "kind": "js", - "name": "onDidChangeTheme", - "declaration": { - "name": "onDidChangeTheme", - "module": "src/webviews/apps/shared/theme.ts" - } - }, - { - "kind": "js", - "name": "computeThemeColors", - "declaration": { - "name": "computeThemeColors", - "module": "src/webviews/apps/shared/theme.ts" - } - }, - { - "kind": "js", - "name": "watchThemeColors", - "declaration": { - "name": "watchThemeColors", - "module": "src/webviews/apps/shared/theme.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/commitDetails/components/button.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "buttonStyles", - "default": "css` .button-container { margin: 1rem auto 0; text-align: left; max-width: 30rem; transition: max-width 0.2s ease-out; } @media (min-width: 640px) { .button-container { max-width: 100%; } } .button-group { display: inline-flex; gap: 0.1rem; } .button-group--single { width: 100%; max-width: 30rem; } .button-group > *:not(:first-child), .button-group > *:not(:first-child) gl-button { border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group > *:not(:last-child), .button-group > *:not(:last-child) gl-button { border-top-right-radius: 0; border-bottom-right-radius: 0; } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "buttonStyles", - "declaration": { - "name": "buttonStyles", - "module": "src/webviews/apps/commitDetails/components/button.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/commitDetails/components/commit-action.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "commitActionStyles", - "default": "css` .commit-action { display: inline-flex; justify-content: center; align-items: center; height: 21px; border-radius: 0.25em; color: inherit; padding: 0.2rem; vertical-align: text-bottom; text-decoration: none; gap: 0.2rem; } .commit-action > * { pointer-events: none; } .commit-action:focus { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } .commit-action:hover { color: var(--vscode-foreground); text-decoration: none; } :host-context(.vscode-dark) .commit-action:hover, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .commit-action:hover { background-color: var(--color-background--lighten-15); } :host-context(.vscode-light) .commit-action:hover, :host-context(.vscode-high-contrast-light) .commit-action:hover { background-color: var(--color-background--darken-15); } :host-context(.vscode-dark) .commit-action.is-active, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .commit-action.is-active { background-color: var(--color-background--lighten-10); } :host-context(.vscode-light) .commit-action.is-active, :host-context(.vscode-high-contrast-light) .commit-action.is-active { background-color: var(--color-background--darken-10); } .commit-action.is-disabled { opacity: 0.5; pointer-events: none; } .commit-action.is-hidden { display: none; } .commit-action--emphasis-low:not(:hover, :focus, :active) { opacity: 0.5; } .pr--opened { color: var(--vscode-gitlens-openPullRequestIconColor); } .pr--closed { color: var(--vscode-gitlens-closedPullRequestIconColor); } .pr--merged { color: var(--vscode-gitlens-mergedPullRequestIconColor); } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "commitActionStyles", - "declaration": { - "name": "commitActionStyles", - "module": "src/webviews/apps/commitDetails/components/commit-action.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/commitDetails/components/commit-details-app.ts", - "declarations": [ - { - "kind": "variable", - "name": "uncommittedSha", - "type": { - "text": "string" }, - "default": "'0000000000000000000000000000000000000000'" - }, - { - "kind": "class", - "description": "", - "name": "GlCommitDetailsApp", - "members": [ + "parameters": [ { - "kind": "field", - "name": "state", + "name": "element", "type": { - "text": "Serialized | undefined" - }, - "attribute": "state" + "text": "T" + } }, { - "kind": "field", - "name": "explain", + "name": "name", "type": { - "text": "ExplainState | undefined" - }, - "attribute": "explain" + "text": "K" + } }, { - "kind": "field", - "name": "generate", + "name": "listener", "type": { - "text": "GenerateState | undefined" - }, - "attribute": "generate" + "text": "(e: DocumentEventMap[K] & { target: HTMLElement | null }, target: T) => void" + } }, { - "kind": "field", - "name": "draftState", + "name": "options", + "optional": true, "type": { - "text": "DraftState" - }, - "default": "{ inReview: false }" - }, + "text": "boolean | AddEventListenerOptions" + } + } + ] + }, + { + "kind": "function", + "name": "on", + "return": { + "type": { + "text": "Disposable" + } + }, + "parameters": [ { - "kind": "field", - "name": "isUncommitted", + "name": "element", "type": { - "text": "boolean" - }, - "readonly": true + "text": "T" + } }, { - "kind": "field", - "name": "hasCommit", + "name": "name", "type": { - "text": "boolean" - }, - "readonly": true + "text": "string" + } }, { - "kind": "field", - "name": "isStash", + "name": "listener", "type": { - "text": "boolean" - }, - "readonly": true + "text": "(e: CustomEvent & { target: HTMLElement | null }, target: T) => void" + } }, { - "kind": "field", - "name": "wipStatus", - "readonly": true + "name": "options", + "optional": true, + "type": { + "text": "boolean | AddEventListenerOptions" + } + } + ] + }, + { + "kind": "function", + "name": "on", + "return": { + "type": { + "text": "Disposable" + } + }, + "parameters": [ + { + "name": "selector", + "type": { + "text": "string" + } }, { - "kind": "field", - "name": "navigation", - "readonly": true + "name": "name", + "type": { + "text": "K" + } }, { - "kind": "field", - "name": "_disposables", + "name": "listener", "type": { - "text": "Disposable[]" - }, - "privacy": "private", - "default": "[]" + "text": "(e: DocumentEventMap[K] & { target: HTMLElement | null }, target: T) => void" + } }, { - "kind": "field", - "name": "_hostIpc", + "name": "options", + "optional": true, "type": { - "text": "HostIpc" - }, - "privacy": "private" + "text": "boolean | AddEventListenerOptions" + } + } + ] + }, + { + "kind": "function", + "name": "on", + "return": { + "type": { + "text": "Disposable" + } + }, + "parameters": [ + { + "name": "selector", + "type": { + "text": "string" + } }, { - "kind": "field", - "name": "indentPreference", + "name": "name", "type": { - "text": "number" - }, - "privacy": "private", - "default": "16" + "text": "string" + } }, { - "kind": "method", - "name": "updateDocumentProperties", - "privacy": "private" + "name": "listener", + "type": { + "text": "(e: CustomEvent & { target: HTMLElement | null }, target: T) => void" + } }, { - "kind": "method", - "name": "onSuggestChanges", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CreatePatchEventDetail" - } - } - ] + "name": "options", + "optional": true, + "type": { + "text": "boolean | AddEventListenerOptions" + } + } + ] + }, + { + "kind": "function", + "name": "on", + "return": { + "type": { + "text": "Disposable" + } + }, + "parameters": [ + { + "name": "sourceOrSelector", + "type": { + "text": "string | Window | Document | Element" + } }, { - "kind": "method", - "name": "onShowCodeSuggestion", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "{ id: string }" - } - } - ] + "name": "name", + "type": { + "text": "K" + } }, { - "kind": "method", - "name": "onMessageReceived", - "privacy": "private", - "parameters": [ - { - "name": "msg", - "type": { - "text": "IpcMessage" - } - } - ] + "name": "listener", + "type": { + "text": "(e: (DocumentEventMap | WindowEventMap)[K] | CustomEvent, target: T) => void" + } }, { - "kind": "method", - "name": "renderTopInspect", - "privacy": "private" + "name": "options", + "optional": true, + "type": { + "text": "boolean | AddEventListenerOptions" + } + } + ] + }, + { + "kind": "function", + "name": "parseDuration", + "return": { + "type": { + "text": "number" + } + }, + "parameters": [ + { + "name": "delay", + "type": { + "text": "number | string" + } + } + ], + "description": "Parses a CSS duration and returns the number of milliseconds." + }, + { + "kind": "function", + "name": "waitForEvent", + "return": { + "type": { + "text": "Promise" + } + }, + "parameters": [ + { + "name": "el", + "type": { + "text": "HTMLElement" + } }, { - "kind": "method", - "name": "renderTopWip", - "privacy": "private" + "name": "eventName", + "type": { + "text": "string" + } + } + ], + "description": "Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements." + } + ], + "exports": [ + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "on", + "declaration": { + "name": "on", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "parseDuration", + "declaration": { + "name": "parseDuration", + "module": "src/webviews/apps/shared/dom.ts" + } + }, + { + "kind": "js", + "name": "waitForEvent", + "declaration": { + "name": "waitForEvent", + "module": "src/webviews/apps/shared/dom.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/events.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "Emitter", + "members": [ + { + "kind": "field", + "name": "_noop", + "privacy": "private", + "static": true, + "readonly": true, + "default": "function (this: void) { /* noop */ }" }, { - "kind": "method", - "name": "renderRepoStatusContent", + "kind": "field", + "name": "_disposed", + "type": { + "text": "boolean" + }, "privacy": "private", - "parameters": [ - { - "name": "_isWip", - "type": { - "text": "boolean" - } - } - ] + "default": "false" }, { - "kind": "method", - "name": "renderWipTooltipContent", + "kind": "field", + "name": "_event", + "type": { + "text": "Event | undefined" + }, "privacy": "private" }, { - "kind": "method", - "name": "renderTopSection", + "kind": "field", + "name": "_deliveryQueue", + "type": { + "text": "LinkedList<[Listener, T]> | undefined" + }, "privacy": "private" }, { - "kind": "method", - "name": "onDraftStateChanged", - "privacy": "private", - "parameters": [ - { - "name": "inReview", - "type": { - "text": "boolean" - } - }, - { - "name": "silent", - "default": "false" - } - ] + "kind": "field", + "name": "listeners", + "type": { + "text": "LinkedList> | undefined" + }, + "privacy": "protected" }, { - "kind": "method", - "name": "onBranchAction", - "privacy": "private", - "parameters": [ - { - "name": "name", - "type": { - "text": "string" - } - } - ] + "kind": "field", + "name": "event", + "type": { + "text": "Event" + }, + "description": "For the public to allow to subscribe\nto events from this Emitter", + "readonly": true }, { "kind": "method", - "name": "onCreatePatchFromWip", - "privacy": "private", + "name": "fire", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "checked", - "default": "true", + "name": "event", "type": { - "text": "boolean | 'staged'" + "text": "T" } } - ] + ], + "description": "To be kept private to fire an event to\nsubscribers" }, { "kind": "method", - "name": "onCommandClickedCore", - "privacy": "private", - "parameters": [ - { - "name": "action", - "optional": true, - "type": { - "text": "GlCommands | `command:${GlCommands}`" - } + "name": "dispose", + "return": { + "type": { + "text": "void" } - ] + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "Emitter", + "declaration": { + "name": "Emitter", + "module": "src/webviews/apps/shared/events.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/git-utils.ts", + "declarations": [ + { + "kind": "function", + "name": "getRemoteNameSlashIndex", + "return": { + "type": { + "text": "number" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "function", + "name": "getBranchNameWithoutRemote", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "function", + "name": "getRemoteNameFromBranchName", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "function", + "name": "isRevisionRange", + "return": { + "type": { + "text": "ref is GitRevisionRange" + } + }, + "parameters": [ + { + "name": "ref", + "type": { + "text": "string | undefined" + } }, { - "kind": "method", - "name": "onSwitchAiModel", + "name": "rangeType", + "default": "'any'", + "type": { + "text": "'any' | 'qualified' | 'qualified-double-dot' | 'qualified-triple-dot'" + } + } + ] + }, + { + "kind": "function", + "name": "isShaParent", + "return": { + "type": { + "text": "boolean" + } + }, + "parameters": [ + { + "name": "ref", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "function", + "name": "isStashReference", + "return": { + "type": { + "text": "ref is GitStashReference" + } + }, + "parameters": [ + { + "name": "ref", + "type": { + "text": "GitReference | undefined" + } + } + ] + }, + { + "kind": "function", + "name": "getReferenceLabel", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "refs", + "type": { + "text": "GitReference | undefined" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "{ capitalize?: boolean; expand?: boolean; icon?: boolean; label?: boolean; quoted?: boolean } | false" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "getRemoteNameSlashIndex", + "declaration": { + "name": "getRemoteNameSlashIndex", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "getBranchNameWithoutRemote", + "declaration": { + "name": "getBranchNameWithoutRemote", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "getRemoteNameFromBranchName", + "declaration": { + "name": "getRemoteNameFromBranchName", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "isRevisionRange", + "declaration": { + "name": "isRevisionRange", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "isShaParent", + "declaration": { + "name": "isShaParent", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "isStashReference", + "declaration": { + "name": "isStashReference", + "module": "src/webviews/apps/shared/git-utils.ts" + } + }, + { + "kind": "js", + "name": "getReferenceLabel", + "declaration": { + "name": "getReferenceLabel", + "module": "src/webviews/apps/shared/git-utils.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/ipc.ts", + "declarations": [ + { + "kind": "function", + "name": "getHostIpcApi", + "return": { + "type": { + "text": "HostIpcApi" + } + } + }, + { + "kind": "class", + "description": "", + "name": "HostIpc", + "members": [ + { + "kind": "field", + "name": "_onReceiveMessage", "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "MouseEvent" - } - } - ] + "default": "new Emitter()" }, { - "kind": "method", - "name": "onExplainCommit", + "kind": "field", + "name": "onReceiveMessage", + "type": { + "text": "Event" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_api", + "type": { + "text": "HostIpcApi" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "MouseEvent" - } - } - ] + "readonly": true }, { - "kind": "method", - "name": "onCreateGenerateTitle", + "kind": "field", + "name": "_disposable", + "type": { + "text": "Disposable" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "CreatePatchMetadataEventDetail" - } - } - ] + "readonly": true }, { - "kind": "method", - "name": "onToggleFilesLayout", + "kind": "field", + "name": "_pendingHandlers", "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MouseEvent" - } + "default": "new Map()" + }, + { + "kind": "method", + "name": "dispose", + "return": { + "type": { + "text": "void" } - ] + } }, { "kind": "method", - "name": "onExpandedChange", + "name": "onMessageReceived", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "WebviewPaneExpandedChangeEventDetail" - } - }, - { - "name": "pane", - "type": { - "text": "string" + "text": "MessageEvent" } } ] }, { "kind": "method", - "name": "onNavigate", - "privacy": "private", + "name": "deserializeIpcData", + "return": { + "type": { + "text": "T" + } + }, "parameters": [ { - "name": "direction", + "name": "data", "type": { - "text": "'back' | 'forward'" + "text": "string" } } ] }, { "kind": "method", - "name": "onTogglePin", - "privacy": "private" - }, - { - "kind": "method", - "name": "onPickCommit", - "privacy": "private", + "name": "sendCommand", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "_e", + "name": "commandType", "type": { - "text": "MouseEvent" + "text": "T" } - } - ] - }, - { - "kind": "method", - "name": "onSearchCommit", - "privacy": "private", - "parameters": [ + }, { - "name": "_e", + "name": "params", + "optional": true, "type": { - "text": "MouseEvent" + "text": "never" } } ] }, { "kind": "method", - "name": "onSwitchMode", - "privacy": "private", + "name": "sendCommand", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "_e", + "name": "commandType", "type": { - "text": "MouseEvent" + "text": "T" } }, { - "name": "mode", + "name": "params", "type": { - "text": "Mode" + "text": "IpcCallParamsType" } } ] }, { "kind": "method", - "name": "onOpenFileOnRemote", - "privacy": "private", + "name": "sendCommand", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "e", + "name": "commandType", "type": { - "text": "FileChangeListItemDetail" + "text": "T" } - } - ] - }, - { - "kind": "method", - "name": "onOpenFile", - "privacy": "private", - "parameters": [ + }, { - "name": "e", + "name": "params", + "optional": true, "type": { - "text": "FileChangeListItemDetail" + "text": "IpcCallParamsType" } } ] }, { "kind": "method", - "name": "onCompareFileWithWorking", - "privacy": "private", + "name": "sendRequest", + "return": { + "type": { + "text": "Promise>" + } + }, "parameters": [ { - "name": "e", + "name": "requestType", "type": { - "text": "FileChangeListItemDetail" + "text": "T" } - } - ] - }, - { - "kind": "method", - "name": "onCompareFileWithPrevious", - "privacy": "private", - "parameters": [ + }, { - "name": "e", + "name": "params", "type": { - "text": "FileChangeListItemDetail" + "text": "IpcCallParamsType" } } ] }, { "kind": "method", - "name": "onFileMoreActions", + "name": "getResponsePromise", "privacy": "private", "parameters": [ { - "name": "e", + "name": "method", "type": { - "text": "FileChangeListItemDetail" + "text": "string" + } + }, + { + "name": "id", + "type": { + "text": "string" } } ] }, { "kind": "method", - "name": "onStageFile", - "privacy": "private", + "name": "setPersistedState", "return": { "type": { "text": "void" @@ -4141,17 +4294,16 @@ }, "parameters": [ { - "name": "e", + "name": "state", "type": { - "text": "FileChangeListItemDetail" + "text": "Partial" } } ] }, { "kind": "method", - "name": "onUnstageFile", - "privacy": "private", + "name": "updatePersistedState", "return": { "type": { "text": "void" @@ -4159,89 +4311,433 @@ }, "parameters": [ { - "name": "e", + "name": "update", "type": { - "text": "FileChangeListItemDetail" + "text": "Partial" } } ] }, { "kind": "method", - "name": "onCommitActions", + "name": "postMessage", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "CustomEvent<{ action: string; alt: boolean }>" + "text": "IpcMessage" } } ] } - ], - "events": [ - { - "name": "state-changed", - "type": { - "text": "CustomEvent" - } + ] + }, + { + "kind": "function", + "name": "assertsSerialized", + "return": { + "type": { + "text": "asserts obj is Serialized" } - ], - "attributes": [ - { - "name": "state", - "type": { - "text": "Serialized | undefined" - }, - "fieldName": "state" - }, - { - "name": "explain", - "type": { - "text": "ExplainState | undefined" - }, - "fieldName": "explain" - }, + }, + "parameters": [ { - "name": "generate", + "name": "obj", "type": { - "text": "GenerateState | undefined" - }, - "fieldName": "generate" + "text": "unknown" + } } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-commit-details-app", - "customElement": true + ] } ], "exports": [ { "kind": "js", - "name": "uncommittedSha", + "name": "getHostIpcApi", "declaration": { - "name": "uncommittedSha", - "module": "src/webviews/apps/commitDetails/components/commit-details-app.ts" + "name": "getHostIpcApi", + "module": "src/webviews/apps/shared/ipc.ts" } }, { "kind": "js", - "name": "GlCommitDetailsApp", + "name": "HostIpc", "declaration": { - "name": "GlCommitDetailsApp", - "module": "src/webviews/apps/commitDetails/components/commit-details-app.ts" + "name": "HostIpc", + "module": "src/webviews/apps/shared/ipc.ts" } }, { - "kind": "custom-element-definition", - "name": "gl-commit-details-app", + "kind": "js", + "name": "assertsSerialized", "declaration": { - "name": "GlCommitDetailsApp", - "module": "src/webviews/apps/commitDetails/components/commit-details-app.ts" + "name": "assertsSerialized", + "module": "src/webviews/apps/shared/ipc.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/onboarding.ts", + "declarations": [ + { + "kind": "function", + "name": "createOnboarding", + "return": { + "type": { + "text": "Driver" + } + }, + "parameters": [ + { + "name": "steps", + "type": { + "text": "KeyedDriveStep[]" + } + }, + { + "name": "config", + "default": "{}", + "type": { + "text": "Exclude" + } + }, + { + "name": "onHighlightedByKey", + "optional": true, + "type": { + "text": "KeyedDriverHook" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "createOnboarding", + "declaration": { + "name": "createOnboarding", + "module": "src/webviews/apps/shared/onboarding.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/stateProviderBase.ts", + "declarations": [ + { + "kind": "class", + "description": "Base class for webview state providers that handles bootstrap initialization.\n\nSubclasses declare their bootstrap strategy ('sync' or 'async') and implement\nmessage handling. The base class automatically handles state initialization:\n- Sync: Uses bootstrap state from HTML\n- Async: Requests full state from extension after connection", + "name": "StateProviderBase", + "members": [ + { + "kind": "field", + "name": "disposable", + "type": { + "text": "Disposable" + }, + "privacy": "protected", + "readonly": true + }, + { + "kind": "field", + "name": "provider", + "type": { + "text": "ContextProvider" + }, + "privacy": "protected", + "readonly": true + }, + { + "kind": "field", + "name": "_state", + "type": { + "text": "State" + }, + "privacy": "protected" + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "readonly": true + }, + { + "kind": "field", + "name": "webviewId", + "readonly": true + }, + { + "kind": "field", + "name": "webviewInstanceId", + "readonly": true + }, + { + "kind": "field", + "name": "timestamp", + "readonly": true + }, + { + "kind": "method", + "name": "dispose", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "field", + "name": "deferBootstrap", + "type": { + "text": "boolean" + }, + "privacy": "protected", + "readonly": true + }, + { + "kind": "method", + "name": "createContextProvider", + "privacy": "protected", + "return": { + "type": { + "text": "ContextProvider" + } + }, + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ] + }, + { + "kind": "method", + "name": "initializeState", + "privacy": "protected", + "return": { + "type": { + "text": "Promise" + } + } + }, + { + "kind": "method", + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ] + }, + { + "kind": "method", + "name": "onPersistState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ] + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "StateProviderBase", + "declaration": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/telemetry.ts", + "declarations": [ + { + "kind": "variable", + "name": "telemetryEventName", + "type": { + "text": "string" + }, + "default": "'gl-telemetry-fired'" + }, + { + "kind": "function", + "name": "emitTelemetrySentEvent", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "el", + "type": { + "text": "EventTarget" + } + }, + { + "name": "params", + "type": { + "text": "TelemetrySendEventParams" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "telemetryEventName", + "declaration": { + "name": "telemetryEventName", + "module": "src/webviews/apps/shared/telemetry.ts" + } + }, + { + "kind": "js", + "name": "emitTelemetrySentEvent", + "declaration": { + "name": "emitTelemetrySentEvent", + "module": "src/webviews/apps/shared/telemetry.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/theme.ts", + "declarations": [ + { + "kind": "variable", + "name": "onDidChangeTheme", + "type": { + "text": "Event" + } + }, + { + "kind": "function", + "name": "computeThemeColors", + "return": { + "type": { + "text": "ThemeChangeEvent" + } + }, + "parameters": [ + { + "name": "mutations", + "optional": true, + "type": { + "text": "MutationRecord[]" + } + } + ] + }, + { + "kind": "function", + "name": "watchThemeColors", + "return": { + "type": { + "text": "Disposable" + } + } + } + ], + "exports": [ + { + "kind": "js", + "name": "onDidChangeTheme", + "declaration": { + "name": "onDidChangeTheme", + "module": "src/webviews/apps/shared/theme.ts" + } + }, + { + "kind": "js", + "name": "computeThemeColors", + "declaration": { + "name": "computeThemeColors", + "module": "src/webviews/apps/shared/theme.ts" + } + }, + { + "kind": "js", + "name": "watchThemeColors", + "declaration": { + "name": "watchThemeColors", + "module": "src/webviews/apps/shared/theme.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/commitDetails/components/button.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "buttonStyles", + "default": "css` .button-container { margin: 1rem auto 0; text-align: left; max-width: 30rem; transition: max-width 0.2s ease-out; } @media (min-width: 640px) { .button-container { max-width: 100%; } } .button-group { display: inline-flex; gap: 0.1rem; } .button-group--single { width: 100%; max-width: 30rem; } .button-group > *:not(:first-child), .button-group > *:not(:first-child) gl-button { border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group > *:not(:last-child), .button-group > *:not(:last-child) gl-button { border-top-right-radius: 0; border-bottom-right-radius: 0; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "buttonStyles", + "declaration": { + "name": "buttonStyles", + "module": "src/webviews/apps/commitDetails/components/button.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/commitDetails/components/commit-action.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "commitActionStyles", + "default": "css` .commit-action { display: inline-flex; justify-content: center; align-items: center; height: 21px; border-radius: 0.25em; color: inherit; padding: 0.2rem; vertical-align: text-bottom; text-decoration: none; gap: 0.2rem; } .commit-action > * { pointer-events: none; } .commit-action:focus { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } .commit-action:hover { color: var(--vscode-foreground); text-decoration: none; } :host-context(.vscode-dark) .commit-action:hover, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .commit-action:hover { background-color: var(--color-background--lighten-15); } :host-context(.vscode-light) .commit-action:hover, :host-context(.vscode-high-contrast-light) .commit-action:hover { background-color: var(--color-background--darken-15); } :host-context(.vscode-dark) .commit-action.is-active, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .commit-action.is-active { background-color: var(--color-background--lighten-10); } :host-context(.vscode-light) .commit-action.is-active, :host-context(.vscode-high-contrast-light) .commit-action.is-active { background-color: var(--color-background--darken-10); } .commit-action.is-disabled { opacity: 0.5; pointer-events: none; } .commit-action.is-hidden { display: none; } .commit-action--emphasis-low:not(:hover, :focus, :active) { opacity: 0.5; } .pr--opened { color: var(--vscode-gitlens-openPullRequestIconColor); } .pr--closed { color: var(--vscode-gitlens-closedPullRequestIconColor); } .pr--merged { color: var(--vscode-gitlens-mergedPullRequestIconColor); } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "commitActionStyles", + "declaration": { + "name": "commitActionStyles", + "module": "src/webviews/apps/commitDetails/components/commit-action.css.ts" } } ] @@ -4272,7 +4768,7 @@ "kind": "field", "name": "state", "type": { - "text": "Serialized | undefined" + "text": "State | undefined" }, "attribute": "state" }, @@ -4308,6 +4804,52 @@ }, "attribute": "explain" }, + { + "kind": "field", + "name": "_commit", + "type": { + "text": "State['commit']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "commit", + "type": { + "text": "State['commit']" + } + }, + { + "kind": "field", + "name": "_enriched", + "type": { + "text": "Awaited['enriched']>" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "enriched", + "type": { + "text": "Awaited['enriched']>" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_enrichedPromise", + "type": { + "text": "NonNullable['enriched']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "enrichedPromise", + "type": { + "text": "NonNullable['enriched']" + } + }, { "kind": "field", "name": "navigation", @@ -4406,6 +4948,28 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "method", + "name": "getFileContextData", + "privacy": "protected", + "return": { + "type": { + "text": "string | undefined" + } + }, + "parameters": [ + { + "name": "file", + "type": { + "text": "File" + } + } + ], + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "field", "name": "files", @@ -4443,6 +5007,18 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "field", + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "attribute": "orgSettings", + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "field", "name": "emptyText", @@ -4533,6 +5109,20 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "method", + "name": "renderChangedFilesActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult<1> | undefined" + } + }, + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "method", "name": "onShareWipChanges", @@ -5093,7 +5683,7 @@ { "name": "state", "type": { - "text": "Serialized | undefined" + "text": "State | undefined" }, "fieldName": "state" }, @@ -5138,6 +5728,17 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "fieldName": "orgSettings", + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "name": "empty-text", "type": { @@ -5221,6 +5822,14 @@ }, "attribute": "preferences" }, + { + "kind": "field", + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "attribute": "orgSettings" + }, { "kind": "field", "name": "emptyText", @@ -5287,6 +5896,16 @@ } ] }, + { + "kind": "method", + "name": "renderChangedFilesActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult<1> | undefined" + } + } + }, { "kind": "method", "name": "onShareWipChanges", @@ -5512,6 +6131,24 @@ } ] }, + { + "kind": "method", + "name": "getFileContextData", + "privacy": "protected", + "return": { + "type": { + "text": "string | undefined" + } + }, + "parameters": [ + { + "name": "_file", + "type": { + "text": "File" + } + } + ] + }, { "kind": "method", "name": "fileToTreeModel", @@ -5799,6 +6436,13 @@ }, "fieldName": "preferences" }, + { + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "fieldName": "orgSettings" + }, { "name": "empty-text", "type": { @@ -6256,14 +6900,6 @@ }, "attribute": "wip" }, - { - "kind": "field", - "name": "orgSettings", - "type": { - "text": "State['orgSettings'] | undefined" - }, - "attribute": "orgSettings" - }, { "kind": "field", "name": "draftState", @@ -6280,6 +6916,15 @@ }, "attribute": "generate" }, + { + "kind": "field", + "name": "experimentalComposerEnabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "experimentalComposerEnabled" + }, { "kind": "field", "name": "inReview", @@ -6328,6 +6973,9 @@ { "kind": "field", "name": "patchCreateState", + "type": { + "text": "CreatePatchState" + }, "readonly": true }, { @@ -6347,10 +6995,30 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "method", + "name": "renderChangedFilesActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult<1> | undefined" + } + }, + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "method", "name": "renderSecondaryAction", - "privacy": "private" + "privacy": "private", + "parameters": [ + { + "name": "hasPrimary", + "default": "true" + } + ] }, { "kind": "method", @@ -6411,6 +7079,28 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "method", + "name": "getFileContextData", + "privacy": "protected", + "return": { + "type": { + "text": "string | undefined" + } + }, + "parameters": [ + { + "name": "file", + "type": { + "text": "File" + } + } + ], + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "method", "name": "onDataActionClick", @@ -6487,6 +7177,18 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "kind": "field", + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "attribute": "orgSettings", + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "kind": "field", "name": "emptyText", @@ -7155,13 +7857,6 @@ }, "fieldName": "wip" }, - { - "name": "orgSettings", - "type": { - "text": "State['orgSettings'] | undefined" - }, - "fieldName": "orgSettings" - }, { "name": "draftState", "type": { @@ -7176,6 +7871,14 @@ }, "fieldName": "generate" }, + { + "name": "experimentalComposerEnabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "experimentalComposerEnabled" + }, { "name": "files", "type": { @@ -7210,6 +7913,17 @@ "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" } }, + { + "name": "orgSettings", + "type": { + "text": "State['orgSettings'] | undefined" + }, + "fieldName": "orgSettings", + "inheritedFrom": { + "name": "GlDetailsBase", + "module": "src/webviews/apps/commitDetails/components/gl-details-base.ts" + } + }, { "name": "empty-text", "type": { @@ -7252,13 +7966,30 @@ }, { "kind": "javascript-module", - "path": "src/webviews/apps/home/components/ama-banner.ts", + "path": "src/webviews/apps/home/components/ai-all-access-banner.ts", "declarations": [ + { + "kind": "variable", + "name": "aiAllAccessBannerTagName", + "type": { + "text": "string" + }, + "default": "'gl-ai-all-access-banner'" + }, { "kind": "class", "description": "", - "name": "GlAmaBanner", + "name": "GlAiAllAccessBanner", "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, { "kind": "field", "name": "_state", @@ -7277,198 +8008,298 @@ }, { "kind": "field", - "name": "closed", + "name": "shouldShow", "type": { "text": "boolean" }, "privacy": "private", - "default": "false" + "readonly": true }, - { - "kind": "method", - "name": "onClose", - "privacy": "private" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-ama-banner", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlAmaBanner", - "declaration": { - "name": "GlAmaBanner", - "module": "src/webviews/apps/home/components/ama-banner.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-ama-banner", - "declaration": { - "name": "GlAmaBanner", - "module": "src/webviews/apps/home/components/ama-banner.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/home/components/feature-nav.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlFeatureNav", - "members": [ { "kind": "field", - "name": "badgeSource", + "name": "bodyLabel", "type": { - "text": "Source" + "text": "string" }, "privacy": "private", - "default": "{ source: 'home', detail: 'badge' }", - "attribute": "badgeSource" + "readonly": true }, { "kind": "field", - "name": "_state", + "name": "primaryButtonLabel", "type": { - "text": "State" + "text": "string" }, - "privacy": "private" + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "orgAllowsDrafts", + "name": "hasAdvancedOrHigher", "type": { "text": "boolean" }, - "readonly": true - }, - { - "kind": "field", - "name": "blockRepoFeatures", "privacy": "private", "readonly": true }, { "kind": "method", - "name": "onRepoFeatureClicked", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MouseEvent" - } - } - ] - }, - { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ - { - "name": "badgeSource", - "type": { - "text": "Source" - }, - "default": "{ source: 'home', detail: 'badge' }", - "fieldName": "badgeSource" + "name": "onSecondaryClick", + "privacy": "private" } ], "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" + "name": "LitElement", + "package": "lit" }, - "tagName": "gl-feature-nav", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlFeatureNav", + "name": "aiAllAccessBannerTagName", "declaration": { - "name": "GlFeatureNav", - "module": "src/webviews/apps/home/components/feature-nav.ts" + "name": "aiAllAccessBannerTagName", + "module": "src/webviews/apps/home/components/ai-all-access-banner.ts" + } + }, + { + "kind": "js", + "name": "GlAiAllAccessBanner", + "declaration": { + "name": "GlAiAllAccessBanner", + "module": "src/webviews/apps/home/components/ai-all-access-banner.ts" } }, { "kind": "custom-element-definition", - "name": "gl-feature-nav", "declaration": { - "name": "GlFeatureNav", - "module": "src/webviews/apps/home/components/feature-nav.ts" + "name": "GlAiAllAccessBanner", + "module": "src/webviews/apps/home/components/ai-all-access-banner.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/home/components/integration-banner.ts", + "path": "src/webviews/apps/home/components/ama-banner.ts", "declarations": [ - { - "kind": "variable", - "name": "integrationBannerTagName", - "type": { - "text": "string" - }, - "default": "'gl-integration-banner'" - }, { "kind": "class", "description": "", - "name": "GlIntegrationBanner", + "name": "GlAmaBanner", "members": [ - { - "kind": "field", - "name": "shadowRootOptions", - "type": { - "text": "ShadowRootInit" - }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" - }, + { + "kind": "field", + "name": "_state", + "type": { + "text": "State" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_ipc", + "type": { + "text": "HostIpc" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "closed", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "method", + "name": "onClose", + "privacy": "private" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-ama-banner", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlAmaBanner", + "declaration": { + "name": "GlAmaBanner", + "module": "src/webviews/apps/home/components/ama-banner.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-ama-banner", + "declaration": { + "name": "GlAmaBanner", + "module": "src/webviews/apps/home/components/ama-banner.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/home/components/feature-nav.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlFeatureNav", + "members": [ + { + "kind": "field", + "name": "badgeSource", + "type": { + "text": "Source" + }, + "privacy": "private", + "default": "{ source: 'home', detail: 'badge' }", + "attribute": "badgeSource" + }, + { + "kind": "field", + "name": "_state", + "type": { + "text": "State" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "orgAllowsDrafts", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "blockRepoFeatures", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "onRepoFeatureClicked", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + } + ] + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "badgeSource", + "type": { + "text": "Source" + }, + "default": "{ source: 'home', detail: 'badge' }", + "fieldName": "badgeSource" + } + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + }, + "tagName": "gl-feature-nav", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlFeatureNav", + "declaration": { + "name": "GlFeatureNav", + "module": "src/webviews/apps/home/components/feature-nav.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-feature-nav", + "declaration": { + "name": "GlFeatureNav", + "module": "src/webviews/apps/home/components/feature-nav.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/home/components/integration-banner.ts", + "declarations": [ + { + "kind": "variable", + "name": "integrationBannerTagName", + "type": { + "text": "string" + }, + "default": "'gl-integration-banner'" + }, + { + "kind": "class", + "description": "", + "name": "GlIntegrationBanner", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, { "kind": "field", "name": "_state", @@ -7575,6 +8406,16 @@ }, "privacy": "private" }, + { + "kind": "method", + "name": "renderWalkthroughProgress", + "privacy": "private", + "return": { + "type": { + "text": "unknown" + } + } + }, { "kind": "field", "name": "onDismissWalkthrough", @@ -7885,52 +8726,149 @@ }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/patchDetails/patchDetails.ts", + "path": "src/webviews/apps/plus/composer/composer.ts", "declarations": [ - { - "kind": "variable", - "name": "uncommittedSha", - "type": { - "text": "string" - }, - "default": "'0000000000000000000000000000000000000000'" - }, { "kind": "class", "description": "", - "name": "PatchDetailsApp", + "name": "ComposerAppHost", "members": [ { "kind": "method", - "name": "onInitialize", + "name": "createStateProvider", "privacy": "protected", "return": { "type": { - "text": "void" + "text": "ComposerStateProvider" } }, + "parameters": [ + { + "name": "bootstrap", + "type": { + "text": "string" + } + }, + { + "name": "ipc", + "type": { + "text": "HostIpc" + } + }, + { + "name": "logger", + "type": { + "text": "LoggerContext" + } + } + ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "kind": "method", - "name": "onBind", + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "name", + "type": { + "text": "string" + }, + "attribute": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "placement", + "type": { + "text": "'editor' | 'view'" + }, + "default": "'editor'", + "attribute": "placement", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "_ipc", + "type": { + "text": "HostIpc" + }, "privacy": "protected", - "return": { - "type": { - "text": "Disposable[]" - } + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "_logger", + "type": { + "text": "LoggerContext" }, + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "_promos", + "type": { + "text": "PromosContext" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "_telemetry", + "type": { + "text": "TelemetryContext" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "kind": "field", + "name": "bootstrap", + "type": { + "text": "string" + }, + "privacy": "private", + "attribute": "bootstrap", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { "kind": "method", - "name": "onMessageReceived", + "name": "onThemeUpdated", "privacy": "protected", "return": { "type": { @@ -7939,470 +8877,444 @@ }, "parameters": [ { - "name": "msg", + "name": "e", "type": { - "text": "IpcMessage" + "text": "ThemeChangeEvent" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "kind": "method", - "name": "onPatchChecked", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "PatchCheckedDetail" - } - } - ] + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onCreateCheckRepo", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CreatePatchCheckRepositoryEventDetail" - } - } - ] + "kind": "field", + "name": "disposables", + "type": { + "text": "Disposable[]" + }, + "privacy": "protected", + "readonly": true, + "default": "[]", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onCreateUpdateMetadata", + "kind": "field", + "name": "_focused", + "type": { + "text": "boolean | undefined" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CreatePatchMetadataEventDetail" - } - } - ] + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onCreateGenerateTitle", + "kind": "field", + "name": "_inputFocused", + "type": { + "text": "boolean | undefined" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "CreatePatchMetadataEventDetail" - } - } - ] + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onDraftUpdateMetadata", + "kind": "field", + "name": "_sendWebviewFocusChangedCommandDebounced", + "type": { + "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "{ visibility: DraftVisibility }" - } - } - ] + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onDraftUpdatePermissions", - "privacy": "private" + "kind": "field", + "name": "_stateProvider", + "type": { + "text": "Provider" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "method", - "name": "onShowPatchInGraph", - "privacy": "private", + "name": "onWebviewFocusChanged", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "_e", + "name": "focused", "type": { - "text": "ShowPatchInGraphDetail" + "text": "boolean" } } - ] + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "method", - "name": "onCreatePatch", - "privacy": "private", + "name": "onWebviewVisibilityChanged", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "e", + "name": "visible", "type": { - "text": "CreatePatchEventDetail" + "text": "boolean" } } - ] - }, - { - "kind": "method", - "name": "onShareLocalPatch", - "privacy": "private" - }, - { - "kind": "method", - "name": "onCopyCloudLink", - "privacy": "private" + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onModeClicked", + "kind": "field", + "name": "onFocusIn", "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "Event" - } - } - ] + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onApplyPatch", + "kind": "field", + "name": "onFocusOut", "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "ApplyPatchDetail" - } - } - ] + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "method", - "name": "onArchiveDraft", - "privacy": "private", - "parameters": [ - { - "name": "reason", - "optional": true, - "type": { - "text": "DraftReasonEventDetail['reason']" - } + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" } - ] - }, - { - "kind": "method", - "name": "onChangePatchBase", - "privacy": "private", + }, "parameters": [ { - "name": "e", + "name": "name", "type": { - "text": "ChangePatchBaseDetail" + "text": "T" } - } - ] - }, - { - "kind": "method", - "name": "onSelectPatchRepo", - "privacy": "private", - "parameters": [ + }, { - "name": "e", + "name": "detail", "type": { - "text": "SelectPatchRepoDetail" + "text": "CustomEventDetailType" } - } - ] - }, - { - "kind": "method", - "name": "onCommandClickedCore", - "privacy": "private", - "parameters": [ + }, { - "name": "action", + "name": "options", "optional": true, "type": { - "text": "GlCommands | `command:${GlCommands}`" - } - } - ] - }, - { - "kind": "method", - "name": "onSwitchAIModel", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "MouseEvent" - } - } - ] - }, - { - "kind": "method", - "name": "onAIExplain", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "MouseEvent" - } - } - ] - }, - { - "kind": "method", - "name": "onToggleFilesLayout", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MouseEvent" + "text": "Omit>, 'detail'>" } } - ] - }, + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "superclass": { + "name": "GlAppHost", + "module": "/src/webviews/apps/shared/appHost" + }, + "tagName": "gl-composer-apphost", + "customElement": true, + "attributes": [ { - "kind": "method", - "name": "onInviteUsers", - "privacy": "private" + "name": "name", + "type": { + "text": "string" + }, + "fieldName": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onUpdateUserSelection", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CreatePatchUpdateSelectionEventDetail | PatchDetailsUpdateSelectionEventDetail" - } - } - ] + "name": "placement", + "type": { + "text": "'editor' | 'view'" + }, + "default": "'editor'", + "fieldName": "placement", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "method", - "name": "onOpenFileOnRemote", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "FileChangeListItemDetail" - } - } - ] - }, + "name": "bootstrap", + "type": { + "text": "string" + }, + "fieldName": "bootstrap", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "ComposerAppHost", + "declaration": { + "name": "ComposerAppHost", + "module": "src/webviews/apps/plus/composer/composer.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-composer-apphost", + "declaration": { + "name": "ComposerAppHost", + "module": "src/webviews/apps/plus/composer/composer.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/context.ts", + "declarations": [ + { + "kind": "variable", + "name": "stateContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "stateContext", + "declaration": { + "name": "stateContext", + "module": "src/webviews/apps/plus/composer/context.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/stateProvider.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "ComposerStateProvider", + "members": [ { "kind": "method", - "name": "onOpenFile", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "FileChangeListItemDetail" - } + "name": "createContextProvider", + "privacy": "protected", + "return": { + "type": { + "text": "ContextProvider" } - ] - }, - { - "kind": "method", - "name": "onCompareFileWithWorking", - "privacy": "private", + }, "parameters": [ { - "name": "e", + "name": "state", "type": { - "text": "FileChangeListItemDetail" + "text": "State" } } - ] + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "onCompareFileWithPrevious", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "FileChangeListItemDetail" - } + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" } - ] - }, - { - "kind": "method", - "name": "onFileMoreActions", - "privacy": "private", + }, "parameters": [ { - "name": "e", + "name": "msg", "type": { - "text": "FileChangeListItemDetail" + "text": "IpcMessage" } } - ] + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_component", + "name": "disposable", "type": { - "text": "GlPatchDetailsApp | undefined" + "text": "Disposable" }, - "privacy": "private" - }, - { - "kind": "field", - "name": "component", - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "attachState", - "privacy": "private", - "parameters": [ - { - "name": "_force", - "optional": true, - "type": { - "text": "boolean" - } - } - ] - }, - { - "kind": "field", - "name": "debouncedAttachState", - "privacy": "private" + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_api", + "name": "provider", "type": { - "text": "HostIpcApi" + "text": "ContextProvider" }, - "privacy": "private", + "privacy": "protected", "readonly": true, "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "_hostIpc", + "name": "_state", "type": { - "text": "HostIpc" + "text": "State" }, - "privacy": "private", - "readonly": true, - "default": "new HostIpc(this.appName)", + "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "_logger", + "name": "state", "type": { - "text": "LoggerContext" + "text": "State" }, - "privacy": "private", "readonly": true, - "default": "new LoggerContext(appName)", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "_promos", - "type": { - "text": "PromosContext" - }, - "privacy": "private", + "name": "webviewId", "readonly": true, - "default": "new PromosContext(this._hostIpc)", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "_telemetry", - "type": { - "text": "TelemetryContext" - }, - "privacy": "protected", + "name": "webviewInstanceId", "readonly": true, - "default": "new TelemetryContext(this._hostIpc)", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "state", - "type": { - "text": "State" + "name": "timestamp", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "method", + "name": "dispose", + "return": { + "type": { + "text": "void" + } }, - "privacy": "protected", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "field", - "name": "placement", + "name": "deferBootstrap", "type": { - "text": "'editor' | 'view'" + "text": "boolean" }, "privacy": "protected", "readonly": true, - "default": "(document.body.getAttribute('data-placement') ?? 'editor')", "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onInitialized", + "name": "initializeState", "privacy": "protected", "return": { "type": { - "text": "void" + "text": "Promise" } }, "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { "kind": "method", - "name": "onThemeUpdated", + "name": "onPersistState", "privacy": "protected", "return": { "type": { @@ -8411,291 +9323,90 @@ }, "parameters": [ { - "name": "e", + "name": "state", "type": { - "text": "ThemeChangeEvent" + "text": "State" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "field", - "name": "_focused", - "type": { - "text": "boolean | undefined" - }, - "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "field", - "name": "_inputFocused", - "type": { - "text": "boolean | undefined" - }, - "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } - }, + } + ], + "superclass": { + "name": "StateProviderBase", + "module": "/src/webviews/apps/shared/stateProviderBase" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "ComposerStateProvider", + "declaration": { + "name": "ComposerStateProvider", + "module": "src/webviews/apps/plus/composer/stateProvider.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/graph/gate.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlGraphGate", + "members": [ { "kind": "field", - "name": "bindDisposables", + "name": "graphState", "type": { - "text": "Disposable[] | undefined" - }, - "privacy": "private", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "bind", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "text": "typeof graphStateContext.__context__" } }, { "kind": "method", - "name": "log", - "privacy": "protected", + "name": "emit", "return": { "type": { - "text": "void" + "text": "CustomEventType" } }, "parameters": [ { - "name": "message", + "name": "name", "type": { - "text": "string" + "text": "T" } }, { - "name": "optionalParams", + "name": "detail", "type": { - "text": "any[]" + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" } } ], "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" } - }, + } + ], + "mixins": [ { - "kind": "method", - "name": "getState", - "privacy": "protected", - "return": { - "type": { - "text": "State | undefined" - } - }, - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "sendCommand", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "command", - "type": { - "text": "TCommand" - } - }, - { - "name": "params", - "type": { - "text": "IpcCallParamsType" - } - } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "sendRequest", - "privacy": "protected", - "return": { - "type": { - "text": "Promise>" - } - }, - "parameters": [ - { - "name": "requestType", - "type": { - "text": "T" - } - }, - { - "name": "params", - "type": { - "text": "IpcCallParamsType" - } - } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "method", - "name": "setState", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "state", - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - }, - { - "kind": "field", - "name": "bootstrap", - "default": "undefined", - "inheritedFrom": { - "name": "App", - "module": "src/webviews/apps/shared/appBase.ts" - } - } - ], - "superclass": { - "name": "App", - "module": "/src/webviews/apps/shared/appBase" - } - } - ], - "exports": [ - { - "kind": "js", - "name": "uncommittedSha", - "declaration": { - "name": "uncommittedSha", - "module": "src/webviews/apps/plus/patchDetails/patchDetails.ts" - } - }, - { - "kind": "js", - "name": "PatchDetailsApp", - "declaration": { - "name": "PatchDetailsApp", - "module": "src/webviews/apps/plus/patchDetails/patchDetails.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/context.ts", - "declarations": [ - { - "kind": "variable", - "name": "stateContext" - } - ], - "exports": [ - { - "kind": "js", - "name": "stateContext", - "declaration": { - "name": "stateContext", - "module": "src/webviews/apps/plus/graph/context.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/gate.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlGraphGate", - "members": [ - { - "kind": "field", - "name": "state", - "type": { - "text": "State" - } - }, - { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + "name": "SignalWatcher", + "package": "@lit-labs/signals" } ], "superclass": { @@ -8746,14 +9457,7 @@ }, { "kind": "field", - "name": "state", - "type": { - "text": "typeof stateContext.__context__" - } - }, - { - "kind": "field", - "name": "graphApp", + "name": "graphState", "type": { "text": "typeof graphStateContext.__context__" } @@ -8993,17 +9697,19 @@ }, { "kind": "field", - "name": "hostState", + "name": "graphState", "type": { - "text": "typeof stateContext.__context__" + "text": "typeof graphStateContext.__context__" } }, { "kind": "field", - "name": "appState", + "name": "aiAllowed", "type": { - "text": "typeof graphStateContext.__context__" - } + "text": "boolean" + }, + "privacy": "private", + "default": "true" }, { "kind": "field", @@ -9543,16 +10249,6 @@ }, "privacy": "private" }, - { - "kind": "field", - "name": "_graphState", - "type": { - "text": "typeof graphStateContext.__context__" - }, - "privacy": "private", - "readonly": true, - "default": "new GraphAppState()" - }, { "kind": "field", "name": "searching", @@ -9579,14 +10275,14 @@ "privacy": "protected", "return": { "type": { - "text": "StateProvider" + "text": "GraphStateProvider" } }, "parameters": [ { - "name": "state", + "name": "bootstrap", "type": { - "text": "State" + "text": "string" } }, { @@ -9645,29 +10341,6 @@ "module": "src/webviews/apps/shared/appHost.ts" } }, - { - "kind": "method", - "name": "applyTheme", - "privacy": "private", - "parameters": [ - { - "name": "theme", - "type": { - "text": "{ cssVariables: CssVariables; themeOpacityFactor: number }" - } - } - ] - }, - { - "kind": "method", - "name": "getGraphTheming", - "privacy": "private", - "return": { - "type": { - "text": "{ cssVariables: CssVariables; themeOpacityFactor: number }" - } - } - }, { "kind": "field", "name": "shadowRootOptions", @@ -9758,7 +10431,7 @@ "kind": "field", "name": "bootstrap", "type": { - "text": "State" + "text": "string" }, "privacy": "private", "attribute": "bootstrap", @@ -9833,31 +10506,9 @@ "kind": "field", "name": "_stateProvider", "type": { - "text": "StateProvider" + "text": "Provider" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - }, - { - "kind": "method", - "name": "onPersistState", "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "state", - "type": { - "text": "State" - } - } - ], "inheritedFrom": { "name": "GlAppHost", "module": "src/webviews/apps/shared/appHost.ts" @@ -9971,7 +10622,7 @@ { "name": "bootstrap", "type": { - "text": "State" + "text": "string" }, "fieldName": "bootstrap", "inheritedFrom": { @@ -10005,10 +10656,14 @@ "kind": "javascript-module", "path": "src/webviews/apps/plus/graph/stateProvider.ts", "declarations": [ + { + "kind": "variable", + "name": "graphStateContext" + }, { "kind": "class", "description": "", - "name": "GraphAppState", + "name": "GraphStateProvider", "members": [ { "kind": "field", @@ -10048,13 +10703,6 @@ "text": "AppState['visibleDays']" } }, - { - "kind": "field", - "name": "theming", - "type": { - "text": "AppState['theming']" - } - }, { "kind": "field", "name": "filter", @@ -10074,18 +10722,22 @@ "kind": "field", "name": "searchResultsResponse", "type": { - "text": "undefined | GraphSearchResults | GraphSearchResultsError" + "text": "GraphSearchResults | GraphSearchResultsError | undefined" } }, { "kind": "field", "name": "searchResults", - "readonly": true + "type": { + "text": "GraphSearchResults | undefined" + } }, { "kind": "field", "name": "searchResultsError", - "readonly": true + "type": { + "text": "GraphSearchResultsError | undefined" + } }, { "kind": "field", @@ -10093,1449 +10745,1473 @@ "type": { "text": "undefined | GraphSelectedRows" } - } - ] - }, - { - "kind": "variable", - "name": "graphStateContext" - }, - { - "kind": "class", - "description": "", - "name": "GraphStateProvider", - "members": [ + }, { "kind": "field", - "name": "disposable", + "name": "windowFocused", "type": { - "text": "Disposable" - }, - "privacy": "private", - "readonly": true + "text": "boolean | undefined" + } }, { "kind": "field", - "name": "provider", + "name": "webroot", "type": { - "text": "ContextProvider<{ __context__: State }, ReactiveElementHost>" - }, - "privacy": "private", - "readonly": true, - "default": "new ContextProvider(host, { context: stateContext, initialValue: state })" + "text": "string | undefined" + } }, { "kind": "field", - "name": "_state", + "name": "repositories", "type": { - "text": "State" - }, - "privacy": "private", - "readonly": true, - "default": "state" + "text": "State['repositories']" + } }, { "kind": "field", - "name": "state", - "readonly": true - }, - { - "kind": "method", - "name": "updateState", - "privacy": "private", - "parameters": [ - { - "name": "partial", - "type": { - "text": "Partial" - } - } - ] + "name": "selectedRepository", + "type": { + "text": "string | undefined" + } }, { - "kind": "method", - "name": "dispose", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "selectedRepositoryVisibility", + "type": { + "text": "State['selectedRepositoryVisibility']" } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "GraphAppState", - "declaration": { - "name": "GraphAppState", - "module": "src/webviews/apps/plus/graph/stateProvider.ts" - } - }, - { - "kind": "js", - "name": "graphStateContext", - "declaration": { - "name": "graphStateContext", - "module": "src/webviews/apps/plus/graph/stateProvider.ts" - } - }, - { - "kind": "js", - "name": "GraphStateProvider", - "declaration": { - "name": "GraphStateProvider", - "module": "src/webviews/apps/plus/graph/stateProvider.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/timeline/context.ts", - "declarations": [ - { - "kind": "variable", - "name": "stateContext" - } - ], - "exports": [ - { - "kind": "js", - "name": "stateContext", - "declaration": { - "name": "stateContext", - "module": "src/webviews/apps/plus/timeline/context.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/timeline/stateProvider.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "TimelineStateProvider", - "members": [ + }, { "kind": "field", - "name": "disposable", + "name": "branchesVisibility", "type": { - "text": "Disposable" - }, - "privacy": "private", - "readonly": true + "text": "State['branchesVisibility']" + } }, { "kind": "field", - "name": "provider", + "name": "branch", "type": { - "text": "ContextProvider<{ __context__: State }, ReactiveElementHost>" - }, - "privacy": "private", - "readonly": true, - "default": "new ContextProvider(host, { context: stateContext, initialValue: state })" + "text": "State['branch']" + } }, { "kind": "field", - "name": "_state", + "name": "branchState", "type": { - "text": "State" - }, - "privacy": "private", - "default": "state" + "text": "State['branchState']" + } }, { "kind": "field", - "name": "state", + "name": "lastFetched", "type": { - "text": "State" - }, - "readonly": true + "text": "Date | undefined" + } }, { - "kind": "method", - "name": "dispose", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "subscription", + "type": { + "text": "State['subscription']" } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "TimelineStateProvider", - "declaration": { - "name": "TimelineStateProvider", - "module": "src/webviews/apps/plus/timeline/stateProvider.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/timeline/timeline.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "timelineBaseStyles", - "default": "css` * { box-sizing: border-box; } :not(:defined) { visibility: hidden; } [hidden] { display: none !important; } /* roll into shared focus style */ :focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } a { text-decoration: none; &:hover { text-decoration: underline; } } b { font-weight: 600; } p { margin-top: 0; } ul { margin-top: 0; padding-left: 1.2em; } section, header { display: flex; flex-direction: column; padding: 0; } h2 { font-weight: 400; } h3 { border: none; color: var(--color-view-header-foreground); font-size: 1.5rem; font-weight: 600; margin-bottom: 0; white-space: nowrap; } h4 { font-size: 1.5rem; font-weight: 400; margin: 0.5rem 0 1rem 0; } `" - }, - { - "kind": "variable", - "name": "timelineStyles", - "default": "css` :host { display: block; color: var(--color-view-foreground); font-family: var(--font-family); font-size: var(--font-size); margin: 0; padding: 0; height: 100vh; overflow: hidden; } .container { display: flex; flex-direction: column; height: 100%; } .header { flex: none; display: grid; grid-template-columns: 1fr min-content; align-items: center; grid-template-areas: 'details toolbox'; margin: 0.5rem 1rem; } :host-context(body[data-placement='editor']) .header { margin-top: 1rem; margin-right: 1.5rem; } .details { grid-area: details; display: flex; gap: 1rem; align-items: center; font-size: var(--font-size); min-width: 0; margin-right: 1rem; } .details gl-breadcrumbs { flex: 1; min-width: 0; padding: 0.1rem 0; overflow: hidden; } .details .details__ref, .details .details__timeframe { min-width: 0; margin: 0; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } .details .details__ref { flex: 0 100000000 auto; color: var(--color-foreground--75); font-size: 1.2rem; margin-left: auto; } .details .details__ref .ref { margin-left: 0.25rem; } .details .details__timeframe { flex: 0 0 auto; color: var(--color-foreground--75); margin-right: 0.6rem; user-select: none; white-space: nowrap; font-size: 1.2rem; margin-left: auto; } .toolbox { grid-area: toolbox; align-items: center; display: flex; gap: 0.3rem; } .toolbox gl-feature-badge { padding-bottom: 0.4rem; } :host-context(body[data-placement='editor']) .toolbox gl-feature-badge { padding-left: 0.4rem; } .select-container { display: flex; align-items: center; justify-content: space-between; flex: 100% 0 1; position: relative; } .select-container label { margin: 0 1rem 0 0; font-size: var(--font-size); user-select: none; } .select-container::after { font-family: codicon; content: '\\\\eab4'; font-size: 1.4rem; pointer-events: none; top: 50%; right: 8px; transform: translateY(-50%); position: absolute; color: var(--vscode-foreground); } .select { -webkit-appearance: none; -moz-appearance: none; appearance: none; border: 1px solid var(--vscode-dropdown-border); cursor: pointer; font-family: inherit; min-height: 100%; padding: 2px 26px 2px 8px; background-color: var(--vscode-dropdown-background); border-radius: 0.3rem; box-sizing: border-box; color: var(--vscode-foreground); font-family: var(--font-family); height: 26px; user-select: none; } .timeline { flex: 1; min-height: 0; } .timeline__empty { padding: 0.4rem 2rem 1.3rem 2rem; font-size: var(--font-size); } .timeline__empty p { margin-top: 0; } :host-context(body[data-placement='view']) gl-feature-gate { background-color: var(--vscode-sideBar-background); } gl-feature-gate gl-feature-badge { vertical-align: super; margin-left: 0.4rem; margin-right: 0.4rem; } label { min-width: fit-content; } label[disabled] { opacity: 0.5; } .config__content { display: flex; flex-direction: column; gap: 0.8rem; max-width: 30rem; min-width: 20rem; margin-bottom: 0.4rem; } .config__content menu-label { padding: 0; margin-bottom: -0.4rem; } .config__content section { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 0.5rem; } .breadcrumb-item-children { display: flex; } .breadcrumb-folder { cursor: pointer; } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "timelineBaseStyles", - "declaration": { - "name": "timelineBaseStyles", - "module": "src/webviews/apps/plus/timeline/timeline.css.ts" - } - }, - { - "kind": "js", - "name": "timelineStyles", - "declaration": { - "name": "timelineStyles", - "module": "src/webviews/apps/plus/timeline/timeline.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/timeline/timeline.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlTimelineApp", - "members": [ + }, { "kind": "field", - "name": "shadowRootOptions", + "name": "allowed", "type": { - "text": "ShadowRootInit" + "text": "boolean" }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "default": "false" }, { "kind": "field", - "name": "_chart", + "name": "avatars", "type": { - "text": "GlTimelineChart | undefined" - }, - "privacy": "private" + "text": "State['avatars']" + } }, { - "kind": "method", - "name": "createStateProvider", - "privacy": "protected", - "return": { - "type": { - "text": "TimelineStateProvider" - } - }, - "parameters": [ - { - "name": "state", - "type": { - "text": "State" - } - }, - { - "name": "ipc", - "type": { - "text": "HostIpc" - } - } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" + "kind": "field", + "name": "refsMetadata", + "type": { + "text": "State['refsMetadata']" } }, { - "kind": "method", - "name": "onPersistState", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "state", - "type": { - "text": "State" - } - } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" + "kind": "field", + "name": "rows", + "type": { + "text": "State['rows']" } }, { "kind": "field", - "name": "_loading", + "name": "rowsStats", "type": { - "text": "boolean" - }, - "privacy": "private", - "default": "false" + "text": "State['rowsStats']" + } }, { "kind": "field", - "name": "allowed", - "readonly": true + "name": "rowsStatsLoading", + "type": { + "text": "boolean | undefined" + } }, { "kind": "field", - "name": "base", - "readonly": true + "name": "downstreams", + "type": { + "text": "State['downstreams']" + } }, { "kind": "field", - "name": "config", - "readonly": true + "name": "paging", + "type": { + "text": "State['paging']" + } }, { "kind": "field", - "name": "head", - "readonly": true + "name": "columns", + "type": { + "text": "State['columns']" + } }, { "kind": "field", - "name": "repository", - "readonly": true + "name": "config", + "type": { + "text": "State['config']" + } }, { "kind": "field", - "name": "scope", - "readonly": true + "name": "context", + "type": { + "text": "State['context']" + } }, { "kind": "field", - "name": "isShowAllBranchesSupported", - "readonly": true + "name": "nonce", + "type": { + "text": "string | undefined" + } }, { "kind": "field", - "name": "isSliceBySupported", - "readonly": true + "name": "workingTreeStats", + "type": { + "text": "State['workingTreeStats']" + } }, { "kind": "field", - "name": "sliceBy", - "readonly": true + "name": "defaultSearchMode", + "type": { + "text": "State['defaultSearchMode']" + } }, { "kind": "field", - "name": "subscription", - "readonly": true + "name": "useNaturalLanguageSearch", + "type": { + "text": "boolean | undefined" + } }, { - "kind": "method", - "name": "renderGate", - "privacy": "private" + "kind": "field", + "name": "excludeRefs", + "type": { + "text": "State['excludeRefs']" + } }, { - "kind": "method", - "name": "renderBreadcrumbs", - "privacy": "private" + "kind": "field", + "name": "excludeTypes", + "type": { + "text": "State['excludeTypes']" + } }, { - "kind": "method", - "name": "renderRepositoryBreadcrumbItem", - "privacy": "private" + "kind": "field", + "name": "includeOnlyRefs", + "type": { + "text": "State['includeOnlyRefs']" + } }, { - "kind": "method", - "name": "renderBranchBreadcrumbItem", - "privacy": "private" + "kind": "field", + "name": "featurePreview", + "type": { + "text": "State['featurePreview']" + } }, { - "kind": "method", - "name": "renderBreadcrumbPathItems", - "privacy": "private" + "kind": "field", + "name": "orgSettings", + "type": { + "text": "State['orgSettings']" + } }, { - "kind": "method", - "name": "renderChart", - "privacy": "private" + "kind": "field", + "name": "isBusy", + "readonly": true }, { "kind": "method", - "name": "renderConfigPopover", - "privacy": "private" + "name": "createContextProvider", + "privacy": "protected", + "return": { + "type": { + "text": "ContextProvider" + } + }, + "parameters": [ + { + "name": "_state", + "type": { + "text": "State" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "renderConfigHead", - "privacy": "private" + "name": "initializeState", + "privacy": "protected", + "return": { + "type": { + "text": "Promise" + } + }, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "renderConfigBase", - "privacy": "private" + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "method", - "name": "renderConfigShowAllBranches", + "kind": "field", + "name": "fireProviderUpdate", "privacy": "private" }, { "kind": "method", - "name": "renderPeriodSelect", - "privacy": "private", + "name": "updateState", + "privacy": "protected", "parameters": [ { - "name": "period", + "name": "partial", "type": { - "text": "TimelinePeriod" + "text": "Partial" + } + }, + { + "name": "silent", + "optional": true, + "type": { + "text": "boolean" } } ] }, { - "kind": "method", - "name": "renderConfigSliceBy", - "privacy": "private" + "kind": "field", + "name": "disposable", + "type": { + "text": "Disposable" + }, + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "method", - "name": "renderTimeframe", - "privacy": "private" + "kind": "field", + "name": "provider", + "type": { + "text": "ContextProvider" + }, + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "onChooseBaseRef", - "privacy": "private" + "name": "_state", + "type": { + "text": "State" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "onChooseHeadRef", - "privacy": "private" + "name": "state", + "type": { + "text": "State" + }, + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "onChoosePath", - "privacy": "private" + "name": "webviewId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "onChangeScope", - "privacy": "private" + "name": "webviewInstanceId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "method", - "name": "onChartCommitSelected", + "kind": "field", + "name": "timestamp", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "method", + "name": "dispose", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "field", + "name": "deferBootstrap", + "type": { + "text": "boolean" + }, + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + }, + { + "kind": "method", + "name": "onPersistState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } + } + ], + "superclass": { + "name": "StateProviderBase", + "module": "/src/webviews/apps/shared/stateProviderBase" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "graphStateContext", + "declaration": { + "name": "graphStateContext", + "module": "src/webviews/apps/plus/graph/stateProvider.ts" + } + }, + { + "kind": "js", + "name": "GraphStateProvider", + "declaration": { + "name": "GraphStateProvider", + "module": "src/webviews/apps/plus/graph/stateProvider.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/patchDetails/patchDetails.ts", + "declarations": [ + { + "kind": "variable", + "name": "uncommittedSha", + "type": { + "text": "string" + }, + "default": "'0000000000000000000000000000000000000000'" + }, + { + "kind": "class", + "description": "", + "name": "PatchDetailsApp", + "members": [ + { + "kind": "method", + "name": "onInitialize", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } + }, + { + "kind": "method", + "name": "onBind", + "privacy": "protected", + "return": { + "type": { + "text": "Disposable[]" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } + }, + { + "kind": "method", + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } + }, + { + "kind": "method", + "name": "onPatchChecked", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "CustomEvent" + "text": "PatchCheckedDetail" } } ] }, { "kind": "method", - "name": "onPeriodChanged", + "name": "onCreateCheckRepo", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "Event" + "text": "CreatePatchCheckRepositoryEventDetail" } } ] }, { "kind": "method", - "name": "onSliceByChanged", + "name": "onCreateUpdateMetadata", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "Event" + "text": "CreatePatchMetadataEventDetail" } } ] }, { - "kind": "field", - "name": "_fireSelectDataPointDebounced", - "type": { - "text": "Deferrable<(e: CommitEventDetail) => void> | undefined" - }, - "privacy": "private" + "kind": "method", + "name": "onCreateGenerateTitle", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "CreatePatchMetadataEventDetail" + } + } + ] }, { "kind": "method", - "name": "fireSelectDataPoint", + "name": "onDraftUpdateMetadata", "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "CommitEventDetail" + "text": "{ visibility: DraftVisibility }" } } ] }, { - "kind": "field", - "name": "name", - "type": { - "text": "string" - }, - "attribute": "name", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - }, - { - "kind": "field", - "name": "placement", - "type": { - "text": "'editor' | 'view'" - }, - "default": "'editor'", - "attribute": "placement", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onDraftUpdatePermissions", + "privacy": "private" }, { - "kind": "field", - "name": "_ipc", - "type": { - "text": "HostIpc" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onShowPatchInGraph", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "ShowPatchInGraphDetail" + } + } + ] }, { - "kind": "field", - "name": "_logger", - "type": { - "text": "LoggerContext" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onCreatePatch", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CreatePatchEventDetail" + } + } + ] }, { - "kind": "field", - "name": "_promos", - "type": { - "text": "PromosContext" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onShareLocalPatch", + "privacy": "private" }, { - "kind": "field", - "name": "_telemetry", - "type": { - "text": "TelemetryContext" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onCopyCloudLink", + "privacy": "private" }, { - "kind": "field", - "name": "bootstrap", - "type": { - "text": "State" - }, + "kind": "method", + "name": "onModeClicked", "privacy": "private", - "attribute": "bootstrap", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] }, { "kind": "method", - "name": "onThemeUpdated", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onApplyPatch", + "privacy": "private", "parameters": [ { "name": "e", "type": { - "text": "ThemeChangeEvent" + "text": "ApplyPatchDetail" } } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - }, - { - "kind": "field", - "name": "state", - "type": { - "text": "State" - }, - "readonly": true, - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } - }, - { - "kind": "field", - "name": "disposables", - "type": { - "text": "Disposable[]" - }, - "privacy": "protected", - "readonly": true, - "default": "[]", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + ] }, { - "kind": "field", - "name": "_focused", - "type": { - "text": "boolean | undefined" - }, + "kind": "method", + "name": "onArchiveDraft", "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "reason", + "optional": true, + "type": { + "text": "DraftReasonEventDetail['reason']" + } + } + ] }, { - "kind": "field", - "name": "_inputFocused", - "type": { - "text": "boolean | undefined" - }, + "kind": "method", + "name": "onChangePatchBase", "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "e", + "type": { + "text": "ChangePatchBaseDetail" + } + } + ] }, { - "kind": "field", - "name": "_sendWebviewFocusChangedCommandDebounced", - "type": { - "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" - }, + "kind": "method", + "name": "onSelectPatchRepo", "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "e", + "type": { + "text": "SelectPatchRepoDetail" + } + } + ] }, { - "kind": "field", - "name": "_stateProvider", - "type": { - "text": "StateProvider" - }, + "kind": "method", + "name": "onCommandClickedCore", "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "action", + "optional": true, + "type": { + "text": "GlCommands | `command:${GlCommands}`" + } + } + ] }, { "kind": "method", - "name": "onWebviewFocusChanged", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onSwitchAIModel", + "privacy": "private", "parameters": [ { - "name": "focused", + "name": "_e", "type": { - "text": "boolean" + "text": "MouseEvent" } } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + ] }, { "kind": "method", - "name": "onWebviewVisibilityChanged", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, + "name": "onAIExplain", + "privacy": "private", "parameters": [ { - "name": "visible", + "name": "_e", "type": { - "text": "boolean" + "text": "MouseEvent" } } - ], - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + ] }, { - "kind": "field", - "name": "onFocusIn", + "kind": "method", + "name": "onToggleFilesLayout", "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + } + ] }, { - "kind": "field", - "name": "onFocusOut", - "privacy": "private", - "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" - } + "kind": "method", + "name": "onInviteUsers", + "privacy": "private" }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, + "name": "onUpdateUserSelection", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "e", "type": { - "text": "T" + "text": "CreatePatchUpdateSelectionEventDetail | PatchDetailsUpdateSelectionEventDetail" } - }, + } + ] + }, + { + "kind": "method", + "name": "onOpenFileOnRemote", + "privacy": "private", + "parameters": [ { - "name": "detail", + "name": "e", "type": { - "text": "CustomEventDetailType" + "text": "FileChangeListItemDetail" } - }, + } + ] + }, + { + "kind": "method", + "name": "onOpenFile", + "privacy": "private", + "parameters": [ { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "Omit>, 'detail'>" + "text": "FileChangeListItemDetail" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" + ] + }, + { + "kind": "method", + "name": "onCompareFileWithWorking", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } + } + ] + }, + { + "kind": "method", + "name": "onCompareFileWithPrevious", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } + } + ] + }, + { + "kind": "method", + "name": "onFileMoreActions", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "FileChangeListItemDetail" + } + } + ] + }, + { + "kind": "field", + "name": "_component", + "type": { + "text": "GlPatchDetailsApp | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "component", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "attachState", + "privacy": "private", + "parameters": [ + { + "name": "_force", + "optional": true, + "type": { + "text": "boolean" + } + } + ] + }, + { + "kind": "field", + "name": "debouncedAttachState", + "privacy": "private" + }, + { + "kind": "field", + "name": "_api", + "type": { + "text": "HostIpcApi" + }, + "privacy": "private", + "readonly": true, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } - } - ], - "superclass": { - "name": "GlAppHost", - "module": "/src/webviews/apps/shared/appHost" - }, - "tagName": "gl-timeline-app", - "customElement": true, - "attributes": [ + }, { - "name": "name", + "kind": "field", + "name": "_hostIpc", "type": { - "text": "string" + "text": "HostIpc" }, - "fieldName": "name", + "privacy": "private", + "readonly": true, + "default": "new HostIpc(this.appName)", "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "placement", + "kind": "field", + "name": "_logger", "type": { - "text": "'editor' | 'view'" + "text": "LoggerContext" }, - "default": "'editor'", - "fieldName": "placement", + "privacy": "private", + "readonly": true, + "default": "new LoggerContext(appName)", "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } }, { - "name": "bootstrap", + "kind": "field", + "name": "_promos", "type": { - "text": "State" + "text": "PromosContext" }, - "fieldName": "bootstrap", + "privacy": "private", + "readonly": true, + "default": "new PromosContext(this._hostIpc)", "inheritedFrom": { - "name": "GlAppHost", - "module": "src/webviews/apps/shared/appHost.ts" + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "GlTimelineApp", - "declaration": { - "name": "GlTimelineApp", - "module": "src/webviews/apps/plus/timeline/timeline.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-timeline-app", - "declaration": { - "name": "GlTimelineApp", - "module": "src/webviews/apps/plus/timeline/timeline.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/branch-icon.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlBranchIcon", - "members": [ + }, { "kind": "field", - "name": "branch", + "name": "_telemetry", "type": { - "text": "string | undefined" + "text": "TelemetryContext" }, - "attribute": "branch" + "privacy": "protected", + "readonly": true, + "default": "new TelemetryContext(this._hostIpc)", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "field", - "name": "status", + "name": "state", "type": { - "text": "GitBranchStatus | undefined" + "text": "State" }, - "attribute": "status" + "privacy": "protected", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "field", - "name": "hasChanges", + "name": "placement", "type": { - "text": "boolean" + "text": "'editor' | 'view'" }, - "default": "false", - "attribute": "hasChanges" + "privacy": "protected", + "readonly": true, + "default": "(document.body.getAttribute('data-placement') ?? 'editor')", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } + }, + { + "kind": "method", + "name": "onInitialized", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } + }, + { + "kind": "method", + "name": "onThemeUpdated", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "ThemeChangeEvent" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "field", - "name": "upstream", + "name": "_focused", "type": { - "text": "string | undefined" + "text": "boolean | undefined" }, - "attribute": "upstream" + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "field", - "name": "worktree", + "name": "_inputFocused", "type": { - "text": "boolean" + "text": "boolean | undefined" }, - "default": "false", - "attribute": "worktree" + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "field", - "name": "isDefault", + "name": "bindDisposables", "type": { - "text": "boolean" + "text": "Disposable[] | undefined" }, - "default": "false", - "attribute": "is-default" + "privacy": "private", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "method", - "name": "renderIcon", - "privacy": "private" + "name": "bind", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { "kind": "method", - "name": "renderTooltipContent", - "privacy": "private" - } - ], - "attributes": [ - { - "name": "branch", - "type": { - "text": "string | undefined" + "name": "log", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "fieldName": "branch" + "parameters": [ + { + "name": "message", + "type": { + "text": "string" + } + }, + { + "name": "optionalParams", + "type": { + "text": "any[]" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { - "name": "status", - "type": { - "text": "GitBranchStatus | undefined" + "kind": "method", + "name": "getState", + "privacy": "protected", + "return": { + "type": { + "text": "State | undefined" + } }, - "fieldName": "status" + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { - "name": "hasChanges", - "type": { - "text": "boolean" + "kind": "method", + "name": "sendCommand", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "default": "false", - "fieldName": "hasChanges" + "parameters": [ + { + "name": "command", + "type": { + "text": "TCommand" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { - "name": "upstream", - "type": { - "text": "string | undefined" + "kind": "method", + "name": "sendRequest", + "privacy": "protected", + "return": { + "type": { + "text": "Promise>" + } }, - "fieldName": "upstream" + "parameters": [ + { + "name": "requestType", + "type": { + "text": "T" + } + }, + { + "name": "params", + "type": { + "text": "IpcCallParamsType" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { - "name": "worktree", - "type": { - "text": "boolean" + "kind": "method", + "name": "setState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "default": "false", - "fieldName": "worktree" + "parameters": [ + { + "name": "state", + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } }, { - "name": "is-default", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "isDefault" + "kind": "field", + "name": "bootstrap", + "default": "undefined", + "inheritedFrom": { + "name": "App", + "module": "src/webviews/apps/shared/appBase.ts" + } } ], "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-branch-icon", - "customElement": true + "name": "App", + "module": "/src/webviews/apps/shared/appBase" + } } ], "exports": [ { "kind": "js", - "name": "GlBranchIcon", + "name": "uncommittedSha", "declaration": { - "name": "GlBranchIcon", - "module": "src/webviews/apps/shared/components/branch-icon.ts" + "name": "uncommittedSha", + "module": "src/webviews/apps/plus/patchDetails/patchDetails.ts" } }, { - "kind": "custom-element-definition", - "name": "gl-branch-icon", + "kind": "js", + "name": "PatchDetailsApp", "declaration": { - "name": "GlBranchIcon", - "module": "src/webviews/apps/shared/components/branch-icon.ts" + "name": "PatchDetailsApp", + "module": "src/webviews/apps/plus/patchDetails/patchDetails.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/branch-name.ts", + "path": "src/webviews/apps/plus/timeline/context.ts", + "declarations": [ + { + "kind": "variable", + "name": "stateContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "stateContext", + "declaration": { + "name": "stateContext", + "module": "src/webviews/apps/plus/timeline/context.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/timeline/stateProvider.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlBranchName", + "name": "TimelineStateProvider", "members": [ { - "kind": "field", - "name": "name", - "type": { - "text": "string | undefined" + "kind": "method", + "name": "createContextProvider", + "privacy": "protected", + "return": { + "type": { + "text": "ContextProvider" + } }, - "attribute": "name" + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "kind": "field", - "name": "size", - "type": { - "text": "number" + "kind": "method", + "name": "onMessageReceived", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "default": "12", - "attribute": "size" - }, - { - "kind": "field", - "name": "worktree", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "worktree" - } - ], - "attributes": [ - { - "name": "name", - "type": { - "text": "string | undefined" - }, - "fieldName": "name" - }, - { - "name": "size", - "type": { - "text": "number" - }, - "default": "12", - "fieldName": "size" - }, - { - "name": "worktree", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "worktree" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-branch-name", - "customElement": true - }, - { - "kind": "function", - "name": "renderBranchName", - "return": { - "type": { - "text": "TemplateResult" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "string | undefined" + "parameters": [ + { + "name": "msg", + "type": { + "text": "IpcMessage" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" } }, { - "name": "worktree", - "optional": true, - "type": { - "text": "boolean" - } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "GlBranchName", - "declaration": { - "name": "GlBranchName", - "module": "src/webviews/apps/shared/components/branch-name.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-branch-name", - "declaration": { - "name": "GlBranchName", - "module": "src/webviews/apps/shared/components/branch-name.ts" - } - }, - { - "kind": "js", - "name": "renderBranchName", - "declaration": { - "name": "renderBranchName", - "module": "src/webviews/apps/shared/components/branch-name.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/breadcrumbs.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlBreadcrumbs", - "members": [], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-breadcrumbs", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlBreadcrumbItem", - "members": [ - { - "kind": "field", - "name": "_collapsed", - "type": { - "text": "boolean | undefined" + "kind": "method", + "name": "onPersistState", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "privacy": "private" + "parameters": [ + { + "name": "state", + "type": { + "text": "State" + } + } + ], + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "collapsed", + "name": "disposable", "type": { - "text": "boolean" + "text": "Disposable" }, - "privacy": "private", - "attribute": "collapsed", - "reflects": true + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "collapsible", + "name": "provider", "type": { - "text": "boolean" + "text": "ContextProvider" }, - "privacy": "private", - "readonly": true + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "collapsibleState", + "name": "_state", "type": { - "text": "CollapsibleState" + "text": "State" }, - "default": "'none'", - "attribute": "collapsibleState" + "privacy": "protected", + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "icon", + "name": "state", "type": { - "text": "string | undefined" + "text": "State" }, - "attribute": "icon" + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "iconTooltip", - "type": { - "text": "string | undefined" - }, - "attribute": "iconTooltip" + "name": "webviewId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "_shrink", - "type": { - "text": "number" - }, - "privacy": "private", - "default": "1" + "name": "webviewInstanceId", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "shrink", - "type": { - "text": "number" - }, - "attribute": "shrink" + "name": "timestamp", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "method", - "name": "renderIcon", - "privacy": "private", - "parameters": [ - { - "name": "collapsible", - "type": { - "text": "boolean" - } - }, - { - "name": "collapsed", - "type": { - "text": "boolean" - } + "name": "dispose", + "return": { + "type": { + "text": "void" } - ] + }, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { "kind": "field", - "name": "onToggleCollapse", - "privacy": "private" - } - ], - "attributes": [ - { - "name": "collapsed", + "name": "deferBootstrap", "type": { "text": "boolean" }, - "fieldName": "collapsed" - }, - { - "name": "collapsibleState", - "type": { - "text": "CollapsibleState" - }, - "default": "'none'", - "fieldName": "collapsibleState" - }, - { - "name": "icon", - "type": { - "text": "string | undefined" - }, - "fieldName": "icon" - }, - { - "name": "iconTooltip", - "type": { - "text": "string | undefined" - }, - "fieldName": "iconTooltip" + "privacy": "protected", + "readonly": true, + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } }, { - "name": "shrink", - "type": { - "text": "number" + "kind": "method", + "name": "initializeState", + "privacy": "protected", + "return": { + "type": { + "text": "Promise" + } }, - "fieldName": "shrink" + "inheritedFrom": { + "name": "StateProviderBase", + "module": "src/webviews/apps/shared/stateProviderBase.ts" + } } ], "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-breadcrumb-item", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlBreadcrumbItemChild", - "members": [], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-breadcrumb-item-child", - "customElement": true + "name": "StateProviderBase", + "module": "/src/webviews/apps/shared/stateProviderBase" + } } ], "exports": [ { "kind": "js", - "name": "GlBreadcrumbs", - "declaration": { - "name": "GlBreadcrumbs", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-breadcrumbs", - "declaration": { - "name": "GlBreadcrumbs", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" - } - }, - { - "kind": "js", - "name": "GlBreadcrumbItem", - "declaration": { - "name": "GlBreadcrumbItem", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-breadcrumb-item", - "declaration": { - "name": "GlBreadcrumbItem", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" - } - }, - { - "kind": "js", - "name": "GlBreadcrumbItemChild", - "declaration": { - "name": "GlBreadcrumbItemChild", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-breadcrumb-item-child", + "name": "TimelineStateProvider", "declaration": { - "name": "GlBreadcrumbItemChild", - "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + "name": "TimelineStateProvider", + "module": "src/webviews/apps/plus/timeline/stateProvider.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/button-container.ts", + "path": "src/webviews/apps/plus/timeline/timeline.css.ts", "declarations": [ { - "kind": "class", - "description": "", - "name": "ButtonContainer", - "members": [ - { - "kind": "field", - "name": "editor", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "editor" - }, - { - "kind": "field", - "name": "layout", - "type": { - "text": "'shift' | 'editor' | 'full'" - }, - "default": "'shift'", - "attribute": "layout", - "reflects": true - }, - { - "kind": "field", - "name": "grouping", - "type": { - "text": "'gap' | 'split' | 'gap-wide'" - }, - "default": "'gap'", - "attribute": "grouping", - "reflects": true - } - ], - "attributes": [ - { - "name": "editor", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "editor" - }, - { - "name": "layout", - "type": { - "text": "'shift' | 'editor' | 'full'" - }, - "default": "'shift'", - "fieldName": "layout" - }, - { - "name": "grouping", - "type": { - "text": "'gap' | 'split' | 'gap-wide'" - }, - "default": "'gap'", - "fieldName": "grouping" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "button-container", - "customElement": true + "kind": "variable", + "name": "timelineBaseStyles", + "default": "css` * { box-sizing: border-box; } :not(:defined) { visibility: hidden; } [hidden] { display: none !important; } /* roll into shared focus style */ :focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; } a { text-decoration: none; &:hover { text-decoration: underline; } } b { font-weight: 600; } p { margin-top: 0; } ul { margin-top: 0; padding-left: 1.2em; } section, header { display: flex; flex-direction: column; padding: 0; } h2 { font-weight: 400; } h3 { border: none; color: var(--color-view-header-foreground); font-size: 1.5rem; font-weight: 600; margin-bottom: 0; white-space: nowrap; } h4 { font-size: 1.5rem; font-weight: 400; margin: 0.5rem 0 1rem 0; } `" + }, + { + "kind": "variable", + "name": "timelineStyles", + "default": "css` :host { display: block; color: var(--color-view-foreground); font-family: var(--font-family); font-size: var(--font-size); margin: 0; padding: 0; height: 100vh; overflow: hidden; } .container { display: flex; flex-direction: column; height: 100%; } .header { flex: none; display: grid; grid-template-columns: 1fr min-content; align-items: center; grid-template-areas: 'details toolbox'; margin: 0.5rem 1rem; } :host-context(body[data-placement='editor']) .header { margin-top: 1rem; margin-right: 1.5rem; } .details { grid-area: details; display: flex; gap: 1rem; align-items: center; font-size: var(--font-size); min-width: 0; margin-right: 1rem; } .details gl-breadcrumbs { flex: 1; min-width: 0; padding: 0.1rem 0; overflow: hidden; } .details .details__ref, .details .details__timeframe { min-width: 0; margin: 0; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } .details .details__ref { flex: 0 100000000 auto; color: var(--color-foreground--75); font-size: 1.2rem; margin-left: auto; } .details .details__ref .ref { margin-left: 0.25rem; } .details .details__timeframe { flex: 0 0 auto; color: var(--color-foreground--75); margin-right: 0.6rem; user-select: none; white-space: nowrap; font-size: 1.2rem; margin-left: auto; } .toolbox { grid-area: toolbox; align-items: center; display: flex; gap: 0.3rem; } .toolbox gl-feature-badge { padding-bottom: 0.4rem; } :host-context(body[data-placement='editor']) .toolbox gl-feature-badge { padding-left: 0.4rem; } .select-container { display: flex; align-items: center; justify-content: space-between; flex: 100% 0 1; position: relative; } .select-container label { margin: 0 1rem 0 0; font-size: var(--font-size); user-select: none; } .select-container::after { font-family: codicon; content: '\\\\eab4'; font-size: 1.4rem; pointer-events: none; top: 50%; right: 8px; transform: translateY(-50%); position: absolute; color: var(--vscode-foreground); } .select { -webkit-appearance: none; -moz-appearance: none; appearance: none; border: 1px solid var(--vscode-dropdown-border); cursor: pointer; font-family: inherit; min-height: 100%; padding: 2px 26px 2px 8px; background-color: var(--vscode-dropdown-background); border-radius: 0.3rem; box-sizing: border-box; color: var(--vscode-foreground); font-family: var(--font-family); height: 26px; user-select: none; } .timeline { flex: 1; min-height: 0; } .timeline__empty { padding: 0.4rem 2rem 1.3rem 2rem; font-size: var(--font-size); } .timeline__empty p { margin-top: 0; } :host-context(body[data-placement='view']) gl-feature-gate { background-color: var(--vscode-sideBar-background); } gl-feature-gate gl-feature-badge { vertical-align: super; margin-left: 0.4rem; margin-right: 0.4rem; } label { min-width: fit-content; } label[disabled] { opacity: 0.5; } .config__content { display: flex; flex-direction: column; gap: 0.8rem; max-width: 30rem; min-width: 20rem; margin-bottom: 0.4rem; } .config__content menu-label { padding: 0; margin-bottom: -0.4rem; } .config__content section { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 0.5rem; } .breadcrumb-item-children { display: flex; } .breadcrumb-folder { cursor: pointer; } `" } ], "exports": [ { "kind": "js", - "name": "ButtonContainer", + "name": "timelineBaseStyles", "declaration": { - "name": "ButtonContainer", - "module": "src/webviews/apps/shared/components/button-container.ts" + "name": "timelineBaseStyles", + "module": "src/webviews/apps/plus/timeline/timeline.css.ts" } }, { - "kind": "custom-element-definition", - "name": "button-container", + "kind": "js", + "name": "timelineStyles", "declaration": { - "name": "ButtonContainer", - "module": "src/webviews/apps/shared/components/button-container.ts" + "name": "timelineStyles", + "module": "src/webviews/apps/plus/timeline/timeline.css.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/button.ts", + "path": "src/webviews/apps/plus/timeline/timeline.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlButton", + "name": "GlTimelineApp", "members": [ { "kind": "field", @@ -11544,416 +12220,584 @@ "text": "ShadowRootInit" }, "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "control", + "name": "_chart", "type": { - "text": "HTMLElement" + "text": "GlTimelineChart | undefined" }, - "privacy": "protected" + "privacy": "private" }, { - "kind": "field", - "name": "appearance", - "type": { - "text": "'alert' | 'secondary' | 'toolbar' | 'input' | undefined" + "kind": "method", + "name": "createStateProvider", + "privacy": "protected", + "return": { + "type": { + "text": "TimelineStateProvider" + } }, - "attribute": "appearance", - "reflects": true + "parameters": [ + { + "name": "bootstrap", + "type": { + "text": "string" + } + }, + { + "name": "ipc", + "type": { + "text": "HostIpc" + } + }, + { + "name": "logger", + "type": { + "text": "LoggerContext" + } + } + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "disabled", + "name": "_loading", "type": { "text": "boolean" }, - "default": "false", - "attribute": "disabled", - "reflects": true + "privacy": "private", + "default": "false" }, { "kind": "field", - "name": "density", - "type": { - "text": "'compact' | 'tight' | undefined" - }, - "attribute": "density", - "reflects": true + "name": "allowed", + "readonly": true }, { "kind": "field", - "name": "full", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "full", - "reflects": true + "name": "base", + "readonly": true }, { "kind": "field", - "name": "href", - "type": { - "text": "string | undefined" - }, - "attribute": "href" + "name": "config", + "readonly": true }, { "kind": "field", - "name": "tooltip", - "type": { - "text": "string | undefined" - }, - "attribute": "tooltip" - }, + "name": "head", + "readonly": true + }, { "kind": "field", - "name": "tooltipPlacement", - "type": { - "text": "GlTooltip['placement'] | undefined" - }, - "default": "'bottom'", - "attribute": "tooltipPlacement" + "name": "repository", + "readonly": true + }, + { + "kind": "field", + "name": "scope", + "readonly": true + }, + { + "kind": "field", + "name": "isShowAllBranchesSupported", + "readonly": true + }, + { + "kind": "field", + "name": "isSliceBySupported", + "readonly": true + }, + { + "kind": "field", + "name": "sliceBy", + "readonly": true + }, + { + "kind": "field", + "name": "subscription", + "readonly": true }, { "kind": "method", - "name": "renderControl", + "name": "renderGate", "privacy": "private" }, { "kind": "method", - "name": "onLinkKeypress", + "name": "renderBreadcrumbs", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderRepositoryBreadcrumbItem", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderBranchBreadcrumbItem", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderBreadcrumbPathItems", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderChart", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderConfigPopover", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderConfigHead", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderConfigBase", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderConfigShowAllBranches", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPeriodSelect", "privacy": "private", "parameters": [ { - "name": "e", + "name": "period", "type": { - "text": "KeyboardEvent" + "text": "TimelinePeriod" } } ] }, { "kind": "method", - "name": "focus", - "return": { - "type": { - "text": "void" - } - }, + "name": "renderConfigSliceBy", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderTimeframe", + "privacy": "private" + }, + { + "kind": "field", + "name": "onChooseBaseRef", + "privacy": "private" + }, + { + "kind": "field", + "name": "onChooseHeadRef", + "privacy": "private" + }, + { + "kind": "field", + "name": "onChoosePath", + "privacy": "private" + }, + { + "kind": "field", + "name": "onChangeScope", + "privacy": "private" + }, + { + "kind": "method", + "name": "onChartCommitSelected", + "privacy": "private", "parameters": [ { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "FocusOptions" + "text": "CustomEvent" } } ] }, { "kind": "method", - "name": "blur", - "return": { - "type": { - "text": "void" + "name": "onPeriodChanged", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } } - } + ] }, { "kind": "method", - "name": "click", - "return": { - "type": { - "text": "void" + "name": "onSliceByChanged", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } } - } - } - ], - "attributes": [ + ] + }, { - "name": "appearance", + "kind": "field", + "name": "_fireSelectDataPointDebounced", "type": { - "text": "'alert' | 'secondary' | 'toolbar' | 'input' | undefined" + "text": "Deferrable<(e: CommitEventDetail) => void> | undefined" }, - "fieldName": "appearance" + "privacy": "private" }, { - "name": "disabled", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "disabled" + "kind": "method", + "name": "fireSelectDataPoint", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CommitEventDetail" + } + } + ] }, { - "name": "density", + "kind": "field", + "name": "name", "type": { - "text": "'compact' | 'tight' | undefined" + "text": "string" }, - "fieldName": "density" + "attribute": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "full", + "kind": "field", + "name": "placement", "type": { - "text": "boolean" + "text": "'editor' | 'view'" }, - "default": "false", - "fieldName": "full" + "default": "'editor'", + "attribute": "placement", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "href", + "kind": "field", + "name": "_ipc", "type": { - "text": "string | undefined" + "text": "HostIpc" }, - "fieldName": "href" + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "tooltip", + "kind": "field", + "name": "_logger", "type": { - "text": "string | undefined" + "text": "LoggerContext" }, - "fieldName": "tooltip" + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "tooltipPlacement", + "kind": "field", + "name": "_promos", "type": { - "text": "GlTooltip['placement'] | undefined" + "text": "PromosContext" }, - "default": "'bottom'", - "fieldName": "tooltipPlacement" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-button", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlButton", - "declaration": { - "name": "GlButton", - "module": "src/webviews/apps/shared/components/button.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-button", - "declaration": { - "name": "GlButton", - "module": "src/webviews/apps/shared/components/button.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/code-icon.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "CodeIcon", - "members": [ + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, { "kind": "field", - "name": "icon", + "name": "_telemetry", "type": { - "text": "string" + "text": "TelemetryContext" }, - "default": "''", - "attribute": "icon", - "reflects": true + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "modifier", + "name": "bootstrap", "type": { "text": "string" }, - "default": "''", - "attribute": "modifier", - "reflects": true + "privacy": "private", + "attribute": "bootstrap", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "kind": "field", - "name": "size", - "type": { - "text": "number | undefined" + "kind": "method", + "name": "onThemeUpdated", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "default": "undefined", - "attribute": "size" + "parameters": [ + { + "name": "e", + "type": { + "text": "ThemeChangeEvent" + } + } + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "flip", + "name": "state", "type": { - "text": "'inline' | 'block' | undefined" + "text": "State" }, - "attribute": "flip", - "reflects": true + "readonly": true, + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "rotate", + "name": "disposables", "type": { - "text": "'45' | undefined" + "text": "Disposable[]" }, - "attribute": "rotate", - "reflects": true - } - ], - "attributes": [ + "privacy": "protected", + "readonly": true, + "default": "[]", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, { - "name": "icon", + "kind": "field", + "name": "_focused", "type": { - "text": "string" + "text": "boolean | undefined" }, - "default": "''", - "fieldName": "icon" + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "modifier", + "kind": "field", + "name": "_inputFocused", "type": { - "text": "string" + "text": "boolean | undefined" }, - "default": "''", - "fieldName": "modifier" + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "size", + "kind": "field", + "name": "_sendWebviewFocusChangedCommandDebounced", "type": { - "text": "number | undefined" + "text": "Deferrable<(params: WebviewFocusChangedParams) => void>" }, - "default": "undefined", - "fieldName": "size" + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "flip", + "kind": "field", + "name": "_stateProvider", "type": { - "text": "'inline' | 'block' | undefined" + "text": "Provider" }, - "fieldName": "flip" + "privacy": "protected", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "rotate", - "type": { - "text": "'45' | undefined" + "kind": "method", + "name": "onWebviewFocusChanged", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "fieldName": "rotate" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "code-icon", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "CodeIcon", - "declaration": { - "name": "CodeIcon", - "module": "src/webviews/apps/shared/components/code-icon.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "code-icon", - "declaration": { - "name": "CodeIcon", - "module": "src/webviews/apps/shared/components/code-icon.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/commit-sha.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlCommitSha", - "members": [ + "parameters": [ + { + "name": "focused", + "type": { + "text": "boolean" + } + } + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, { - "kind": "field", - "name": "sha", - "type": { - "text": "string | undefined" + "kind": "method", + "name": "onWebviewVisibilityChanged", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "attribute": "sha" + "parameters": [ + { + "name": "visible", + "type": { + "text": "boolean" + } + } + ], + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "size", - "type": { - "text": "number" - }, - "default": "12", - "attribute": "size" + "name": "onFocusIn", + "privacy": "private", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { "kind": "field", - "name": "label", + "name": "onFocusOut", "privacy": "private", - "readonly": true - } - ], - "attributes": [ - { - "name": "sha", - "type": { - "text": "string | undefined" - }, - "fieldName": "sha" + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } }, { - "name": "size", - "type": { - "text": "number" + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } }, - "default": "12", - "fieldName": "size" + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } } ], "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-commit-sha", - "customElement": true - }, - { - "kind": "function", - "name": "renderCommitSha", - "return": { - "type": { - "text": "TemplateResult" - } + "name": "GlAppHost", + "module": "/src/webviews/apps/shared/appHost" }, - "parameters": [ + "tagName": "gl-timeline-app", + "customElement": true, + "attributes": [ { - "name": "sha", + "name": "name", "type": { - "text": "string | undefined" + "text": "string" + }, + "fieldName": "name", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } }, { - "name": "size", - "default": "12", + "name": "placement", "type": { - "text": "number" + "text": "'editor' | 'view'" + }, + "default": "'editor'", + "fieldName": "placement", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" + } + }, + { + "name": "bootstrap", + "type": { + "text": "string" + }, + "fieldName": "bootstrap", + "inheritedFrom": { + "name": "GlAppHost", + "module": "src/webviews/apps/shared/appHost.ts" } } ] @@ -11962,1401 +12806,1641 @@ "exports": [ { "kind": "js", - "name": "GlCommitSha", + "name": "GlTimelineApp", "declaration": { - "name": "GlCommitSha", - "module": "src/webviews/apps/shared/components/commit-sha.ts" + "name": "GlTimelineApp", + "module": "src/webviews/apps/plus/timeline/timeline.ts" } }, { "kind": "custom-element-definition", - "name": "gl-commit-sha", - "declaration": { - "name": "GlCommitSha", - "module": "src/webviews/apps/shared/components/commit-sha.ts" - } - }, - { - "kind": "js", - "name": "renderCommitSha", + "name": "gl-timeline-app", "declaration": { - "name": "renderCommitSha", - "module": "src/webviews/apps/shared/components/commit-sha.ts" + "name": "GlTimelineApp", + "module": "src/webviews/apps/plus/timeline/timeline.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/copy-container.ts", + "path": "src/webviews/apps/shared/components/branch-icon.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlCopyContainer", + "name": "GlBranchIcon", "members": [ { "kind": "field", - "name": "tagName", - "static": true, - "readonly": true, - "default": "'gl-copy-container'", - "type": { - "text": "string" - } - }, - { - "kind": "field", - "name": "content", + "name": "branch", "type": { "text": "string | undefined" }, - "attribute": "content" - }, - { - "kind": "field", - "name": "copyLabel", - "type": { - "text": "string" - }, - "default": "'Copy'", - "attribute": "copyLabel" + "attribute": "branch" }, { "kind": "field", - "name": "copiedLabel", + "name": "status", "type": { - "text": "string" + "text": "GitBranchStatus | undefined" }, - "default": "'Copied'", - "attribute": "copiedLabel" + "attribute": "status" }, { "kind": "field", - "name": "placement", + "name": "hasChanges", "type": { - "text": "GlTooltip['placement'] | undefined" + "text": "boolean" }, - "default": "'top'", - "attribute": "placement" + "default": "false", + "attribute": "hasChanges" }, { "kind": "field", - "name": "timeout", + "name": "upstream", "type": { - "text": "number" + "text": "string | undefined" }, - "default": "1000", - "attribute": "timeout" + "attribute": "upstream" }, { "kind": "field", - "name": "_resetTimer", + "name": "worktree", "type": { - "text": "ReturnType | undefined" + "text": "boolean" }, - "privacy": "private" + "default": "false", + "attribute": "worktree" }, { "kind": "field", - "name": "label", + "name": "isDefault", "type": { - "text": "string" + "text": "boolean" }, - "privacy": "private" - }, - { - "kind": "method", - "name": "onClick", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "MouseEvent" - } - } - ] + "default": "false", + "attribute": "is-default" }, { "kind": "method", - "name": "cancelResetTimer", + "name": "renderIcon", "privacy": "private" }, { "kind": "method", - "name": "createResetTimer", + "name": "renderTooltipContent", "privacy": "private" } ], "attributes": [ { - "name": "content", + "name": "branch", "type": { "text": "string | undefined" }, - "fieldName": "content" + "fieldName": "branch" }, { - "name": "copyLabel", + "name": "status", "type": { - "text": "string" + "text": "GitBranchStatus | undefined" }, - "default": "'Copy'", - "fieldName": "copyLabel" + "fieldName": "status" }, { - "name": "copiedLabel", + "name": "hasChanges", "type": { - "text": "string" + "text": "boolean" }, - "default": "'Copied'", - "fieldName": "copiedLabel" + "default": "false", + "fieldName": "hasChanges" }, { - "name": "placement", + "name": "upstream", "type": { - "text": "GlTooltip['placement'] | undefined" + "text": "string | undefined" }, - "default": "'top'", - "fieldName": "placement" + "fieldName": "upstream" }, { - "name": "timeout", + "name": "worktree", "type": { - "text": "number" + "text": "boolean" }, - "default": "1000", - "fieldName": "timeout" + "default": "false", + "fieldName": "worktree" + }, + { + "name": "is-default", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "isDefault" } ], "superclass": { "name": "LitElement", "package": "lit" }, + "tagName": "gl-branch-icon", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlCopyContainer", + "name": "GlBranchIcon", "declaration": { - "name": "GlCopyContainer", - "module": "src/webviews/apps/shared/components/copy-container.ts" + "name": "GlBranchIcon", + "module": "src/webviews/apps/shared/components/branch-icon.ts" } }, { "kind": "custom-element-definition", + "name": "gl-branch-icon", "declaration": { - "name": "GlCopyContainer", - "module": "src/webviews/apps/shared/components/copy-container.ts" + "name": "GlBranchIcon", + "module": "src/webviews/apps/shared/components/branch-icon.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/element.ts", + "path": "src/webviews/apps/shared/components/branch-name.ts", "declarations": [ { - "kind": "function", - "name": "observe", - "parameters": [ + "kind": "class", + "description": "", + "name": "GlBranchName", + "members": [ { - "name": "keys", + "kind": "field", + "name": "name", "type": { - "text": "keyof T | (keyof T)[]" - } + "text": "string | undefined" + }, + "attribute": "name" }, { - "name": "options", - "optional": true, + "kind": "field", + "name": "size", "type": { - "text": "{ afterFirstUpdate?: boolean }" - } + "text": "number" + }, + "default": "12", + "attribute": "size" + }, + { + "kind": "field", + "name": "worktree", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "worktree" } - ] - }, - { - "kind": "class", - "description": "", - "name": "GlElement", - "members": [ + ], + "attributes": [ { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "name": "name", + "type": { + "text": "string | undefined" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ] + "fieldName": "name" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "name": "size", + "type": { + "text": "number" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "optional": true, - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ] + "default": "12", + "fieldName": "size" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "name": "worktree", + "type": { + "text": "boolean" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ] + "default": "false", + "fieldName": "worktree" } ], "superclass": { "name": "LitElement", "package": "lit" }, + "tagName": "gl-branch-name", "customElement": true + }, + { + "kind": "function", + "name": "renderBranchName", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string | undefined" + } + }, + { + "name": "worktree", + "optional": true, + "type": { + "text": "boolean" + } + } + ] } ], "exports": [ { "kind": "js", - "name": "observe", + "name": "GlBranchName", "declaration": { - "name": "observe", - "module": "src/webviews/apps/shared/components/element.ts" + "name": "GlBranchName", + "module": "src/webviews/apps/shared/components/branch-name.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-branch-name", + "declaration": { + "name": "GlBranchName", + "module": "src/webviews/apps/shared/components/branch-name.ts" } }, { "kind": "js", - "name": "GlElement", + "name": "renderBranchName", "declaration": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" + "name": "renderBranchName", + "module": "src/webviews/apps/shared/components/branch-name.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/feature-badge.ts", + "path": "src/webviews/apps/shared/components/breadcrumbs.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlFeatureBadge", + "name": "GlBreadcrumbs", + "members": [], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-breadcrumbs", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlBreadcrumbItem", "members": [ { "kind": "field", - "name": "cloud", + "name": "_collapsed", "type": { - "text": "boolean" + "text": "boolean | undefined" }, - "default": "false", - "attribute": "cloud" + "privacy": "private" }, { "kind": "field", - "name": "placement", + "name": "collapsed", "type": { - "text": "GlPopover['placement']" + "text": "boolean" }, - "default": "'bottom'", - "attribute": "placement", + "privacy": "private", + "attribute": "collapsed", "reflects": true }, { "kind": "field", - "name": "preview", + "name": "collapsible", "type": { "text": "boolean" }, - "default": "false", - "attribute": "preview" + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "promos", + "name": "collapsibleState", "type": { - "text": "PromosContext" + "text": "CollapsibleState" }, - "privacy": "private" + "default": "'none'", + "attribute": "collapsibleState" }, { "kind": "field", - "name": "source", + "name": "icon", "type": { - "text": "Source | undefined" + "text": "string | undefined" }, - "attribute": "source" + "attribute": "icon" }, { "kind": "field", - "name": "subscription", + "name": "iconTooltip", "type": { - "text": "Subscription | undefined" - } + "text": "string | undefined" + }, + "attribute": "iconTooltip" }, { "kind": "field", - "name": "daysRemaining", + "name": "_shrink", + "type": { + "text": "number" + }, "privacy": "private", - "readonly": true + "default": "1" }, { "kind": "field", - "name": "state", - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "renderBadge", - "privacy": "private" + "name": "shrink", + "type": { + "text": "number" + }, + "attribute": "shrink" }, { "kind": "method", - "name": "renderPopoverHeader", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderPopoverContent", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderStartTrialActions", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderUpgradeActions", + "name": "renderIcon", "privacy": "private", "parameters": [ { - "name": "leadin", - "optional": true, + "name": "collapsible", "type": { - "text": "TemplateResult" + "text": "boolean" + } + }, + { + "name": "collapsed", + "type": { + "text": "boolean" } } ] }, { - "kind": "method", - "name": "renderPromo", + "kind": "field", + "name": "onToggleCollapse", "privacy": "private" } ], "attributes": [ { - "name": "cloud", + "name": "collapsed", + "type": { + "text": "boolean" + }, + "fieldName": "collapsed" + }, + { + "name": "collapsibleState", + "type": { + "text": "CollapsibleState" + }, + "default": "'none'", + "fieldName": "collapsibleState" + }, + { + "name": "icon", + "type": { + "text": "string | undefined" + }, + "fieldName": "icon" + }, + { + "name": "iconTooltip", + "type": { + "text": "string | undefined" + }, + "fieldName": "iconTooltip" + }, + { + "name": "shrink", + "type": { + "text": "number" + }, + "fieldName": "shrink" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-breadcrumb-item", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlBreadcrumbItemChild", + "members": [], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-breadcrumb-item-child", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlBreadcrumbs", + "declaration": { + "name": "GlBreadcrumbs", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-breadcrumbs", + "declaration": { + "name": "GlBreadcrumbs", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + }, + { + "kind": "js", + "name": "GlBreadcrumbItem", + "declaration": { + "name": "GlBreadcrumbItem", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-breadcrumb-item", + "declaration": { + "name": "GlBreadcrumbItem", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + }, + { + "kind": "js", + "name": "GlBreadcrumbItemChild", + "declaration": { + "name": "GlBreadcrumbItemChild", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-breadcrumb-item-child", + "declaration": { + "name": "GlBreadcrumbItemChild", + "module": "src/webviews/apps/shared/components/breadcrumbs.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/button-container.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "ButtonContainer", + "members": [ + { + "kind": "field", + "name": "editor", "type": { "text": "boolean" }, "default": "false", - "fieldName": "cloud" + "attribute": "editor" }, { - "name": "placement", + "kind": "field", + "name": "layout", "type": { - "text": "GlPopover['placement']" + "text": "'shift' | 'editor' | 'full'" }, - "default": "'bottom'", - "fieldName": "placement" + "default": "'shift'", + "attribute": "layout", + "reflects": true }, { - "name": "preview", + "kind": "field", + "name": "grouping", + "type": { + "text": "'gap' | 'split' | 'gap-wide'" + }, + "default": "'gap'", + "attribute": "grouping", + "reflects": true + } + ], + "attributes": [ + { + "name": "editor", "type": { "text": "boolean" }, "default": "false", - "fieldName": "preview" + "fieldName": "editor" }, { - "name": "source", + "name": "layout", "type": { - "text": "Source | undefined" + "text": "'shift' | 'editor' | 'full'" }, - "fieldName": "source" + "default": "'shift'", + "fieldName": "layout" + }, + { + "name": "grouping", + "type": { + "text": "'gap' | 'split' | 'gap-wide'" + }, + "default": "'gap'", + "fieldName": "grouping" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-feature-badge", + "tagName": "button-container", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlFeatureBadge", + "name": "ButtonContainer", "declaration": { - "name": "GlFeatureBadge", - "module": "src/webviews/apps/shared/components/feature-badge.ts" + "name": "ButtonContainer", + "module": "src/webviews/apps/shared/components/button-container.ts" } }, { "kind": "custom-element-definition", - "name": "gl-feature-badge", + "name": "button-container", "declaration": { - "name": "GlFeatureBadge", - "module": "src/webviews/apps/shared/components/feature-badge.ts" + "name": "ButtonContainer", + "module": "src/webviews/apps/shared/components/button-container.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/feature-gate.ts", + "path": "src/webviews/apps/shared/components/button.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlFeatureGate", + "name": "GlButton", "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "control", + "type": { + "text": "HTMLElement" + }, + "privacy": "protected" + }, { "kind": "field", "name": "appearance", "type": { - "text": "'alert' | 'welcome' | undefined" + "text": "'alert' | 'secondary' | 'toolbar' | 'input' | undefined" }, "attribute": "appearance", "reflects": true }, { "kind": "field", - "name": "featurePreview", + "name": "disabled", "type": { - "text": "FeaturePreview | undefined" + "text": "boolean" }, - "attribute": "featurePreview" + "default": "false", + "attribute": "disabled", + "reflects": true }, { "kind": "field", - "name": "featurePreviewCommandLink", + "name": "density", "type": { - "text": "string | undefined" + "text": "'compact' | 'tight' | undefined" }, - "attribute": "featurePreviewCommandLink" + "attribute": "density", + "reflects": true }, { "kind": "field", - "name": "featureWithArticleIfNeeded", + "name": "full", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "full", + "reflects": true + }, + { + "kind": "field", + "name": "href", "type": { "text": "string | undefined" }, - "attribute": "featureWithArticleIfNeeded" + "attribute": "href" }, { "kind": "field", - "name": "source", + "name": "tooltip", "type": { - "text": "Source | undefined" + "text": "string | undefined" }, - "attribute": "source" + "attribute": "tooltip" }, { "kind": "field", - "name": "state", + "name": "tooltipPlacement", "type": { - "text": "SubscriptionState | undefined" - } + "text": "GlTooltip['placement'] | undefined" + }, + "default": "'bottom'", + "attribute": "tooltipPlacement" }, { "kind": "field", - "name": "webroot", + "name": "truncate", "type": { - "text": "string | undefined" + "text": "boolean" }, - "attribute": "webroot" + "default": "false", + "attribute": "truncate", + "reflects": true + }, + { + "kind": "method", + "name": "renderControl", + "privacy": "private" + }, + { + "kind": "method", + "name": "onLinkKeypress", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "KeyboardEvent" + } + } + ] + }, + { + "kind": "method", + "name": "focus", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "options", + "optional": true, + "type": { + "text": "FocusOptions" + } + } + ] + }, + { + "kind": "method", + "name": "blur", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "method", + "name": "click", + "return": { + "type": { + "text": "void" + } + } } ], "attributes": [ { "name": "appearance", "type": { - "text": "'alert' | 'welcome' | undefined" + "text": "'alert' | 'secondary' | 'toolbar' | 'input' | undefined" }, "fieldName": "appearance" }, { - "name": "featurePreview", + "name": "disabled", "type": { - "text": "FeaturePreview | undefined" + "text": "boolean" }, - "fieldName": "featurePreview" + "default": "false", + "fieldName": "disabled" }, { - "name": "featurePreviewCommandLink", + "name": "density", + "type": { + "text": "'compact' | 'tight' | undefined" + }, + "fieldName": "density" + }, + { + "name": "full", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "full" + }, + { + "name": "href", "type": { "text": "string | undefined" }, - "fieldName": "featurePreviewCommandLink" + "fieldName": "href" }, { - "name": "featureWithArticleIfNeeded", + "name": "tooltip", "type": { "text": "string | undefined" }, - "fieldName": "featureWithArticleIfNeeded" + "fieldName": "tooltip" }, { - "name": "source", + "name": "tooltipPlacement", "type": { - "text": "Source | undefined" + "text": "GlTooltip['placement'] | undefined" }, - "fieldName": "source" + "default": "'bottom'", + "fieldName": "tooltipPlacement" }, { - "name": "webroot", + "name": "truncate", "type": { - "text": "string | undefined" + "text": "boolean" }, - "fieldName": "webroot" + "default": "false", + "fieldName": "truncate" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-feature-gate", + "tagName": "gl-button", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlFeatureGate", + "name": "GlButton", "declaration": { - "name": "GlFeatureGate", - "module": "src/webviews/apps/shared/components/feature-gate.ts" + "name": "GlButton", + "module": "src/webviews/apps/shared/components/button.ts" } }, { "kind": "custom-element-definition", - "name": "gl-feature-gate", + "name": "gl-button", "declaration": { - "name": "GlFeatureGate", - "module": "src/webviews/apps/shared/components/feature-gate.ts" + "name": "GlButton", + "module": "src/webviews/apps/shared/components/button.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/formatted-date.ts", + "path": "src/webviews/apps/shared/components/code-icon.ts", "declarations": [ { "kind": "class", "description": "", - "name": "FormattedDate", + "name": "CodeIcon", "members": [ { "kind": "field", - "name": "format", + "name": "icon", "type": { - "text": "string | undefined" + "text": "string" }, - "attribute": "format" + "default": "''", + "attribute": "icon", + "reflects": true }, { "kind": "field", - "name": "dateStyle", + "name": "modifier", "type": { - "text": "'relative' | 'absolute'" + "text": "string" }, - "default": "'relative'", - "attribute": "date-style" - }, - { - "kind": "field", - "name": "date", - "default": "new Date()", - "attribute": "date", + "default": "''", + "attribute": "modifier", "reflects": true }, { "kind": "field", - "name": "tooltip", + "name": "size", "type": { - "text": "string" + "text": "number | undefined" }, - "default": "''", - "attribute": "tooltip" + "default": "undefined", + "attribute": "size" }, { "kind": "field", - "name": "absoluteDate", + "name": "flip", "type": { - "text": "string" + "text": "'inline' | 'block' | undefined" }, - "readonly": true + "attribute": "flip", + "reflects": true }, { "kind": "field", - "name": "dateLabel", + "name": "rotate", "type": { - "text": "string" + "text": "'45' | undefined" }, - "readonly": true + "attribute": "rotate", + "reflects": true } ], "attributes": [ { - "name": "format", + "name": "icon", "type": { - "text": "string | undefined" + "text": "string" }, - "fieldName": "format" + "default": "''", + "fieldName": "icon" }, { - "name": "date-style", + "name": "modifier", "type": { - "text": "'relative' | 'absolute'" + "text": "string" }, - "default": "'relative'", - "fieldName": "dateStyle" + "default": "''", + "fieldName": "modifier" }, { - "name": "date", - "default": "new Date()", - "fieldName": "date" + "name": "size", + "type": { + "text": "number | undefined" + }, + "default": "undefined", + "fieldName": "size" }, { - "name": "tooltip", + "name": "flip", "type": { - "text": "string" + "text": "'inline' | 'block' | undefined" }, - "default": "''", - "fieldName": "tooltip" + "fieldName": "flip" + }, + { + "name": "rotate", + "type": { + "text": "'45' | undefined" + }, + "fieldName": "rotate" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "formatted-date", + "tagName": "code-icon", "customElement": true } ], "exports": [ { "kind": "js", - "name": "FormattedDate", + "name": "CodeIcon", "declaration": { - "name": "FormattedDate", - "module": "src/webviews/apps/shared/components/formatted-date.ts" + "name": "CodeIcon", + "module": "src/webviews/apps/shared/components/code-icon.ts" } }, { "kind": "custom-element-definition", - "name": "formatted-date", + "name": "code-icon", "declaration": { - "name": "FormattedDate", - "module": "src/webviews/apps/shared/components/formatted-date.ts" + "name": "CodeIcon", + "module": "src/webviews/apps/shared/components/code-icon.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/gitlens-logo.ts", + "path": "src/webviews/apps/shared/components/commit-sha.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GitLensLogo", - "members": [], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gitlens-logo", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GitLensLogo", - "declaration": { - "name": "GitLensLogo", - "module": "src/webviews/apps/shared/components/gitlens-logo.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gitlens-logo", - "declaration": { - "name": "GitLensLogo", - "module": "src/webviews/apps/shared/components/gitlens-logo.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/progress.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "ProgressIndicator", + "name": "GlCommitSha", "members": [ { "kind": "field", - "name": "mode", + "name": "sha", "type": { - "text": "string" + "text": "string | undefined" }, - "default": "'infinite'", - "attribute": "mode", - "reflects": true + "attribute": "sha" }, { "kind": "field", - "name": "active", + "name": "size", "type": { - "text": "boolean" + "text": "number" }, - "default": "false", - "attribute": "active" + "default": "12", + "attribute": "size" }, { "kind": "field", - "name": "position", - "type": { - "text": "'top' | 'bottom'" - }, - "default": "'bottom'", - "attribute": "position" + "name": "label", + "privacy": "private", + "readonly": true } ], "attributes": [ { - "name": "mode", - "type": { - "text": "string" - }, - "default": "'infinite'", - "fieldName": "mode" - }, - { - "name": "active", + "name": "sha", "type": { - "text": "boolean" + "text": "string | undefined" }, - "default": "false", - "fieldName": "active" + "fieldName": "sha" }, { - "name": "position", + "name": "size", "type": { - "text": "'top' | 'bottom'" + "text": "number" }, - "default": "'bottom'", - "fieldName": "position" + "default": "12", + "fieldName": "size" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "progress-indicator", + "tagName": "gl-commit-sha", "customElement": true + }, + { + "kind": "function", + "name": "renderCommitSha", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "parameters": [ + { + "name": "sha", + "type": { + "text": "string | undefined" + } + }, + { + "name": "size", + "default": "12", + "type": { + "text": "number" + } + } + ] } ], "exports": [ { "kind": "js", - "name": "ProgressIndicator", + "name": "GlCommitSha", "declaration": { - "name": "ProgressIndicator", - "module": "src/webviews/apps/shared/components/progress.ts" + "name": "GlCommitSha", + "module": "src/webviews/apps/shared/components/commit-sha.ts" } }, { "kind": "custom-element-definition", - "name": "progress-indicator", + "name": "gl-commit-sha", "declaration": { - "name": "ProgressIndicator", - "module": "src/webviews/apps/shared/components/progress.ts" + "name": "GlCommitSha", + "module": "src/webviews/apps/shared/components/commit-sha.ts" + } + }, + { + "kind": "js", + "name": "renderCommitSha", + "declaration": { + "name": "renderCommitSha", + "module": "src/webviews/apps/shared/components/commit-sha.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/promo.ts", + "path": "src/webviews/apps/shared/components/copy-container.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlPromo", + "name": "GlCopyContainer", "members": [ { "kind": "field", - "name": "shadowRootOptions", + "name": "tagName", + "static": true, + "readonly": true, + "default": "'gl-copy-container'", "type": { - "text": "ShadowRootInit" + "text": "string" + } + }, + { + "kind": "field", + "name": "appearance", + "type": { + "text": "'toolbar' | undefined" }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + "attribute": "appearance", + "reflects": true }, { "kind": "field", - "name": "_focusable", + "name": "content", "type": { - "text": "HTMLElement | undefined" + "text": "string | undefined" }, - "privacy": "private" + "attribute": "content" }, { "kind": "field", - "name": "promoPromise", + "name": "copyLabel", "type": { - "text": "Promise | undefined" + "text": "string" }, - "attribute": "promoPromise" + "default": "'Copy'", + "attribute": "copyLabel" }, { "kind": "field", - "name": "source", + "name": "copiedLabel", "type": { - "text": "Source | undefined" + "text": "string" }, - "attribute": "source" + "default": "'Copied'", + "attribute": "copiedLabel" }, { "kind": "field", - "name": "type", + "name": "disabled", "type": { - "text": "'icon' | 'info' | 'link'" + "text": "boolean" }, - "default": "'info'", - "attribute": "type", + "default": "false", + "attribute": "disabled", "reflects": true }, { "kind": "field", - "name": "_hasPromo", + "name": "placement", "type": { - "text": "boolean" + "text": "GlTooltip['placement'] | undefined" }, - "privacy": "private", - "default": "false" + "default": "'top'", + "attribute": "placement" }, { "kind": "field", - "name": "hasPromo", - "privacy": "private", - "attribute": "has-promo", - "reflects": true + "name": "timeout", + "type": { + "text": "number" + }, + "default": "1000", + "attribute": "timeout" + }, + { + "kind": "field", + "name": "_resetTimer", + "type": { + "text": "ReturnType | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "label", + "type": { + "text": "string" + }, + "privacy": "private" }, { "kind": "method", - "name": "renderPromo", + "name": "onClick", "privacy": "private", "parameters": [ { - "name": "promo", + "name": "_e", "type": { - "text": "Promo | undefined" + "text": "MouseEvent" } } ] }, { "kind": "method", - "name": "getCommandUrl", - "privacy": "private", - "parameters": [ - { - "name": "promo", - "type": { - "text": "Promo | undefined" - } - } - ] + "name": "cancelResetTimer", + "privacy": "private" }, { "kind": "method", - "name": "focus", - "return": { - "type": { - "text": "void" - } - } + "name": "createResetTimer", + "privacy": "private" } ], "attributes": [ { - "name": "promoPromise", + "name": "appearance", "type": { - "text": "Promise | undefined" + "text": "'toolbar' | undefined" }, - "fieldName": "promoPromise" + "fieldName": "appearance" }, { - "name": "source", + "name": "content", "type": { - "text": "Source | undefined" + "text": "string | undefined" }, - "fieldName": "source" + "fieldName": "content" }, { - "name": "type", + "name": "copyLabel", "type": { - "text": "'icon' | 'info' | 'link'" + "text": "string" }, - "default": "'info'", - "fieldName": "type" + "default": "'Copy'", + "fieldName": "copyLabel" }, { - "name": "has-promo", - "fieldName": "hasPromo" + "name": "copiedLabel", + "type": { + "text": "string" + }, + "default": "'Copied'", + "fieldName": "copiedLabel" + }, + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "placement", + "type": { + "text": "GlTooltip['placement'] | undefined" + }, + "default": "'top'", + "fieldName": "placement" + }, + { + "name": "timeout", + "type": { + "text": "number" + }, + "default": "1000", + "fieldName": "timeout" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-promo", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlPromo", + "name": "GlCopyContainer", "declaration": { - "name": "GlPromo", - "module": "src/webviews/apps/shared/components/promo.ts" + "name": "GlCopyContainer", + "module": "src/webviews/apps/shared/components/copy-container.ts" } }, { "kind": "custom-element-definition", - "name": "gl-promo", "declaration": { - "name": "GlPromo", - "module": "src/webviews/apps/shared/components/promo.ts" + "name": "GlCopyContainer", + "module": "src/webviews/apps/shared/components/copy-container.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/ref-button.ts", + "path": "src/webviews/apps/shared/components/element.ts", "declarations": [ { - "kind": "class", - "description": "", - "name": "GlRefButton", - "members": [ - { - "kind": "field", - "name": "disabled", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "disabled", - "reflects": true - }, - { - "kind": "field", - "name": "href", - "type": { - "text": "string | undefined" - }, - "attribute": "href", - "reflects": true - }, - { - "kind": "field", - "name": "icon", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "icon", - "reflects": true - }, - { - "kind": "field", - "name": "ref", - "type": { - "text": "GitReference | undefined" - }, - "attribute": "ref" - }, + "kind": "function", + "name": "observe", + "parameters": [ { - "kind": "field", - "name": "size", + "name": "keys", "type": { - "text": "number" - }, - "default": "16", - "attribute": "size" + "text": "keyof T | (keyof T)[]" + } }, { - "kind": "field", - "name": "worktree", + "name": "options", + "optional": true, "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "worktree" + "text": "{ afterFirstUpdate?: boolean }" + } } - ], - "attributes": [ - { - "name": "disabled", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "disabled" - }, - { - "name": "href", - "type": { - "text": "string | undefined" - }, - "fieldName": "href" - }, - { - "name": "icon", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "icon" - }, + ] + }, + { + "kind": "class", + "description": "", + "name": "GlElement", + "members": [ { - "name": "ref", - "type": { - "text": "GitReference | undefined" + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } }, - "fieldName": "ref" + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ] }, { - "name": "size", - "type": { - "text": "number" + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } }, - "default": "16", - "fieldName": "size" + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "optional": true, + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ] }, { - "name": "worktree", - "type": { - "text": "boolean" + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } }, - "default": "false", - "fieldName": "worktree" + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ] } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-ref-button", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlRefButton", + "name": "observe", "declaration": { - "name": "GlRefButton", - "module": "src/webviews/apps/shared/components/ref-button.ts" + "name": "observe", + "module": "src/webviews/apps/shared/components/element.ts" } }, { - "kind": "custom-element-definition", - "name": "gl-ref-button", + "kind": "js", + "name": "GlElement", "declaration": { - "name": "GlRefButton", - "module": "src/webviews/apps/shared/components/ref-button.ts" + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/ref-name.ts", + "path": "src/webviews/apps/shared/components/feature-badge.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlRefName", + "name": "GlFeatureBadge", "members": [ { "kind": "field", - "name": "icon", + "name": "cloud", "type": { "text": "boolean" }, "default": "false", - "attribute": "icon", - "reflects": true + "attribute": "cloud" }, { "kind": "field", - "name": "ref", + "name": "placement", "type": { - "text": "GitReference | undefined" + "text": "GlPopover['placement']" }, - "attribute": "ref" + "default": "'bottom'", + "attribute": "placement", + "reflects": true }, { "kind": "field", - "name": "size", + "name": "preview", "type": { - "text": "number" + "text": "boolean" }, - "default": "13", - "attribute": "size" + "default": "false", + "attribute": "preview" }, { "kind": "field", - "name": "worktree", + "name": "promos", "type": { - "text": "boolean" + "text": "PromosContext" }, - "default": "false", - "attribute": "worktree" + "privacy": "private" + }, + { + "kind": "field", + "name": "source", + "type": { + "text": "Source | undefined" + }, + "attribute": "source" + }, + { + "kind": "field", + "name": "subscription", + "type": { + "text": "Subscription | undefined" + } + }, + { + "kind": "field", + "name": "daysRemaining", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "state", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "renderBadge", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPopoverHeader", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPopoverContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderStartTrialActions", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderUpgradeActions", + "privacy": "private", + "parameters": [ + { + "name": "leadin", + "optional": true, + "type": { + "text": "TemplateResult" + } + } + ] + }, + { + "kind": "method", + "name": "renderPromo", + "privacy": "private" } ], "attributes": [ { - "name": "icon", + "name": "cloud", "type": { "text": "boolean" }, "default": "false", - "fieldName": "icon" + "fieldName": "cloud" }, { - "name": "ref", + "name": "placement", "type": { - "text": "GitReference | undefined" + "text": "GlPopover['placement']" }, - "fieldName": "ref" + "default": "'bottom'", + "fieldName": "placement" }, { - "name": "size", + "name": "preview", "type": { - "text": "number" + "text": "boolean" }, - "default": "13", - "fieldName": "size" + "default": "false", + "fieldName": "preview" }, { - "name": "worktree", + "name": "source", "type": { - "text": "boolean" + "text": "Source | undefined" }, - "default": "false", - "fieldName": "worktree" + "fieldName": "source" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-ref-name", + "tagName": "gl-feature-badge", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlRefName", + "name": "GlFeatureBadge", "declaration": { - "name": "GlRefName", - "module": "src/webviews/apps/shared/components/ref-name.ts" + "name": "GlFeatureBadge", + "module": "src/webviews/apps/shared/components/feature-badge.ts" } }, { "kind": "custom-element-definition", - "name": "gl-ref-name", - "declaration": { - "name": "GlRefName", - "module": "src/webviews/apps/shared/components/ref-name.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/ref.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "refButtonBaseStyles", - "default": "css` :host { box-sizing: border-box; display: flex; align-items: center; max-width: 100%; min-width: 4.6rem; } * { box-sizing: border-box; } `" - }, - { - "kind": "variable", - "name": "pickerIconStyles", - "default": "css` code-icon.picker-icon { font-size: 1rem; /* margin-top: 0.4rem; */ margin-right: -0.25rem; } code-icon.picker-icon::before { margin-left: -0.4rem; } `" - }, - { - "kind": "variable", - "name": "truncatedButtonStyles", - "default": "css` .truncated-button { max-width: 100%; min-width: 4rem; } gl-button[disabled] { opacity: 1; cursor: default; } .truncated-button__label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "refButtonBaseStyles", - "declaration": { - "name": "refButtonBaseStyles", - "module": "src/webviews/apps/shared/components/ref.css.ts" - } - }, - { - "kind": "js", - "name": "pickerIconStyles", - "declaration": { - "name": "pickerIconStyles", - "module": "src/webviews/apps/shared/components/ref.css.ts" - } - }, - { - "kind": "js", - "name": "truncatedButtonStyles", + "name": "gl-feature-badge", "declaration": { - "name": "truncatedButtonStyles", - "module": "src/webviews/apps/shared/components/ref.css.ts" + "name": "GlFeatureBadge", + "module": "src/webviews/apps/shared/components/feature-badge.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/repo-button-group.ts", + "path": "src/webviews/apps/shared/components/feature-gate.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlRepoButtonGroup", + "name": "GlFeatureGate", "members": [ { "kind": "field", - "name": "connectIcon", - "type": { - "text": "boolean" - }, - "default": "true", - "attribute": "connectIcon" - }, - { - "kind": "field", - "name": "disabled", + "name": "appearance", "type": { - "text": "boolean" + "text": "'alert' | 'welcome' | undefined" }, - "default": "false", - "attribute": "disabled" + "attribute": "appearance", + "reflects": true }, { "kind": "field", - "name": "icon", + "name": "featurePreview", "type": { - "text": "boolean" + "text": "FeaturePreview | undefined" }, - "default": "true", - "attribute": "icon" + "attribute": "featurePreview" }, { "kind": "field", - "name": "repository", + "name": "featurePreviewCommandLink", "type": { - "text": "RepositoryShape | undefined" + "text": "string | undefined" }, - "attribute": "repository" + "attribute": "featurePreviewCommandLink" }, { "kind": "field", - "name": "hasMultipleRepositories", + "name": "featureWithArticleIfNeeded", "type": { - "text": "boolean | undefined" + "text": "string | undefined" }, - "default": "false", - "attribute": "hasMultipleRepositories" + "attribute": "featureWithArticleIfNeeded" }, { "kind": "field", @@ -13368,114 +14452,48 @@ }, { "kind": "field", - "name": "expandable", + "name": "state", "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expandable", - "reflects": true - }, - { - "kind": "field", - "name": "icons", - "readonly": true, - "attribute": "icons", - "reflects": true + "text": "SubscriptionState | undefined" + } }, { "kind": "field", - "name": "displayName", + "name": "webroot", "type": { - "text": "string" - }, - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "renderProviderIcon", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderConnectIcon", - "privacy": "private" - }, - { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "text": "string | undefined" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + "attribute": "webroot" } ], "attributes": [ { - "name": "connectIcon", - "type": { - "text": "boolean" - }, - "default": "true", - "fieldName": "connectIcon" - }, - { - "name": "disabled", + "name": "appearance", "type": { - "text": "boolean" + "text": "'alert' | 'welcome' | undefined" }, - "default": "false", - "fieldName": "disabled" + "fieldName": "appearance" }, { - "name": "icon", + "name": "featurePreview", "type": { - "text": "boolean" + "text": "FeaturePreview | undefined" }, - "default": "true", - "fieldName": "icon" + "fieldName": "featurePreview" }, { - "name": "repository", + "name": "featurePreviewCommandLink", "type": { - "text": "RepositoryShape | undefined" + "text": "string | undefined" }, - "fieldName": "repository" + "fieldName": "featurePreviewCommandLink" }, { - "name": "hasMultipleRepositories", + "name": "featureWithArticleIfNeeded", "type": { - "text": "boolean | undefined" + "text": "string | undefined" }, - "default": "false", - "fieldName": "hasMultipleRepositories" + "fieldName": "featureWithArticleIfNeeded" }, { "name": "source", @@ -13485,1161 +14503,1170 @@ "fieldName": "source" }, { - "name": "expandable", + "name": "webroot", "type": { - "text": "boolean" + "text": "string | undefined" }, - "default": "false", - "fieldName": "expandable" - }, - { - "name": "icons", - "readonly": true, - "fieldName": "icons" + "fieldName": "webroot" } ], "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" + "name": "LitElement", + "package": "lit" }, - "tagName": "gl-repo-button-group", + "tagName": "gl-feature-gate", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlRepoButtonGroup", + "name": "GlFeatureGate", "declaration": { - "name": "GlRepoButtonGroup", - "module": "src/webviews/apps/shared/components/repo-button-group.ts" + "name": "GlFeatureGate", + "module": "src/webviews/apps/shared/components/feature-gate.ts" } }, { "kind": "custom-element-definition", - "name": "gl-repo-button-group", + "name": "gl-feature-gate", "declaration": { - "name": "GlRepoButtonGroup", - "module": "src/webviews/apps/shared/components/repo-button-group.ts" + "name": "GlFeatureGate", + "module": "src/webviews/apps/shared/components/feature-gate.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/signal-utils.ts", + "path": "src/webviews/apps/shared/components/formatted-date.ts", "declarations": [ - { - "kind": "function", - "name": "renderAsyncComputed", - "return": { - "type": { - "text": "R | undefined" - } - }, - "parameters": [ - { - "name": "v", - "type": { - "text": "AsyncComputed" - } - }, - { - "name": "{\n\t\tinitial,\n\t\tpending,\n\t\tcomplete,\n\t\terror,\n\t}", - "type": { - "text": "{\n\t\tinitial?: () => R;\n\t\tpending?: () => R;\n\t\tcomplete?: (value: T | undefined) => R;\n\t\terror?: (error: unknown) => R;\n\t}" - } - } - ] - }, { "kind": "class", "description": "", - "name": "AsyncComputedState", + "name": "FormattedDate", "members": [ { "kind": "field", - "name": "_debounce", + "name": "format", "type": { - "text": "number" + "text": "string | undefined" }, - "privacy": "private", - "default": "500" - }, - { - "kind": "field", - "name": "_invalidate", - "privacy": "private" + "attribute": "format" }, { "kind": "field", - "name": "_computed", + "name": "dateStyle", "type": { - "text": "AsyncComputed | undefined" + "text": "'relative' | 'absolute'" }, - "privacy": "private" + "default": "'relative'", + "attribute": "date-style" }, { "kind": "field", - "name": "_state", - "privacy": "private" + "name": "date", + "default": "new Date()" }, { "kind": "field", - "name": "state", + "name": "tooltip", "type": { - "text": "T | undefined" + "text": "string" }, - "readonly": true + "default": "''", + "attribute": "tooltip" }, { "kind": "field", - "name": "computed", + "name": "absoluteDate", "type": { - "text": "AsyncComputed" + "text": "string" }, "readonly": true }, - { - "kind": "method", - "name": "_runCore", - "privacy": "private" - }, { "kind": "field", - "name": "_runDebounced", + "name": "dateLabel", "type": { - "text": "Deferrable<() => void> | undefined" - }, - "privacy": "private" - }, - { - "kind": "method", - "name": "_run", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "immediate", - "default": "false" - } - ] - }, - { - "kind": "method", - "name": "run", - "return": { - "type": { - "text": "void" - } + "text": "string" }, - "parameters": [ - { - "name": "force", - "default": "false" - } - ] - }, - { - "kind": "method", - "name": "invalidate", - "return": { - "type": { - "text": "void" - } - } + "readonly": true } - ] - }, - { - "kind": "function", - "name": "signalState", - "parameters": [ + ], + "attributes": [ { - "name": "initialValue", - "optional": true, + "name": "format", "type": { - "text": "T" - } - } - ] - }, - { - "kind": "function", - "name": "signalObjectState", - "parameters": [ + "text": "string | undefined" + }, + "fieldName": "format" + }, { - "name": "initialValue", - "optional": true, + "name": "date-style", "type": { - "text": "T" - } + "text": "'relative' | 'absolute'" + }, + "default": "'relative'", + "fieldName": "dateStyle" }, { - "name": "options", - "default": "{}", + "name": "tooltip", "type": { - "text": "{ afterChange?: (target: any, value: T) => void }" - } + "text": "string" + }, + "default": "''", + "fieldName": "tooltip" } - ] + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "formatted-date", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "renderAsyncComputed", + "name": "FormattedDate", "declaration": { - "name": "renderAsyncComputed", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "name": "FormattedDate", + "module": "src/webviews/apps/shared/components/formatted-date.ts" } }, { - "kind": "js", - "name": "AsyncComputedState", + "kind": "custom-element-definition", + "name": "formatted-date", "declaration": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } - }, - { - "kind": "js", - "name": "signalState", - "declaration": { - "name": "signalState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } - }, - { - "kind": "js", - "name": "signalObjectState", - "declaration": { - "name": "signalObjectState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "name": "FormattedDate", + "module": "src/webviews/apps/shared/components/formatted-date.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/skeleton-loader.ts", + "path": "src/webviews/apps/shared/components/gitlens-logo.ts", "declarations": [ { "kind": "class", "description": "", - "name": "SkeletonLoader", - "members": [ - { - "kind": "field", - "name": "lines", - "type": { - "text": "number" - }, - "default": "1", - "attribute": "lines" - } - ], - "attributes": [ - { - "name": "lines", - "type": { - "text": "number" - }, - "default": "1", - "fieldName": "lines" - } - ], + "name": "GitLensLogo", + "members": [], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "skeleton-loader", + "tagName": "gitlens-logo", "customElement": true } ], "exports": [ { "kind": "js", - "name": "SkeletonLoader", + "name": "GitLensLogo", "declaration": { - "name": "SkeletonLoader", - "module": "src/webviews/apps/shared/components/skeleton-loader.ts" + "name": "GitLensLogo", + "module": "src/webviews/apps/shared/components/gitlens-logo.ts" } }, { "kind": "custom-element-definition", - "name": "skeleton-loader", + "name": "gitlens-logo", "declaration": { - "name": "SkeletonLoader", - "module": "src/webviews/apps/shared/components/skeleton-loader.ts" + "name": "GitLensLogo", + "module": "src/webviews/apps/shared/components/gitlens-logo.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/snow.ts", + "path": "src/webviews/apps/shared/components/mcp-banner.ts", "declarations": [ + { + "kind": "variable", + "name": "mcpBannerTagName", + "type": { + "text": "string" + }, + "default": "'gl-mcp-banner'" + }, { "kind": "class", "description": "", - "name": "GlSnow", + "name": "GlMcpBanner", "members": [ { "kind": "field", - "name": "snowing", + "name": "shadowRootOptions", "type": { - "text": "boolean" + "text": "ShadowRootInit" }, - "default": "false", - "attribute": "snowing", - "reflects": true + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" }, { "kind": "field", - "name": "_canvas", + "name": "source", "type": { - "text": "HTMLCanvasElement | undefined" + "text": "string" }, - "privacy": "private" + "default": "'unknown'", + "attribute": "source" }, { "kind": "field", - "name": "_ctx", + "name": "layout", "type": { - "text": "CanvasRenderingContext2D | undefined" + "text": "'default' | 'responsive'" }, - "privacy": "private" + "default": "'default'", + "attribute": "layout" }, { "kind": "field", - "name": "_snowflakes", + "name": "collapsed", "type": { - "text": "Snowflake[]" + "text": "boolean" }, - "privacy": "private", - "default": "[]" + "default": "false", + "attribute": "collapsed" }, { "kind": "field", - "name": "_animationFrame", + "name": "canAutoRegister", "type": { - "text": "number | undefined" + "text": "boolean" }, - "privacy": "private" - }, + "privacy": "private", + "default": "false", + "attribute": "canAutoRegister" + } + ], + "attributes": [ { - "kind": "field", - "name": "_resizeObserver", + "name": "source", "type": { - "text": "ResizeObserver | undefined" + "text": "string" }, - "privacy": "private" - }, - { - "kind": "method", - "name": "renderToggle", - "privacy": "private" + "default": "'unknown'", + "fieldName": "source" }, { - "kind": "method", - "name": "onToggle", - "privacy": "private", - "return": { - "type": { - "text": "void" - } + "name": "layout", + "type": { + "text": "'default' | 'responsive'" }, - "parameters": [ - { - "name": "snowing", - "type": { - "text": "boolean" - } - } - ] - }, - { - "kind": "method", - "name": "updateCanvasSize", - "privacy": "private", - "return": { - "type": { - "text": "void" - } - } - }, - { - "kind": "method", - "name": "clear", - "privacy": "private", - "return": { - "type": { - "text": "void" - } - } + "default": "'default'", + "fieldName": "layout" }, { - "kind": "method", - "name": "createSnowflakes", - "privacy": "private", - "return": { - "type": { - "text": "void" - } - } + "name": "collapsed", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "collapsed" }, { - "kind": "method", - "name": "updateAnimation", - "privacy": "private", - "return": { - "type": { - "text": "void" - } - } - } - ], - "attributes": [ - { - "name": "snowing", + "name": "canAutoRegister", "type": { "text": "boolean" }, "default": "false", - "fieldName": "snowing" + "fieldName": "canAutoRegister" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-snow", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlSnow", + "name": "mcpBannerTagName", "declaration": { - "name": "GlSnow", - "module": "src/webviews/apps/shared/components/snow.ts" + "name": "mcpBannerTagName", + "module": "src/webviews/apps/shared/components/mcp-banner.ts" + } + }, + { + "kind": "js", + "name": "GlMcpBanner", + "declaration": { + "name": "GlMcpBanner", + "module": "src/webviews/apps/shared/components/mcp-banner.ts" } }, { "kind": "custom-element-definition", - "name": "gl-snow", "declaration": { - "name": "GlSnow", - "module": "src/webviews/apps/shared/components/snow.ts" + "name": "GlMcpBanner", + "module": "src/webviews/apps/shared/components/mcp-banner.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/webview-pane.ts", + "path": "src/webviews/apps/shared/components/progress.ts", "declarations": [ { "kind": "class", "description": "", - "name": "WebviewPane", + "name": "ProgressIndicator", "members": [ { "kind": "field", - "name": "collapsable", + "name": "mode", "type": { - "text": "boolean" + "text": "string" }, - "default": "false", - "attribute": "collapsable", + "default": "'infinite'", + "attribute": "mode", "reflects": true }, { "kind": "field", - "name": "expanded", + "name": "active", "type": { "text": "boolean" }, "default": "false", - "attribute": "expanded", - "reflects": true + "attribute": "active" }, { "kind": "field", - "name": "loading", + "name": "position", "type": { - "text": "boolean" + "text": "'top' | 'bottom'" }, - "default": "false", - "attribute": "loading", - "reflects": true - }, - { - "kind": "method", - "name": "renderTitle", - "privacy": "private" - }, - { - "kind": "method", - "name": "toggleExpanded", - "privacy": "private" - } - ], - "events": [ - { - "name": "expanded-change", - "type": { - "text": "CustomEvent" - } + "default": "'bottom'", + "attribute": "position" } ], "attributes": [ { - "name": "collapsable", + "name": "mode", "type": { - "text": "boolean" + "text": "string" }, - "default": "false", - "fieldName": "collapsable" + "default": "'infinite'", + "fieldName": "mode" }, { - "name": "expanded", + "name": "active", "type": { "text": "boolean" }, "default": "false", - "fieldName": "expanded" + "fieldName": "active" }, { - "name": "loading", + "name": "position", "type": { - "text": "boolean" + "text": "'top' | 'bottom'" }, - "default": "false", - "fieldName": "loading" + "default": "'bottom'", + "fieldName": "position" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "webview-pane", + "tagName": "progress-indicator", "customElement": true } ], "exports": [ { "kind": "js", - "name": "WebviewPane", + "name": "ProgressIndicator", "declaration": { - "name": "WebviewPane", - "module": "src/webviews/apps/shared/components/webview-pane.ts" + "name": "ProgressIndicator", + "module": "src/webviews/apps/shared/components/progress.ts" } }, { "kind": "custom-element-definition", - "name": "webview-pane", - "declaration": { - "name": "WebviewPane", - "module": "src/webviews/apps/shared/components/webview-pane.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/contexts/ipc.ts", - "declarations": [ - { - "kind": "variable", - "name": "ipcContext" - } - ], - "exports": [ - { - "kind": "js", - "name": "ipcContext", + "name": "progress-indicator", "declaration": { - "name": "ipcContext", - "module": "src/webviews/apps/shared/contexts/ipc.ts" + "name": "ProgressIndicator", + "module": "src/webviews/apps/shared/components/progress.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/contexts/logger.ts", + "path": "src/webviews/apps/shared/components/promo.ts", "declarations": [ { "kind": "class", "description": "", - "name": "LoggerContext", + "name": "GlPromo", "members": [ { "kind": "field", - "name": "scope", + "name": "shadowRootOptions", "type": { - "text": "LogScope" + "text": "ShadowRootInit" }, - "privacy": "private", - "readonly": true + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" }, { - "kind": "method", - "name": "log", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "_focusable", + "type": { + "text": "HTMLElement | undefined" }, - "parameters": [ - { - "name": "messageOrScope", - "type": { - "text": "string | LogScope | undefined" - } - }, - { - "name": "optionalParams", - "type": { - "text": "any[]" - } - } - ] - } - ] - }, - { - "kind": "variable", - "name": "loggerContext" - } - ], - "exports": [ - { - "kind": "js", - "name": "LoggerContext", - "declaration": { - "name": "LoggerContext", - "module": "src/webviews/apps/shared/contexts/logger.ts" - } - }, - { - "kind": "js", - "name": "loggerContext", - "declaration": { - "name": "loggerContext", - "module": "src/webviews/apps/shared/contexts/logger.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/contexts/promos.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "PromosContext", - "members": [ + "privacy": "private" + }, { "kind": "field", - "name": "ipc", + "name": "promoPromise", "type": { - "text": "HostIpc" + "text": "Promise | undefined" }, - "privacy": "private", - "readonly": true, - "default": "ipc" + "attribute": "promoPromise" }, { "kind": "field", - "name": "disposables", + "name": "source", "type": { - "text": "Disposable[]" + "text": "Source | undefined" + }, + "attribute": "source" + }, + { + "kind": "field", + "name": "type", + "type": { + "text": "'icon' | 'info' | 'link'" + }, + "default": "'info'", + "attribute": "type", + "reflects": true + }, + { + "kind": "field", + "name": "_hasPromo", + "type": { + "text": "boolean" }, "privacy": "private", - "readonly": true, - "default": "[]" + "default": "false" }, { "kind": "field", - "name": "_promos", + "name": "hasPromo", "privacy": "private", - "default": "new Map<`${PromoPlans | undefined}|${PromoLocation | undefined}`, Promise>()" + "attribute": "has-promo", + "reflects": true }, { "kind": "method", - "name": "getApplicablePromo", - "return": { - "type": { - "text": "Promise" - } - }, + "name": "renderPromo", + "privacy": "private", "parameters": [ { - "name": "plan", - "optional": true, + "name": "promo", "type": { - "text": "PromoPlans" + "text": "Promo | undefined" } - }, + } + ] + }, + { + "kind": "method", + "name": "getCommandUrl", + "privacy": "private", + "parameters": [ { - "name": "location", - "optional": true, + "name": "promo", "type": { - "text": "PromoLocation" + "text": "Promo | undefined" } } ] }, { "kind": "method", - "name": "dispose", + "name": "focus", "return": { "type": { "text": "void" } } } - ] - }, - { - "kind": "variable", - "name": "promosContext" + ], + "attributes": [ + { + "name": "promoPromise", + "type": { + "text": "Promise | undefined" + }, + "fieldName": "promoPromise" + }, + { + "name": "source", + "type": { + "text": "Source | undefined" + }, + "fieldName": "source" + }, + { + "name": "type", + "type": { + "text": "'icon' | 'info' | 'link'" + }, + "default": "'info'", + "fieldName": "type" + }, + { + "name": "has-promo", + "fieldName": "hasPromo" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-promo", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "PromosContext", + "name": "GlPromo", "declaration": { - "name": "PromosContext", - "module": "src/webviews/apps/shared/contexts/promos.ts" + "name": "GlPromo", + "module": "src/webviews/apps/shared/components/promo.ts" } }, { - "kind": "js", - "name": "promosContext", + "kind": "custom-element-definition", + "name": "gl-promo", "declaration": { - "name": "promosContext", - "module": "src/webviews/apps/shared/contexts/promos.ts" + "name": "GlPromo", + "module": "src/webviews/apps/shared/components/promo.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/contexts/telemetry.ts", + "path": "src/webviews/apps/shared/components/ref-button.ts", "declarations": [ { "kind": "class", "description": "", - "name": "TelemetryContext", + "name": "GlRefButton", "members": [ { "kind": "field", - "name": "ipc", + "name": "disabled", "type": { - "text": "HostIpc" + "text": "boolean" }, - "privacy": "private", - "readonly": true, - "default": "ipc" + "default": "false", + "attribute": "disabled", + "reflects": true }, { "kind": "field", - "name": "disposables", + "name": "href", "type": { - "text": "Disposable[]" + "text": "string | undefined" }, - "privacy": "private", - "readonly": true, - "default": "[]" + "attribute": "href", + "reflects": true }, { - "kind": "method", - "name": "sendEvent", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "icon", + "type": { + "text": "boolean" }, - "parameters": [ - { - "name": "detail", - "type": { - "text": "TelemetrySendEventParams" - } - } - ] + "default": "false", + "attribute": "icon", + "reflects": true }, { - "kind": "method", - "name": "dispose", - "return": { - "type": { - "text": "void" - } - } + "kind": "field", + "name": "ref", + "type": { + "text": "GitReference | undefined" + }, + "attribute": "ref" + }, + { + "kind": "field", + "name": "size", + "type": { + "text": "number" + }, + "default": "16", + "attribute": "size" + }, + { + "kind": "field", + "name": "worktree", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "worktree" } - ] - }, - { - "kind": "variable", - "name": "telemetryContext" + ], + "attributes": [ + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "href", + "type": { + "text": "string | undefined" + }, + "fieldName": "href" + }, + { + "name": "icon", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "icon" + }, + { + "name": "ref", + "type": { + "text": "GitReference | undefined" + }, + "fieldName": "ref" + }, + { + "name": "size", + "type": { + "text": "number" + }, + "default": "16", + "fieldName": "size" + }, + { + "name": "worktree", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "worktree" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-ref-button", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "TelemetryContext", + "name": "GlRefButton", "declaration": { - "name": "TelemetryContext", - "module": "src/webviews/apps/shared/contexts/telemetry.ts" + "name": "GlRefButton", + "module": "src/webviews/apps/shared/components/ref-button.ts" } }, { - "kind": "js", - "name": "telemetryContext", + "kind": "custom-element-definition", + "name": "gl-ref-button", "declaration": { - "name": "telemetryContext", - "module": "src/webviews/apps/shared/contexts/telemetry.ts" + "name": "GlRefButton", + "module": "src/webviews/apps/shared/components/ref-button.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts", + "path": "src/webviews/apps/shared/components/ref-name.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlDraftDetails", + "name": "GlRefName", "members": [ { "kind": "field", - "name": "state", + "name": "icon", "type": { - "text": "State" + "text": "boolean" }, - "attribute": "state" + "default": "false", + "attribute": "icon", + "reflects": true }, { "kind": "field", - "name": "explainBusy", + "name": "ref", "type": { - "text": "boolean" + "text": "GitReference | undefined" }, - "default": "false" + "attribute": "ref" }, { "kind": "field", - "name": "explain", + "name": "size", "type": { - "text": "ExplainState | undefined" + "text": "number" }, - "attribute": "explain" + "default": "13", + "attribute": "size" }, { "kind": "field", - "name": "selectedPatches", + "name": "worktree", "type": { - "text": "string[]" + "text": "boolean" }, - "default": "[]" - }, + "default": "false", + "attribute": "worktree" + } + ], + "attributes": [ { - "kind": "field", - "name": "validityMessage", + "name": "icon", "type": { - "text": "string | undefined" - } + "text": "boolean" + }, + "default": "false", + "fieldName": "icon" }, { - "kind": "field", - "name": "_copiedLink", + "name": "ref", "type": { - "text": "boolean" + "text": "GitReference | undefined" }, - "privacy": "private", - "default": "false" + "fieldName": "ref" }, { - "kind": "field", - "name": "cloudDraft", - "readonly": true + "name": "size", + "type": { + "text": "number" + }, + "default": "13", + "fieldName": "size" }, + { + "name": "worktree", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "worktree" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-ref-name", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlRefName", + "declaration": { + "name": "GlRefName", + "module": "src/webviews/apps/shared/components/ref-name.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-ref-name", + "declaration": { + "name": "GlRefName", + "module": "src/webviews/apps/shared/components/ref-name.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/ref.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "refButtonBaseStyles", + "default": "css` :host { box-sizing: border-box; display: flex; align-items: center; max-width: 100%; min-width: 4.6rem; } * { box-sizing: border-box; } `" + }, + { + "kind": "variable", + "name": "pickerIconStyles", + "default": "css` code-icon.picker-icon { font-size: 1rem; /* margin-top: 0.4rem; */ margin-right: -0.25rem; } code-icon.picker-icon::before { margin-left: -0.4rem; } `" + }, + { + "kind": "variable", + "name": "truncatedButtonStyles", + "default": "css` .truncated-button { max-width: 100%; min-width: 4rem; } gl-button[disabled] { opacity: 1; cursor: default; } .truncated-button__label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "refButtonBaseStyles", + "declaration": { + "name": "refButtonBaseStyles", + "module": "src/webviews/apps/shared/components/ref.css.ts" + } + }, + { + "kind": "js", + "name": "pickerIconStyles", + "declaration": { + "name": "pickerIconStyles", + "module": "src/webviews/apps/shared/components/ref.css.ts" + } + }, + { + "kind": "js", + "name": "truncatedButtonStyles", + "declaration": { + "name": "truncatedButtonStyles", + "module": "src/webviews/apps/shared/components/ref.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/repo-button-group.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlRepoButtonGroup", + "members": [ { "kind": "field", - "name": "isCodeSuggestion", + "name": "connectIcon", "type": { "text": "boolean" }, - "readonly": true + "default": "true", + "attribute": "connectIcon" }, { "kind": "field", - "name": "canSubmit", + "name": "disabled", "type": { "text": "boolean" }, - "readonly": true + "default": "false", + "attribute": "disabled" }, { - "kind": "method", - "name": "renderEmptyContent", - "privacy": "private" + "kind": "field", + "name": "icon", + "type": { + "text": "boolean" + }, + "default": "true", + "attribute": "icon" }, { - "kind": "method", - "name": "renderPatchMessage", - "privacy": "private" + "kind": "field", + "name": "repository", + "type": { + "text": "RepositoryShape | undefined" + }, + "attribute": "repository" }, { - "kind": "method", - "name": "renderExplainAi", - "privacy": "private" + "kind": "field", + "name": "hasMultipleRepositories", + "type": { + "text": "boolean | undefined" + }, + "default": "false", + "attribute": "hasMultipleRepositories" }, { - "kind": "method", - "name": "renderChangedFiles", - "privacy": "private" + "kind": "field", + "name": "source", + "type": { + "text": "Source | undefined" + }, + "attribute": "source" }, { "kind": "field", - "name": "treeModel", + "name": "expandable", "type": { - "text": "TreeModel[]" + "text": "boolean" }, - "readonly": true + "default": "false", + "attribute": "expandable", + "reflects": true }, { - "kind": "method", - "name": "renderUserSelection", - "privacy": "private", - "parameters": [ - { - "name": "userSelection", - "type": { - "text": "DraftUserSelection" - } - }, - { - "name": "role", - "type": { - "text": "DraftRole" - } - } - ] + "kind": "field", + "name": "icons", + "readonly": true, + "attribute": "icons", + "reflects": true }, { - "kind": "method", - "name": "renderUserSelectionList", + "kind": "field", + "name": "displayName", + "type": { + "text": "string" + }, "privacy": "private", - "parameters": [ - { - "name": "draft", - "type": { - "text": "CloudDraftDetails" - } - }, - { - "name": "includeOwner", - "default": "false" - } - ] - }, - { - "kind": "method", - "name": "renderPatchPermissions", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderCodeSuggectionActions", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderPatches", - "privacy": "private" + "readonly": true }, { "kind": "method", - "name": "renderActionbar", + "name": "renderProviderIcon", "privacy": "private" }, { "kind": "method", - "name": "renderDraftInfo", + "name": "renderConnectIcon", "privacy": "private" }, { "kind": "method", - "name": "onInviteUsers", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "Event" - } + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" } - ] - }, - { - "kind": "method", - "name": "onChangeSelectionRole", - "privacy": "private", + }, "parameters": [ { - "name": "e", + "name": "name", "type": { - "text": "MouseEvent" + "text": "T" } }, { - "name": "selection", + "name": "detail", "type": { - "text": "DraftUserSelection" + "text": "CustomEventDetailType" } }, { - "name": "role", + "name": "options", + "optional": true, "type": { - "text": "PatchDetailsUpdateSelectionEventDetail['role']" + "text": "Omit>, 'detail'>" } } - ] - }, + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ { - "kind": "method", - "name": "onVisibilityChange", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "Event" - } - } - ] + "name": "connectIcon", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "connectIcon" }, { - "kind": "method", - "name": "onUpdatePatch", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "Event" - } - } - ] + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" }, { - "kind": "method", - "name": "onExplainChanges", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MouseEvent | KeyboardEvent" - } - } - ] + "name": "icon", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "icon" }, { - "kind": "method", - "name": "onTreeItemActionClicked", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "name": "repository", + "type": { + "text": "RepositoryShape | undefined" }, - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + "fieldName": "repository" }, { - "kind": "method", - "name": "fireFileEvent", - "return": { - "type": { - "text": "void" - } + "name": "hasMultipleRepositories", + "type": { + "text": "boolean | undefined" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "file", - "type": { - "text": "DraftPatchFileChange" - } - }, - { - "name": "showOptions", - "optional": true, - "type": { - "text": "TextDocumentShowOptions" - } - } - ] + "default": "false", + "fieldName": "hasMultipleRepositories" }, { - "kind": "method", - "name": "onCompareWorking", + "name": "source", + "type": { + "text": "Source | undefined" + }, + "fieldName": "source" + }, + { + "name": "expandable", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expandable" + }, + { + "name": "icons", + "readonly": true, + "fieldName": "icons" + } + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + }, + "tagName": "gl-repo-button-group", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlRepoButtonGroup", + "declaration": { + "name": "GlRepoButtonGroup", + "module": "src/webviews/apps/shared/components/repo-button-group.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-repo-button-group", + "declaration": { + "name": "GlRepoButtonGroup", + "module": "src/webviews/apps/shared/components/repo-button-group.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/signal-utils.ts", + "declarations": [ + { + "kind": "function", + "name": "renderAsyncComputed", + "return": { + "type": { + "text": "R | undefined" + } + }, + "parameters": [ + { + "name": "v", + "type": { + "text": "AsyncComputed" + } + }, + { + "name": "{\n\t\tinitial,\n\t\tpending,\n\t\tcomplete,\n\t\terror,\n\t}", + "type": { + "text": "{\n\t\tinitial?: () => R;\n\t\tpending?: () => R;\n\t\tcomplete?: (value: T | undefined) => R;\n\t\terror?: (error: unknown) => R;\n\t}" + } + } + ] + }, + { + "kind": "class", + "description": "", + "name": "AsyncComputedState", + "members": [ + { + "kind": "field", + "name": "_debounce", + "type": { + "text": "number" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ] + "default": "500" + }, + { + "kind": "field", + "name": "_invalidate", + "privacy": "private" + }, + { + "kind": "field", + "name": "_computed", + "type": { + "text": "AsyncComputed | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_state", + "privacy": "private" + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "T | undefined" + }, + "readonly": true + }, + { + "kind": "field", + "name": "computed", + "type": { + "text": "AsyncComputed" + }, + "readonly": true }, { "kind": "method", - "name": "onOpenFile", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ] + "name": "_runCore", + "privacy": "private" + }, + { + "kind": "field", + "name": "_runDebounced", + "type": { + "text": "Deferrable<() => void> | undefined" + }, + "privacy": "private" }, { "kind": "method", - "name": "onTreeItemChecked", + "name": "_run", "privacy": "protected", "return": { "type": { @@ -14648,21 +15675,14 @@ }, "parameters": [ { - "name": "e", - "type": { - "text": "CustomEvent" - } + "name": "immediate", + "default": "false" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "onTreeItemSelected", - "privacy": "protected", + "name": "run", "return": { "type": { "text": "void" @@ -14670,745 +15690,467 @@ }, "parameters": [ { - "name": "e", - "type": { - "text": "CustomEvent" - } + "name": "force", + "default": "false" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "onApplyPatch", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "optional": true, - "type": { - "text": "MouseEvent | KeyboardEvent" - } - }, - { - "name": "target", - "default": "'current'", - "type": { - "text": "'current' | 'branch' | 'worktree'" - } + "name": "invalidate", + "return": { + "type": { + "text": "void" } - ] + } + } + ] + }, + { + "kind": "function", + "name": "signalState", + "parameters": [ + { + "name": "initialValue", + "optional": true, + "type": { + "text": "T" + } }, { - "kind": "method", - "name": "onArchiveDraft", - "privacy": "private", - "parameters": [ - { - "name": "reason", - "type": { - "text": "DraftReasonEventDetail['reason']" - } - } - ] + "name": "options", + "optional": true, + "type": { + "text": "{ afterChange?: (target: any, value: T) => void }" + } + } + ] + }, + { + "kind": "function", + "name": "signalObjectState", + "parameters": [ + { + "name": "initialValue", + "optional": true, + "type": { + "text": "T" + } }, { - "kind": "method", - "name": "onSelectApplyOption", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent<{ target: MenuItem }>" - } - } - ] + "name": "options", + "optional": true, + "type": { + "text": "{ afterChange?: (target: any, value: T) => void }" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "renderAsyncComputed", + "declaration": { + "name": "renderAsyncComputed", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "js", + "name": "AsyncComputedState", + "declaration": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "js", + "name": "signalState", + "declaration": { + "name": "signalState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "js", + "name": "signalObjectState", + "declaration": { + "name": "signalObjectState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/skeleton-loader.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "SkeletonLoader", + "members": [ + { + "kind": "field", + "name": "lines", + "type": { + "text": "number" + }, + "default": "1", + "attribute": "lines" + } + ], + "attributes": [ + { + "name": "lines", + "type": { + "text": "number" + }, + "default": "1", + "fieldName": "lines" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "skeleton-loader", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "SkeletonLoader", + "declaration": { + "name": "SkeletonLoader", + "module": "src/webviews/apps/shared/components/skeleton-loader.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "skeleton-loader", + "declaration": { + "name": "SkeletonLoader", + "module": "src/webviews/apps/shared/components/skeleton-loader.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/snow.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlSnow", + "members": [ + { + "kind": "field", + "name": "snowing", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "snowing", + "reflects": true }, { - "kind": "method", - "name": "onChangePatchBase", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "optional": true, - "type": { - "text": "MouseEvent | KeyboardEvent" - } - } - ] + "kind": "field", + "name": "_canvas", + "type": { + "text": "HTMLCanvasElement | undefined" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onSelectPatchRepo", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "optional": true, - "type": { - "text": "MouseEvent | KeyboardEvent" - } - } - ] + "kind": "field", + "name": "_ctx", + "type": { + "text": "CanvasRenderingContext2D | undefined" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onShowInGraph", + "kind": "field", + "name": "_snowflakes", + "type": { + "text": "Snowflake[]" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "optional": true, - "type": { - "text": "MouseEvent | KeyboardEvent" - } - } - ] + "default": "[]" }, { - "kind": "method", - "name": "onCopyCloudLink", + "kind": "field", + "name": "_animationFrame", + "type": { + "text": "number | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_resizeObserver", + "type": { + "text": "ResizeObserver | undefined" + }, "privacy": "private" }, { "kind": "method", - "name": "onShareLocalPatch", + "name": "renderToggle", "privacy": "private" }, { "kind": "method", - "name": "draftPatchToTreeModel", + "name": "onToggle", + "privacy": "private", "return": { "type": { - "text": "TreeModel" + "text": "void" } }, "parameters": [ { - "name": "patch", - "type": { - "text": "NonNullable[0]" - } - }, - { - "name": "isTree", - "default": "false" - }, - { - "name": "compact", - "default": "true" - }, - { - "name": "options", - "optional": true, + "name": "snowing", "type": { - "text": "Partial" + "text": "boolean" } } ] }, { "kind": "method", - "name": "getFileActions", - "privacy": "protected", + "name": "updateCanvasSize", + "privacy": "private", "return": { "type": { - "text": "{ icon: string; label: string; action: string }[]" + "text": "void" } - }, - "parameters": [ - { - "name": "_file", - "type": { - "text": "DraftPatchFileChange" - } - }, - { - "name": "_options", - "optional": true, - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "renderLoading", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult" - } - }, - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "renderLayoutAction", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | typeof nothing" - } - }, - "parameters": [ - { - "name": "layout", - "type": { - "text": "string" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "renderTreeView", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult" - } - }, - "parameters": [ - { - "name": "treeModel", - "type": { - "text": "TreeModel[]" - } - }, - { - "name": "guides", - "default": "'none'", - "type": { - "text": "'none' | 'onHover' | 'always'" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "renderFiles", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel[]" - } - }, - "parameters": [ - { - "name": "files", - "type": { - "text": "GitFileChangeShape[]" - } - }, - { - "name": "isTree", - "default": "false" - }, - { - "name": "compact", - "default": "false" - }, - { - "name": "level", - "default": "2" - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "walkFileTree", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, - "parameters": [ - { - "name": "item", - "type": { - "text": "HierarchicalItem" - } - }, - { - "name": "options", - "default": "{ level: 1 }", - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "folderToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "getRepoActions", - "privacy": "protected", - "return": { - "type": { - "text": "TreeItemAction[]" - } - }, - "parameters": [ - { - "name": "_name", - "type": { - "text": "string" - } - }, - { - "name": "_path", - "type": { - "text": "string" - } - }, - { - "name": "_options", - "optional": true, - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "emptyTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" } }, { "kind": "method", - "name": "repoToTreeModel", - "privacy": "protected", + "name": "clear", + "privacy": "private", "return": { "type": { - "text": "TreeModel" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "path", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - }, - { - "name": "description", - "optional": true, - "type": { - "text": "string" - } + "text": "void" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" } }, { "kind": "method", - "name": "fileToTreeModel", - "privacy": "protected", + "name": "createSnowflakes", + "privacy": "private", "return": { "type": { - "text": "TreeModel" - } - }, - "parameters": [ - { - "name": "file", - "type": { - "text": "GitFileChangeShape" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - }, - { - "name": "flat", - "default": "false" - }, - { - "name": "glue", - "default": "'/'" + "text": "void" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" } }, { "kind": "method", - "name": "emit", + "name": "updateAnimation", + "privacy": "private", "return": { "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } + "text": "void" } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" } } ], "attributes": [ { - "name": "state", - "type": { - "text": "State" - }, - "fieldName": "state" - }, - { - "name": "explain", + "name": "snowing", "type": { - "text": "ExplainState | undefined" + "text": "boolean" }, - "fieldName": "explain" + "default": "false", + "fieldName": "snowing" } ], "superclass": { - "name": "GlTreeBase", - "module": "/src/webviews/apps/plus/patchDetails/components/gl-tree-base" + "name": "LitElement", + "package": "lit" }, - "tagName": "gl-draft-details", + "tagName": "gl-snow", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlDraftDetails", + "name": "GlSnow", "declaration": { - "name": "GlDraftDetails", - "module": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts" + "name": "GlSnow", + "module": "src/webviews/apps/shared/components/snow.ts" } }, { "kind": "custom-element-definition", - "name": "gl-draft-details", + "name": "gl-snow", "declaration": { - "name": "GlDraftDetails", - "module": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts" + "name": "GlSnow", + "module": "src/webviews/apps/shared/components/snow.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts", + "path": "src/webviews/apps/shared/components/webview-pane.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlPatchCreate", + "name": "WebviewPane", "members": [ { "kind": "field", - "name": "state", - "type": { - "text": "Serialized | undefined" - }, - "attribute": "state" - }, - { - "kind": "field", - "name": "review", + "name": "collapsable", "type": { "text": "boolean" }, "default": "false", - "attribute": "review" - }, - { - "kind": "field", - "name": "generate", - "type": { - "text": "GenerateState | undefined" - }, - "attribute": "generate" + "attribute": "collapsable", + "reflects": true }, { "kind": "field", - "name": "generateBusy", + "name": "expanded", "type": { "text": "boolean" }, - "default": "false" + "default": "false", + "attribute": "expanded", + "reflects": true }, { "kind": "field", - "name": "creationBusy", + "name": "loading", "type": { "text": "boolean" }, - "default": "false" - }, - { - "kind": "field", - "name": "titleInput", - "type": { - "text": "HTMLInputElement" - } + "default": "false", + "attribute": "loading", + "reflects": true }, { - "kind": "field", - "name": "descInput", - "type": { - "text": "HTMLInputElement" - } + "kind": "method", + "name": "renderTitle", + "privacy": "private" }, { - "kind": "field", - "name": "generateAiButton", - "type": { - "text": "HTMLElement" - } - }, + "kind": "method", + "name": "toggleExpanded", + "privacy": "private" + } + ], + "events": [ { - "kind": "field", - "name": "validityMessage", + "name": "expanded-change", "type": { - "text": "string | undefined" + "text": "CustomEvent" } - }, - { - "kind": "field", - "name": "create", - "type": { - "text": "NonNullable" - }, - "readonly": true - }, - { - "kind": "field", - "name": "createChanges", - "type": { - "text": "Change[]" - }, - "readonly": true - }, - { - "kind": "field", - "name": "createEntries", - "type": { - "text": "[string, Change][]" - }, - "readonly": true - }, + } + ], + "attributes": [ { - "kind": "field", - "name": "hasWipChanges", + "name": "collapsable", "type": { "text": "boolean" }, - "readonly": true - }, - { - "kind": "field", - "name": "selectedChanges", - "type": { - "text": "[string, Change][]" - }, - "readonly": true + "default": "false", + "fieldName": "collapsable" }, { - "kind": "field", - "name": "canSubmit", + "name": "expanded", "type": { "text": "boolean" }, - "readonly": true - }, - { - "kind": "field", - "name": "fileLayout", - "type": { - "text": "ViewFilesLayout" - }, - "readonly": true + "default": "false", + "fieldName": "expanded" }, { - "kind": "field", - "name": "isCompact", + "name": "loading", "type": { "text": "boolean" }, - "readonly": true - }, - { - "kind": "field", - "name": "filesModified", - "type": { - "text": "number" - }, - "readonly": true - }, - { - "kind": "field", - "name": "draftVisibility", - "type": { - "text": "DraftVisibility" - }, - "readonly": true - }, - { - "kind": "method", - "name": "renderUserSelection", - "privacy": "private", - "parameters": [ - { - "name": "userSelection", - "type": { - "text": "DraftUserSelection" - } - } - ] - }, - { - "kind": "method", - "name": "renderUserSelectionList", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderForm", - "privacy": "private" - }, + "default": "false", + "fieldName": "loading" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "webview-pane", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "WebviewPane", + "declaration": { + "name": "WebviewPane", + "module": "src/webviews/apps/shared/components/webview-pane.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "webview-pane", + "declaration": { + "name": "WebviewPane", + "module": "src/webviews/apps/shared/components/webview-pane.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/contexts/ipc.ts", + "declarations": [ + { + "kind": "variable", + "name": "ipcContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "ipcContext", + "declaration": { + "name": "ipcContext", + "module": "src/webviews/apps/shared/contexts/ipc.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/contexts/logger.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "LoggerContext", + "members": [ { - "kind": "method", - "name": "renderChangedFiles", - "privacy": "private" + "kind": "field", + "name": "scope", + "type": { + "text": "LogScope" + }, + "privacy": "private", + "readonly": true }, { "kind": "method", - "name": "onTreeItemChecked", - "privacy": "protected", + "name": "log", "return": { "type": { "text": "void" @@ -15416,2209 +16158,2297 @@ }, "parameters": [ { - "name": "e", + "name": "messageOrScope", "type": { - "text": "CustomEvent" + "text": "string | LogScope | undefined" } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } - }, - { - "kind": "method", - "name": "onTreeItemSelected", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ + }, { - "name": "e", + "name": "optionalParams", "type": { - "text": "CustomEvent" + "text": "any[]" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] + } + ] + }, + { + "kind": "variable", + "name": "loggerContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "LoggerContext", + "declaration": { + "name": "LoggerContext", + "module": "src/webviews/apps/shared/contexts/logger.ts" + } + }, + { + "kind": "js", + "name": "loggerContext", + "declaration": { + "name": "loggerContext", + "module": "src/webviews/apps/shared/contexts/logger.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/contexts/promos.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "PromosContext", + "members": [ + { + "kind": "field", + "name": "ipc", + "type": { + "text": "HostIpc" + }, + "privacy": "private", + "readonly": true, + "default": "ipc" }, { - "kind": "method", - "name": "renderTreeViewWithModel", - "privacy": "private" + "kind": "field", + "name": "disposables", + "type": { + "text": "Disposable[]" + }, + "privacy": "private", + "readonly": true, + "default": "[]" }, { - "kind": "method", - "name": "getTreeForChange", + "kind": "field", + "name": "_promos", "privacy": "private", + "default": "new Map<`${PromoPlans | undefined}|${PromoLocation | undefined}`, Promise>()" + }, + { + "kind": "method", + "name": "getApplicablePromo", "return": { "type": { - "text": "TreeModel[] | undefined" + "text": "Promise" } }, "parameters": [ { - "name": "change", + "name": "plan", + "optional": true, "type": { - "text": "Change" + "text": "PromoPlans" } }, { - "name": "isMulti", - "default": "false" - }, - { - "name": "isTree", - "default": "false" - }, - { - "name": "compact", - "default": "true" - } - ] - }, - { - "kind": "method", - "name": "isTree", - "privacy": "private", - "parameters": [ - { - "name": "count", + "name": "location", + "optional": true, "type": { - "text": "number" + "text": "PromoLocation" } } ] }, { "kind": "method", - "name": "createPatch", - "privacy": "private" - }, + "name": "dispose", + "return": { + "type": { + "text": "void" + } + } + } + ] + }, + { + "kind": "variable", + "name": "promosContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "PromosContext", + "declaration": { + "name": "PromosContext", + "module": "src/webviews/apps/shared/contexts/promos.ts" + } + }, + { + "kind": "js", + "name": "promosContext", + "declaration": { + "name": "promosContext", + "module": "src/webviews/apps/shared/contexts/promos.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/contexts/telemetry.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "TelemetryContext", + "members": [ { - "kind": "method", - "name": "onCreateAll", + "kind": "field", + "name": "ipc", + "type": { + "text": "HostIpc" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "Event" - } - } - ] + "readonly": true, + "default": "ipc" }, { - "kind": "method", - "name": "onSelectCreateOption", + "kind": "field", + "name": "disposables", + "type": { + "text": "Disposable[]" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "CustomEvent<{ target: MenuItem }>" - } - } - ] + "readonly": true, + "default": "[]" }, { "kind": "method", - "name": "getChangeForRepo", - "privacy": "private", + "name": "sendEvent", "return": { "type": { - "text": "Change | undefined" + "text": "void" } }, "parameters": [ { - "name": "repoUri", + "name": "detail", "type": { - "text": "string" + "text": "TelemetrySendEventParams" } } ] }, { "kind": "method", - "name": "onTitleInput", - "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "InputEvent" - } + "name": "dispose", + "return": { + "type": { + "text": "void" } - ] + } + } + ] + }, + { + "kind": "variable", + "name": "telemetryContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "TelemetryContext", + "declaration": { + "name": "TelemetryContext", + "module": "src/webviews/apps/shared/contexts/telemetry.ts" + } + }, + { + "kind": "js", + "name": "telemetryContext", + "declaration": { + "name": "telemetryContext", + "module": "src/webviews/apps/shared/contexts/telemetry.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/app.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "ComposerApp", + "members": [ + { + "kind": "field", + "name": "state", + "type": { + "text": "State" + } }, { "kind": "field", - "name": "onDebounceTitleInput", + "name": "_ipc", + "type": { + "text": "HostIpc" + }, "privacy": "private" }, { - "kind": "method", - "name": "onDescriptionInput", + "kind": "field", + "name": "history", + "type": { + "text": "ComposerHistory" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "InputEvent" - } - } - ] + "default": "{ resetState: null, undoStack: [], redoStack: [], }" }, { "kind": "field", - "name": "onDebounceDescriptionInput", + "name": "commitMessageDebounceTimer", + "type": { + "text": "number | undefined" + }, "privacy": "private" }, { - "kind": "method", - "name": "onInviteUsers", + "kind": "field", + "name": "commitMessageBeingEdited", + "type": { + "text": "string | null" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "Event" - } - } - ] + "default": "null" }, { - "kind": "method", - "name": "onChangeSelectionRole", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "MouseEvent" - } - }, - { - "name": "selection", - "type": { - "text": "DraftUserSelection" - } - }, - { - "name": "role", - "type": { - "text": "CreatePatchUpdateSelectionEventDetail['role']" - } - } - ] + "kind": "field", + "name": "commitsPanel", + "type": { + "text": "CommitsPanel" + } }, { - "kind": "method", - "name": "onVisibilityChange", - "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "Event" - } - } - ] + "kind": "field", + "name": "onboarding", + "type": { + "text": "Driver | undefined" + }, + "privacy": "private" }, { - "kind": "method", - "name": "onGenerateTitleClick", + "kind": "field", + "name": "selectedCommitId", + "type": { + "text": "string | null" + }, "privacy": "private", - "parameters": [ - { - "name": "_e", - "type": { - "text": "Event" - } - } - ] + "default": "null" }, { - "kind": "method", - "name": "fireMetadataUpdate", - "privacy": "private" + "kind": "field", + "name": "selectedUnassignedSection", + "type": { + "text": "'staged' | 'unstaged' | 'unassigned' | null" + }, + "privacy": "private", + "default": "null" }, { - "kind": "method", - "name": "onTreeItemActionClicked", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "selectedCommitIds", + "type": { + "text": "Set" }, - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + "privacy": "private", + "default": "new Set()" }, { - "kind": "method", - "name": "onOpenFile", + "kind": "field", + "name": "selectedHunkId", + "type": { + "text": "string | null" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ] + "default": "null" }, { - "kind": "method", - "name": "onStageFile", + "kind": "field", + "name": "selectedHunkIds", + "type": { + "text": "Set" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } - } - ] + "default": "new Set()" }, { - "kind": "method", - "name": "onUnstageFile", + "kind": "field", + "name": "customInstructions", + "type": { + "text": "string" + }, "privacy": "private", - "parameters": [ - { - "name": "e", - "type": { - "text": "CustomEvent" - } + "default": "''" + }, + { + "kind": "field", + "name": "compositionSummarySelected", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "compositionFeedback", + "type": { + "text": "'helpful' | 'unhelpful' | null" + }, + "privacy": "private", + "default": "null" + }, + { + "kind": "field", + "name": "compositionSessionId", + "type": { + "text": "string | null" + }, + "privacy": "private", + "default": "null" + }, + { + "kind": "field", + "name": "currentDropTarget", + "type": { + "text": "HTMLElement | null" + }, + "privacy": "private", + "default": "null" + }, + { + "kind": "field", + "name": "lastSelectedHunkId", + "type": { + "text": "string | null" + }, + "privacy": "private", + "default": "null" + }, + { + "kind": "field", + "name": "showCommitsGeneratedModal", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "onboardingStepNumber", + "type": { + "text": "number" + }, + "privacy": "private", + "default": "0" + }, + { + "kind": "field", + "name": "hunksSortable", + "type": { + "text": "Sortable | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "isDragging", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "lastMouseEvent", + "type": { + "text": "MouseEvent | undefined" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "handleForcedUpdate", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeSortable", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeHunksSortable", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeAllDropZones", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeCommitDropZones", + "privacy": "private" + }, + { + "kind": "method", + "name": "createDataSnapshot", + "privacy": "private", + "return": { + "type": { + "text": "ComposerDataSnapshot" } - ] + } }, { "kind": "method", - "name": "onShowInGraph", + "name": "applyDataSnapshot", "privacy": "private", "parameters": [ { - "name": "_e", + "name": "snapshot", "type": { - "text": "CustomEvent" + "text": "ComposerDataSnapshot" } } ] }, { "kind": "method", - "name": "onCancel", + "name": "saveToHistory", "privacy": "private" }, { "kind": "method", - "name": "getFileActions", - "privacy": "protected", + "name": "initializeResetStateIfNeeded", + "privacy": "private" + }, + { + "kind": "method", + "name": "resetHistory", + "privacy": "private" + }, + { + "kind": "method", + "name": "canUndo", + "privacy": "private", "return": { "type": { - "text": "{ icon: string; label: string; action: string }[]" - } - }, - "parameters": [ - { - "name": "file", - "type": { - "text": "GitFileChangeShape" - } - }, - { - "name": "_options", - "optional": true, - "type": { - "text": "Partial" - } + "text": "boolean" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" } }, { "kind": "method", - "name": "getRepoActions", - "privacy": "protected", + "name": "canRedo", + "privacy": "private", "return": { "type": { - "text": "{ icon: string; label: string; action: string }[]" + "text": "boolean" } - }, + } + }, + { + "kind": "method", + "name": "undo", + "privacy": "private" + }, + { + "kind": "method", + "name": "redo", + "privacy": "private" + }, + { + "kind": "method", + "name": "reset", + "privacy": "private" + }, + { + "kind": "method", + "name": "reorderCommits", + "privacy": "private", "parameters": [ { - "name": "_name", + "name": "oldIndex", "type": { - "text": "string" + "text": "number" } }, { - "name": "_path", + "name": "newIndex", "type": { - "text": "string" + "text": "number" } - }, + } + ] + }, + { + "kind": "method", + "name": "handleHunkDragStart", + "privacy": "private", + "parameters": [ { - "name": "_options", - "optional": true, + "name": "hunkIds", "type": { - "text": "Partial" + "text": "string[]" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "renderLoading", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult" - } - }, - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + "name": "handleHunkDragEnd", + "privacy": "private" }, { "kind": "method", - "name": "renderLayoutAction", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | typeof nothing" - } - }, + "name": "initializeDragTracking", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleHunkMove", + "privacy": "private", "parameters": [ { - "name": "layout", + "name": "hunkId", + "type": { + "text": "string" + } + }, + { + "name": "targetCommitId", "type": { "text": "string" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "renderTreeView", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult" - } - }, + "name": "createNewCommitWithHunks", + "privacy": "private", "parameters": [ { - "name": "treeModel", - "type": { - "text": "TreeModel[]" - } - }, - { - "name": "guides", - "default": "'none'", + "name": "hunkIds", "type": { - "text": "'none' | 'onHover' | 'always'" + "text": "string[]" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "renderFiles", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel[]" - } - }, + "name": "unassignHunks", + "privacy": "private", "parameters": [ { - "name": "files", + "name": "hunkIds", "type": { - "text": "GitFileChangeShape[]" + "text": "string[]" } - }, - { - "name": "isTree", - "default": "false" - }, - { - "name": "compact", - "default": "false" - }, - { - "name": "level", - "default": "2" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "walkFileTree", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "moveHunksToCommit", + "privacy": "private", "parameters": [ { - "name": "item", + "name": "hunkIds", "type": { - "text": "HierarchicalItem" + "text": "string[]" } }, { - "name": "options", - "default": "{ level: 1 }", + "name": "targetCommitId", "type": { - "text": "Partial" + "text": "string" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "folderToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "moveHunkToCommit", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "hunkId", "type": { "text": "string" } }, { - "name": "options", - "optional": true, + "name": "targetCommitId", "type": { - "text": "Partial" + "text": "string" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "emptyTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "createNewCommitWithHunk", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "hunkId", "type": { "text": "string" } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "repoToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "selectHunk", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "hunkId", "type": { "text": "string" } }, { - "name": "path", + "name": "shiftKey", + "default": "false" + } + ] + }, + { + "kind": "method", + "name": "selectCommit", + "privacy": "private", + "parameters": [ + { + "name": "commitId", "type": { "text": "string" } }, { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - }, + "name": "shiftKey", + "default": "false" + } + ] + }, + { + "kind": "method", + "name": "selectUnassignedSection", + "privacy": "private", + "parameters": [ { - "name": "description", - "optional": true, + "name": "section", "type": { - "text": "string" + "text": "'staged' | 'unstaged' | 'unassigned'" } } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "fileToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "updateCommitMessage", + "privacy": "private", "parameters": [ { - "name": "file", + "name": "commitId", "type": { - "text": "GitFileChangeShape" + "text": "string" } }, { - "name": "options", - "optional": true, + "name": "message", "type": { - "text": "Partial" + "text": "string" } - }, - { - "name": "flat", - "default": "false" - }, - { - "name": "glue", - "default": "'/'" } - ], - "inheritedFrom": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" - } + ] }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "name": "toggleCommitMessageExpanded", + "privacy": "private" + }, + { + "kind": "method", + "name": "toggleAiExplanationExpanded", + "privacy": "private" + }, + { + "kind": "method", + "name": "toggleFilesChangedExpanded", + "privacy": "private" + }, + { + "kind": "field", + "name": "autoScrollActive", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "autoScrollTimer", + "type": { + "text": "number | undefined" }, + "privacy": "private" + }, + { + "kind": "field", + "name": "mouseTracker", + "privacy": "private" + }, + { + "kind": "method", + "name": "startAutoScroll", + "privacy": "private" + }, + { + "kind": "method", + "name": "stopAutoScroll", + "privacy": "private" + }, + { + "kind": "method", + "name": "performAutoScroll", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, + "name": "mouseY", "type": { - "text": "Omit>, 'detail'>" + "text": "number" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ + ] + }, { - "name": "state", + "kind": "method", + "name": "closeModal", + "privacy": "private" + }, + { + "kind": "field", + "name": "hunksWithAssignments", "type": { - "text": "Serialized | undefined" + "text": "ComposerHunk[]" }, - "fieldName": "state" + "privacy": "private", + "readonly": true }, { - "name": "review", + "kind": "field", + "name": "aiEnabled", "type": { "text": "boolean" }, - "default": "false", - "fieldName": "review" + "privacy": "private", + "readonly": true }, { - "name": "generate", + "kind": "field", + "name": "aiDisabledReason", "type": { - "text": "GenerateState | undefined" + "text": "string | null" }, - "fieldName": "generate" - } - ], - "superclass": { - "name": "GlTreeBase", - "module": "/src/webviews/apps/plus/patchDetails/components/gl-tree-base" - }, - "tagName": "gl-patch-create", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlPatchCreate", - "declaration": { - "name": "GlPatchCreate", - "module": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-patch-create", - "declaration": { - "name": "GlPatchCreate", - "module": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlTreeBase", - "members": [ + "privacy": "private", + "readonly": true + }, { - "kind": "method", - "name": "onTreeItemActionClicked", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "canFinishAndCommit", + "type": { + "text": "boolean" }, - "parameters": [ - { - "name": "_e", - "type": { - "text": "CustomEvent" - } - } - ] + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onTreeItemChecked", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "isPreviewMode", + "type": { + "text": "boolean" }, - "parameters": [ - { - "name": "_e", - "type": { - "text": "CustomEvent" - } - } - ] + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onTreeItemSelected", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "kind": "field", + "name": "canCombineCommits", + "type": { + "text": "boolean" }, - "parameters": [ - { - "name": "_e", - "type": { - "text": "CustomEvent" - } - } - ] + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "showHistoryButtons", + "type": { + "text": "boolean" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "canMoveHunks", + "type": { + "text": "boolean" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "isReadyToFinishAndCommit", + "type": { + "text": "boolean" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "canGenerateCommitsWithAI", + "type": { + "text": "boolean" + }, + "privacy": "private", + "readonly": true }, { "kind": "method", - "name": "renderLoading", - "privacy": "protected", + "name": "getEligibleHunksForAI", + "privacy": "private", "return": { "type": { - "text": "TemplateResult" + "text": "typeof this.hunksWithAssignments" } } }, { - "kind": "method", - "name": "renderLayoutAction", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | typeof nothing" - } + "kind": "field", + "name": "canEditCommitMessages", + "type": { + "text": "boolean" }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "canGenerateCommitMessages", + "type": { + "text": "boolean" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "finishAndCommit", + "privacy": "private" + }, + { + "kind": "method", + "name": "closeComposer", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCloseSafetyError", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleReloadComposer", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCloseLoadingError", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCloseAIOperationError", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCancelGenerateCommits", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCancelGenerateCommitMessage", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderLoadingDialogs", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderLoadingDialog", + "privacy": "private", "parameters": [ { - "name": "layout", + "name": "title", "type": { "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "renderTreeView", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult" - } - }, - "parameters": [ + }, { - "name": "treeModel", + "name": "bodyText", "type": { - "text": "TreeModel[]" + "text": "string" } }, { - "name": "guides", - "default": "'none'", + "name": "onCancel", + "optional": true, "type": { - "text": "'none' | 'onHover' | 'always'" + "text": "() => void" } } ] }, { "kind": "method", - "name": "renderFiles", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel[]" - } - }, + "name": "handleGenerateCommitsWithAI", + "privacy": "private", "parameters": [ { - "name": "files", + "name": "e", "type": { - "text": "GitFileChangeShape[]" + "text": "CustomEvent" } - }, - { - "name": "isTree", - "default": "false" - }, - { - "name": "compact", - "default": "false" - }, - { - "name": "level", - "default": "2" } ] }, { "kind": "method", - "name": "walkFileTree", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "handleAddHunksToCommit", + "privacy": "private", "parameters": [ { - "name": "item", - "type": { - "text": "HierarchicalItem" - } - }, - { - "name": "options", - "default": "{ level: 1 }", + "name": "e", "type": { - "text": "Partial" + "text": "CustomEvent" } } ] }, { "kind": "method", - "name": "folderToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "handleCloseComposer", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleSelectAIModel", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleSelectCompositionSummary", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCompositionFeedbackHelpful", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "Partial" + "text": "CustomEvent" } } ] }, { "kind": "method", - "name": "getRepoActions", - "privacy": "protected", - "return": { - "type": { - "text": "TreeItemAction[]" - } - }, + "name": "handleCompositionFeedbackUnhelpful", + "privacy": "private", "parameters": [ { - "name": "_name", - "type": { - "text": "string" - } - }, - { - "name": "_path", - "type": { - "text": "string" - } - }, - { - "name": "_options", - "optional": true, + "name": "e", "type": { - "text": "Partial" + "text": "CustomEvent" } } ] }, { "kind": "method", - "name": "emptyTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "handleCustomInstructionsChange", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "Partial" + "text": "CustomEvent" } } ] }, { - "kind": "method", - "name": "repoToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } + "kind": "field", + "name": "detailsPanel", + "type": { + "text": "DetailsPanel" }, + "privacy": "private" + }, + { + "kind": "method", + "name": "handleFocusCommitMessage", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "string" - } - }, - { - "name": "path", - "type": { - "text": "string" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Partial" - } - }, - { - "name": "description", - "optional": true, + "name": "e", "type": { - "text": "string" + "text": "CustomEvent<{ commitId: string; checkValidity: boolean }>" } } ] }, { "kind": "method", - "name": "getFileActions", - "privacy": "protected", - "return": { - "type": { - "text": "TreeItemAction[]" - } - }, + "name": "generateCommitsWithAI", + "privacy": "private", "parameters": [ { - "name": "_file", - "type": { - "text": "GitFileChangeShape" - } - }, - { - "name": "_options", - "optional": true, + "name": "customInstructions", + "default": "''", "type": { - "text": "Partial" + "text": "string" } } ] }, { "kind": "method", - "name": "fileToTreeModel", - "privacy": "protected", - "return": { - "type": { - "text": "TreeModel" - } - }, + "name": "generateCommitMessage", + "privacy": "private", "parameters": [ { - "name": "file", - "type": { - "text": "GitFileChangeShape" - } - }, - { - "name": "options", - "optional": true, + "name": "commitId", "type": { - "text": "Partial" + "text": "string" } - }, - { - "name": "flat", - "default": "false" - }, - { - "name": "glue", - "default": "'/'" } ] }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, + "name": "combineSelectedCommits", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderWorkingDirectoryWarning", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderActions", + "privacy": "private" + }, + { + "kind": "method", + "name": "onRepositorySelectorClicked", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "Omit>, 'detail'>" + "text": "CustomEvent" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + ] + }, + { + "kind": "field", + "name": "onboardingSteps", + "type": { + "text": "KeyedDriveStep[]" + }, + "privacy": "private", + "default": "[ { key: `${onboardingKey}-welcome`, popover: { title: 'Welcome to Commit Composer', description: `Compose your changes into organized, meaningful commits before committing them. Use AI to automatically structure your work into draft commits with clear messages and descriptions, or commit manually.

Learn More`, }, }, { key: `${onboardingKey}-compose`, element: () => this.commitsPanel.autoComposeSection!, popover: { title: 'Auto Compose Commits with AI', description: 'Allow AI to organize your working changes into well-formed commits with clear messages and descriptions that help reviewers.

You can change which model to use and add custom instructions.', }, }, { key: `${onboardingKey}-changes`, element: () => this.commitsPanel.changesSection, popover: { title: 'Review and Compose Working Changes', description: \"Draft Commits represent what will be committed when you're finished. You can inspect changes to add commit messages and review diffs.

Coming soon: add draft commits and easily move hunks and lines between them.\", }, }, { key: `${onboardingKey}-finish`, element: () => this.commitsPanel.finishSection, popover: { title: 'Finish & Commit', description: \"Draft commits and messages will be committed when you're finished.\", }, }, ]" + }, + { + "kind": "method", + "name": "openOnboarding", + "privacy": "private" + }, + { + "kind": "method", + "name": "dismissOnboarding" + }, + { + "kind": "method", + "name": "advanceOnboardingStep" + }, + { + "kind": "method", + "name": "reduceOnboardingStep" } ], "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-composer-app", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlTreeBase", + "name": "ComposerApp", "declaration": { - "name": "GlTreeBase", - "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + "name": "ComposerApp", + "module": "src/webviews/apps/plus/composer/components/app.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-composer-app", + "declaration": { + "name": "ComposerApp", + "module": "src/webviews/apps/plus/composer/components/app.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts", + "path": "src/webviews/apps/plus/composer/components/commit-item.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlPatchDetailsApp", + "name": "CommitItem", "members": [ { "kind": "field", - "name": "state", + "name": "commitId", "type": { - "text": "State" + "text": "string" }, - "attribute": "state" + "attribute": "commitId" }, { "kind": "field", - "name": "explain", + "name": "message", "type": { - "text": "ExplainState | undefined" + "text": "string" }, - "attribute": "explain" + "attribute": "message" }, { "kind": "field", - "name": "generate", + "name": "fileCount", "type": { - "text": "GenerateState | undefined" + "text": "number" }, - "attribute": "generate" + "attribute": "fileCount" }, { "kind": "field", - "name": "app", + "name": "additions", "type": { - "text": "PatchDetailsApp | undefined" - } + "text": "number" + }, + "attribute": "additions" }, { "kind": "field", - "name": "wipChangesCount", + "name": "deletions", "type": { "text": "number" }, - "readonly": true + "attribute": "deletions" }, { "kind": "field", - "name": "wipChangeState", - "readonly": true + "name": "selected", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "selected" }, { "kind": "field", - "name": "mode", + "name": "multiSelected", "type": { - "text": "Mode" + "text": "boolean" }, - "readonly": true + "default": "false", + "attribute": "multiSelected" }, { "kind": "field", - "name": "indentPreference", + "name": "isPreviewMode", "type": { - "text": "number" + "text": "boolean" }, - "privacy": "private", - "default": "16" + "default": "false", + "attribute": "isPreviewMode" }, { - "kind": "method", - "name": "updateDocumentProperties", - "privacy": "private" + "kind": "field", + "name": "first", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "first" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "kind": "field", + "name": "last", + "type": { + "text": "boolean" }, + "default": "false", + "attribute": "last" + }, + { + "kind": "method", + "name": "handleClick", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, + "name": "e", "type": { - "text": "Omit>, 'detail'>" + "text": "MouseEvent | KeyboardEvent" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" + ] + } + ], + "events": [ + { + "name": "commit-selected", + "type": { + "text": "CustomEvent" } } ], "attributes": [ { - "name": "state", + "name": "commitId", "type": { - "text": "State" + "text": "string" }, - "fieldName": "state" + "fieldName": "commitId" }, { - "name": "explain", + "name": "message", "type": { - "text": "ExplainState | undefined" + "text": "string" }, - "fieldName": "explain" + "fieldName": "message" }, { - "name": "generate", + "name": "fileCount", "type": { - "text": "GenerateState | undefined" + "text": "number" }, - "fieldName": "generate" + "fieldName": "fileCount" + }, + { + "name": "additions", + "type": { + "text": "number" + }, + "fieldName": "additions" + }, + { + "name": "deletions", + "type": { + "text": "number" + }, + "fieldName": "deletions" + }, + { + "name": "selected", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "selected" + }, + { + "name": "multiSelected", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "multiSelected" + }, + { + "name": "isPreviewMode", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "isPreviewMode" + }, + { + "name": "first", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "first" + }, + { + "name": "last", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "last" } ], "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" + "name": "LitElement", + "package": "lit" }, - "tagName": "gl-patch-details-app", + "tagName": "gl-commit-item", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlPatchDetailsApp", + "name": "CommitItem", "declaration": { - "name": "GlPatchDetailsApp", - "module": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts" + "name": "CommitItem", + "module": "src/webviews/apps/plus/composer/components/commit-item.ts" } }, { "kind": "custom-element-definition", - "name": "gl-patch-details-app", + "name": "gl-commit-item", "declaration": { - "name": "GlPatchDetailsApp", - "module": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts" + "name": "CommitItem", + "module": "src/webviews/apps/plus/composer/components/commit-item.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/active-work.ts", + "path": "src/webviews/apps/plus/composer/components/commit-message.ts", "declarations": [ - { - "kind": "variable", - "name": "activeWorkTagName", - "type": { - "text": "string" - }, - "default": "'gl-active-work'" - }, { "kind": "class", "description": "", - "name": "GlActiveWork", + "name": "CommitMessage", "members": [ { "kind": "field", - "name": "_homeState", + "name": "shadowRootOptions", "type": { - "text": "State" + "text": "ShadowRootInit" }, - "privacy": "private" + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" }, { "kind": "field", - "name": "_activeOverviewState", + "name": "commitId", "type": { - "text": "ActiveOverviewState" + "text": "string | undefined" }, - "privacy": "private" + "attribute": "commit-id", + "reflects": true }, { "kind": "field", - "name": "repoCollapsed", + "name": "message", + "type": { + "text": "string | undefined" + }, + "attribute": "message" + }, + { + "kind": "field", + "name": "explanation", + "type": { + "text": "string | undefined" + }, + "attribute": "explanation" + }, + { + "kind": "field", + "name": "explanationLabel", + "type": { + "text": "string | undefined" + }, + "default": "'Auto-composition Summary:'", + "attribute": "explanation-label" + }, + { + "kind": "field", + "name": "placeholder", + "type": { + "text": "string" + }, + "default": "'Enter commit message...'", + "attribute": "placeholder" + }, + { + "kind": "field", + "name": "editable", "type": { "text": "boolean" }, - "privacy": "private", - "default": "true" + "default": "false", + "attribute": "editable", + "reflects": true }, { "kind": "field", - "name": "isPro", - "readonly": true + "name": "aiEnabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "ai-enabled", + "reflects": true + }, + { + "kind": "field", + "name": "aiDisabledReason", + "type": { + "text": "string | null" + }, + "default": "null", + "attribute": "aiDisabledReason" + }, + { + "kind": "field", + "name": "generating", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "generating", + "reflects": true + }, + { + "kind": "field", + "name": "focusableElement", + "type": { + "text": "HTMLTextAreaElement | HTMLParagraphElement" + } + }, + { + "kind": "field", + "name": "validityMessage", + "type": { + "text": "string | undefined" + } }, { "kind": "method", - "name": "renderLoader", + "name": "renderEditable", "privacy": "private" }, { "kind": "method", - "name": "renderPending", + "name": "renderHelpText", "privacy": "private" }, { "kind": "method", - "name": "renderComplete", + "name": "renderReadOnly", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderExplanation", + "privacy": "private" + }, + { + "kind": "method", + "name": "onGenerateCommitMessageClick", + "privacy": "private" + }, + { + "kind": "method", + "name": "onMessageInput", "privacy": "private", "parameters": [ { - "name": "overview", + "name": "event", "type": { - "text": "GetActiveOverviewResponse" + "text": "InputEvent" } - }, - { - "name": "isFetching", - "default": "false" } ] }, { "kind": "method", - "name": "renderRepoBranchCard", + "name": "disapatchMessageChange", "privacy": "private", "parameters": [ { - "name": "branch", - "type": { - "text": "GetOverviewBranch" - } - }, - { - "name": "repo", + "name": "message", "type": { "text": "string" } - }, - { - "name": "isFetching", - "type": { - "text": "boolean" - } } ] }, + { + "kind": "field", + "name": "dispatchMessageChangeDebounced" + }, { "kind": "method", - "name": "onRepositorySelectorClicked", - "privacy": "private", + "name": "focus", "parameters": [ { - "name": "e", + "name": "options", + "optional": true, "type": { - "text": "CustomEvent" + "text": "FocusOptions" } } ] - } - ], - "mixins": [ - { - "name": "SignalWatcher", - "package": "@lit-labs/signals" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlActiveBranchCard", - "members": [ - { - "kind": "method", - "name": "renderActionsMenu", - "privacy": "private" }, { "kind": "method", - "name": "renderBranchStateActions", - "privacy": "private" + "name": "checkValidity", + "parameters": [ + { + "name": "reportErrors", + "default": "false" + } + ] }, { "kind": "method", - "name": "renderBranchIndicator", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | undefined" + "name": "select", + "parameters": [ + { + "name": "checkValidity", + "default": "false" } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + ] + } + ], + "events": [ + { + "name": "generate-commit-message", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "getBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "message-change", + "type": { + "text": "CustomEvent" } - }, + } + ], + "attributes": [ { - "kind": "method", - "name": "getPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } + "name": "commit-id", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "commitId" }, { - "kind": "method", - "name": "getCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } + "name": "message", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "message" }, { - "kind": "method", - "name": "renderIssuesItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "explanation", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "explanation" }, { - "kind": "field", - "name": "_homeState", + "name": "explanation-label", "type": { - "text": "State" + "text": "string | undefined" }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "'Auto-composition Summary:'", + "fieldName": "explanationLabel" }, { - "kind": "field", - "name": "repo", + "name": "placeholder", "type": { "text": "string" }, - "attribute": "repo", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "'Enter commit message...'", + "fieldName": "placeholder" }, { - "kind": "field", - "name": "showUpgrade", + "name": "editable", "type": { "text": "boolean" }, "default": "false", - "attribute": "showUpgrade", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "editable" }, { - "kind": "field", - "name": "_branch", + "name": "ai-enabled", "type": { - "text": "GetOverviewBranch" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "aiEnabled" }, { - "kind": "field", - "name": "branch", + "name": "aiDisabledReason", "type": { - "text": "GetOverviewBranch" + "text": "string | null" }, - "attribute": "branch", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "fieldName": "aiDisabledReason" }, { - "kind": "field", - "name": "_autolinks", + "name": "generating", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "default": "false", + "fieldName": "generating" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-commit-message", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "CommitMessage", + "declaration": { + "name": "CommitMessage", + "module": "src/webviews/apps/plus/composer/components/commit-message.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-commit-message", + "declaration": { + "name": "CommitMessage", + "module": "src/webviews/apps/plus/composer/components/commit-message.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/commits-panel.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "CommitsPanel", + "members": [ { "kind": "field", - "name": "autolinks", + "name": "commits", "type": { - "text": "Awaited" + "text": "ComposerCommit[]" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "attribute": "commits" }, { "kind": "field", - "name": "_autolinksPromise", + "name": "hunks", "type": { - "text": "GetOverviewBranch['autolinks']" + "text": "ComposerHunk[]" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "attribute": "hunks" }, { "kind": "field", - "name": "autolinksPromise", + "name": "selectedCommitId", "type": { - "text": "GetOverviewBranch['autolinks']" + "text": "string | null" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "selectedCommitId" }, { "kind": "field", - "name": "_contributors", + "name": "selectedCommitIds", "type": { - "text": "Awaited" + "text": "Set" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "new Set()", + "attribute": "selectedCommitIds" }, { "kind": "field", - "name": "contributors", + "name": "selectedUnassignedSection", "type": { - "text": "Awaited" + "text": "string | null" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "selectedUnassignedSection" }, { "kind": "field", - "name": "_contributorsPromise", + "name": "canFinishAndCommit", "type": { - "text": "GetOverviewBranch['contributors']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "true", + "attribute": "canFinishAndCommit" }, { "kind": "field", - "name": "contributorsPromise", + "name": "generating", "type": { - "text": "GetOverviewBranch['contributors']" + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "generating" }, { "kind": "field", - "name": "_issues", + "name": "committing", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "committing" }, { "kind": "field", - "name": "issues", + "name": "aiEnabled", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "aiEnabled" }, { "kind": "field", - "name": "_issuesPromise", + "name": "aiDisabledReason", "type": { - "text": "GetOverviewBranch['issues']" + "text": "string | null" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "aiDisabledReason" }, { "kind": "field", - "name": "issuesPromise", + "name": "isPreviewMode", "type": { - "text": "GetOverviewBranch['issues']" + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "isPreviewMode" }, { "kind": "field", - "name": "_pr", + "name": "baseCommit", "type": { - "text": "Awaited" + "text": "ComposerBaseCommit | null" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "baseCommit" }, { "kind": "field", - "name": "pr", + "name": "repoName", "type": { - "text": "Awaited" + "text": "string | null" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "repoName" }, { "kind": "field", - "name": "_prPromise", + "name": "customInstructions", "type": { - "text": "GetOverviewBranch['pr']" + "text": "string" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "''", + "attribute": "customInstructions" }, { "kind": "field", - "name": "prPromise", + "name": "hasUsedAutoCompose", "type": { - "text": "GetOverviewBranch['pr']" + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "hasUsedAutoCompose" }, { "kind": "field", - "name": "_launchpadItem", + "name": "hasChanges", "type": { - "text": "Awaited>['launchpad']>" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "true", + "attribute": "hasChanges" }, { "kind": "field", - "name": "launchpadItem", + "name": "aiModel", "type": { - "text": "Awaited>['launchpad']>" + "text": "AIModel | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "undefined", + "attribute": "aiModel" }, { "kind": "field", - "name": "_launchpadItemPromise", + "name": "compositionSummarySelected", "type": { - "text": "NonNullable>['launchpad']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "compositionSummarySelected" }, { "kind": "field", - "name": "launchpadItemPromise", + "name": "compositionFeedback", "type": { - "text": "NonNullable>['launchpad']" + "text": "'helpful' | 'unhelpful' | null" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "compositionFeedback" }, { "kind": "field", - "name": "_mergeTarget", + "name": "compositionSessionId", "type": { - "text": "Awaited" + "text": "string | null" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "attribute": "compositionSessionId" }, { "kind": "field", - "name": "mergeTarget", + "name": "isReadyToCommit", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "isReadyToCommit" }, { "kind": "field", - "name": "_mergeTargetPromise", + "name": "changesSection", "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "HTMLElement" } }, { "kind": "field", - "name": "mergeTargetPromise", + "name": "autoComposeSection", "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "HTMLElement | undefined" } }, { "kind": "field", - "name": "_remote", + "name": "finishSection", "type": { - "text": "Awaited" - }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "HTMLElement" } }, { "kind": "field", - "name": "remote", + "name": "commitsSortable", "type": { - "text": "Awaited" + "text": "Sortable | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private" }, { "kind": "field", - "name": "_remotePromise", + "name": "isDraggingHunks", "type": { - "text": "GetOverviewBranch['remote']" + "text": "boolean" }, "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false" }, { "kind": "field", - "name": "remotePromise", + "name": "draggedHunkIds", "type": { - "text": "GetOverviewBranch['remote']" + "text": "string[]" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "default": "[]" }, { - "kind": "field", - "name": "_wip", - "type": { - "text": "Awaited" - }, + "kind": "method", + "name": "initializeSortable", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeDropZones", + "privacy": "private" + }, + { + "kind": "method", + "name": "initializeCommitDropZones", + "privacy": "private" + }, + { + "kind": "method", + "name": "setupNativeDropZone", "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "parameters": [ + { + "name": "element", + "type": { + "text": "HTMLElement" + } + }, + { + "name": "type", + "type": { + "text": "'new-commit' | 'unassign' | 'commit'" + } + } + ] }, { - "kind": "field", - "name": "wip", - "type": { - "text": "Awaited" - }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "kind": "method", + "name": "dispatchCommitReorder", + "privacy": "private", + "parameters": [ + { + "name": "oldIndex", + "type": { + "text": "number" + } + }, + { + "name": "newIndex", + "type": { + "text": "number" + } + } + ] }, { - "kind": "field", - "name": "_wipPromise", - "type": { - "text": "GetOverviewBranch['wip']" - }, + "kind": "method", + "name": "dispatchCreateNewCommit", "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "parameters": [ + { + "name": "hunkIds", + "type": { + "text": "string[]" + } + } + ] }, { - "kind": "field", - "name": "wipPromise", - "type": { - "text": "GetOverviewBranch['wip']" - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "kind": "method", + "name": "dispatchUnassignHunks", + "privacy": "private", + "parameters": [ + { + "name": "hunkIds", + "type": { + "text": "string[]" + } + } + ] }, { - "kind": "field", - "name": "busy", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "busy", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "kind": "method", + "name": "dispatchMoveHunksToCommit", + "privacy": "private", + "parameters": [ + { + "name": "hunkIds", + "type": { + "text": "string[]" + } + }, + { + "name": "targetCommitId", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "method", + "name": "handleHunkDragStart", + "privacy": "private", + "parameters": [ + { + "name": "event", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "addDropZoneHoverEffects", + "privacy": "private" + }, + { + "kind": "method", + "name": "removeDropZoneHoverEffects", + "privacy": "private" }, { "kind": "field", - "name": "expanded", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expanded", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "handleDragEnter", + "privacy": "private" }, { "kind": "field", - "name": "expandable", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expandable", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "handleDragLeave", + "privacy": "private" }, { "kind": "field", - "name": "eventController", + "name": "shouldShowUnassignZone", "type": { - "text": "AbortController | undefined" + "text": "boolean" }, "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "kind": "method", - "name": "onExpandableChanged", - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "readonly": true }, { "kind": "field", - "name": "branchRef", + "name": "shouldShowNewCommitZone", "type": { - "text": "BranchRef" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "isWorktree", + "name": "firstCommitWithoutMessage", "type": { - "text": "boolean" + "text": "ComposerCommit | null" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "cardIndicator", + "name": "shouldShowAddToDraftButton", "type": { - "text": "GlCard['indicator']" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "branchCardIndicator", + "name": "aiModelDisplayName", "type": { - "text": "GlCard['indicator']" + "text": "string" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true }, { "kind": "method", - "name": "attachFocusListener", - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "handleHunkDragEnd", + "privacy": "private" }, { - "kind": "field", - "name": "onFocus", + "kind": "method", + "name": "dispatchCommitSelect", "privacy": "private", - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "parameters": [ + { + "name": "commitId", + "type": { + "text": "string" + } + }, + { + "name": "e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } + } + ] }, { "kind": "method", - "name": "renderIssues", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" + "name": "dispatchUnassignedSelect", + "privacy": "private", + "parameters": [ + { + "name": "section", + "type": { + "text": "string" + } + }, + { + "name": "e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "renderWip", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "dispatchCombineCommits", + "privacy": "private" }, { "kind": "method", - "name": "renderAvatars", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "dispatchFinishAndCommit", + "privacy": "private" }, { "kind": "method", - "name": "renderTracking", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, + "name": "dispatchFocusCommitMessage", + "privacy": "private", "parameters": [ { - "name": "showWip", - "default": "false" + "name": "commitId", + "optional": true, + "type": { + "text": "string" + } } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "renderBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "dispatchGenerateCommitsWithAI", + "privacy": "private" }, { "kind": "method", - "name": "renderPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" + "name": "handleAddAllToDraftCommit", + "privacy": "private", + "parameters": [ + { + "name": "sectionKey", + "type": { + "text": "string" + } } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "renderCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "handleGenerateCommitMessageWithAI", + "privacy": "private" }, { "kind": "method", - "name": "createWebviewCommandLink", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } - }, + "name": "handleAIModelPickerClick", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCompositionSummaryClick", + "privacy": "private", "parameters": [ { - "name": "command", + "name": "e", "type": { - "text": "WebviewCommands | WebviewViewCommands | PlusCommands" + "text": "MouseEvent | KeyboardEvent" } - }, + } + ] + }, + { + "kind": "method", + "name": "handleCompositionFeedbackHelpful", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCompositionFeedbackUnhelpful", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCreateCommitsClick", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCancel", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleCustomInstructionsChange", + "privacy": "private", + "parameters": [ { - "name": "args", - "optional": true, + "name": "e", "type": { - "text": "T | any" + "text": "Event" } } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "createCommandLink", - "privacy": "protected", + "name": "getIncludeButtonText", + "privacy": "private", "return": { "type": { "text": "string" @@ -17626,3229 +18456,2422 @@ }, "parameters": [ { - "name": "command", - "type": { - "text": "GlCommands" - } - }, - { - "name": "args", - "optional": true, + "name": "sectionKey", "type": { - "text": "T | any" + "text": "string" } } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "renderTimestamp", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "renderUnassignedSection", + "privacy": "private" }, { "kind": "method", - "name": "renderBranchItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, + "name": "renderCompositionSummarySection", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderAutoComposeContainer", + "privacy": "private", "parameters": [ { - "name": "actionsSection", - "optional": true, - "type": { - "text": "TemplateResult | NothingType" - } + "name": "disabled", + "default": "false" } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + ] }, { "kind": "method", - "name": "renderBranchIcon", + "name": "renderFinishCommitSection", "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "parameters": [ + { + "name": "disabled", + "default": "false" + } + ] + } + ], + "events": [ + { + "name": "commit-reorder", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "renderPrItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "create-new-commit", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "renderLaunchpadItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "unassign-hunks", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "renderMergeTargetStatus", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "move-hunks-to-commit", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "toggleExpanded", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "expanded", - "default": "!this.expanded" - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "commit-select", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" + "name": "unassigned-select", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "combine-commits", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "finish-and-commit", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "focus-commit-message", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "generate-commits-with-ai", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "add-hunks-to-commit", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "generate-commit-message", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "select-ai-model", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "select-composition-summary", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "composition-feedback-helpful", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "composition-feedback-unhelpful", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "cancel-composer", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "custom-instructions-change", + "type": { + "text": "CustomEvent" } } ], - "superclass": { - "name": "GlBranchCardBase", - "module": "/src/webviews/apps/plus/home/components/branch-card" - }, - "tagName": "gl-active-branch-card", - "customElement": true, "attributes": [ { - "name": "repo", + "name": "commits", "type": { - "text": "string" + "text": "ComposerCommit[]" }, - "fieldName": "repo", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "fieldName": "commits" }, { - "name": "showUpgrade", + "name": "hunks", + "type": { + "text": "ComposerHunk[]" + }, + "default": "[]", + "fieldName": "hunks" + }, + { + "name": "selectedCommitId", + "type": { + "text": "string | null" + }, + "default": "null", + "fieldName": "selectedCommitId" + }, + { + "name": "selectedCommitIds", + "type": { + "text": "Set" + }, + "default": "new Set()", + "fieldName": "selectedCommitIds" + }, + { + "name": "selectedUnassignedSection", + "type": { + "text": "string | null" + }, + "default": "null", + "fieldName": "selectedUnassignedSection" + }, + { + "name": "canFinishAndCommit", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "canFinishAndCommit" + }, + { + "name": "generating", "type": { "text": "boolean" }, "default": "false", - "fieldName": "showUpgrade", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "generating" }, { - "name": "branch", + "name": "committing", "type": { - "text": "GetOverviewBranch" + "text": "boolean" }, - "fieldName": "branch", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "committing" }, { - "name": "busy", + "name": "aiEnabled", "type": { "text": "boolean" }, "default": "false", - "fieldName": "busy", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "aiEnabled" }, { - "name": "expanded", + "name": "aiDisabledReason", + "type": { + "text": "string | null" + }, + "default": "null", + "fieldName": "aiDisabledReason" + }, + { + "name": "isPreviewMode", "type": { "text": "boolean" }, "default": "false", - "fieldName": "expanded", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "isPreviewMode" }, { - "name": "expandable", + "name": "baseCommit", + "type": { + "text": "ComposerBaseCommit | null" + }, + "default": "null", + "fieldName": "baseCommit" + }, + { + "name": "repoName", + "type": { + "text": "string | null" + }, + "default": "null", + "fieldName": "repoName" + }, + { + "name": "customInstructions", + "type": { + "text": "string" + }, + "default": "''", + "fieldName": "customInstructions" + }, + { + "name": "hasUsedAutoCompose", "type": { "text": "boolean" }, "default": "false", - "fieldName": "expandable", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "hasUsedAutoCompose" + }, + { + "name": "hasChanges", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "hasChanges" + }, + { + "name": "aiModel", + "type": { + "text": "AIModel | undefined" + }, + "default": "undefined", + "fieldName": "aiModel" + }, + { + "name": "compositionSummarySelected", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "compositionSummarySelected" + }, + { + "name": "compositionFeedback", + "type": { + "text": "'helpful' | 'unhelpful' | null" + }, + "default": "null", + "fieldName": "compositionFeedback" + }, + { + "name": "compositionSessionId", + "type": { + "text": "string | null" + }, + "default": "null", + "fieldName": "compositionSessionId" + }, + { + "name": "isReadyToCommit", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "isReadyToCommit" } - ] + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-commits-panel", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "activeWorkTagName", + "name": "CommitsPanel", "declaration": { - "name": "activeWorkTagName", - "module": "src/webviews/apps/plus/home/components/active-work.ts" + "name": "CommitsPanel", + "module": "src/webviews/apps/plus/composer/components/commits-panel.ts" } }, { - "kind": "js", - "name": "GlActiveWork", + "kind": "custom-element-definition", + "name": "gl-commits-panel", "declaration": { - "name": "GlActiveWork", - "module": "src/webviews/apps/plus/home/components/active-work.ts" + "name": "CommitsPanel", + "module": "src/webviews/apps/plus/composer/components/commits-panel.ts" } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/composer.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "composerItemStyles", + "default": "css` .composer-item { --composer-item-background: var(--composer-background-05); --composer-item-border: transparent; --composer-item-radius: 1.2rem; --composer-item-color: var(--vscode-foreground); --composer-item-icon-color: var(--vscode-icon-foreground); display: flex; flex-direction: row; align-items: center; /* gap: 0.8rem; */ border: 1px solid var(--composer-item-border); border-radius: var(--composer-item-radius); color: var(--composer-item-color); background: var(--composer-item-background); transition: background-color 0.2s ease; cursor: pointer; } .composer-item:not(.is-selected):is(:focus-visible, :hover) { --composer-item-background: var(--vscode-list-hoverBackground); } .composer-item.is-selected { --composer-item-background: var(--vscode-list-activeSelectionBackground, var(--color-background)); --composer-item-icon-color: var(--vscode-list-activeSelectionForeground, var(--vscode-foreground)); --composer-item-color: var(--vscode-list-activeSelectionForeground); } :host-context(.vscode-high-contrast) .composer-item.is-selected { --composer-item-border: var( --vscode-list-focusAndSelectionOutline, var(--vscode-contrastActiveBorder, var(--vscode-list-focusOutline)) ); } .composer-item.is-summary { --composer-item-border: var(--vscode-panel-border); --composer-item-radius: 0.4rem; } .composer-item.is-uncommitted { --composer-item-background: color-mix( in srgb, var(--vscode-notificationsWarningIcon-foreground) 8%, transparent ); --composer-item-border: color-mix(in srgb, var(--vscode-notificationsWarningIcon-foreground) 20%, transparent); --composer-item-radius: 0.4rem; border-style: dashed; } .composer-item.is-uncommitted:not(.is-selected):is(:focus-visible, :hover) { --composer-item-background: color-mix( in srgb, var(--vscode-notificationsWarningIcon-foreground) 12%, transparent ); } .composer-item.is-uncommitted.is-selected { --composer-item-background: color-mix( in srgb, var(--vscode-notificationsWarningIcon-foreground) 18%, transparent ); --composer-item-border: color-mix(in srgb, var(--vscode-notificationsWarningIcon-foreground) 25%, transparent); --composer-item-color: var(--vscode-foreground); } .composer-item.is-base, .composer-item.is-base:focus-visible, .composer-item.is-base:hover { --composer-item-background: var(--color-background); --composer-item-icon-color: var(--color-foreground--65); --composer-item-color: var(--color-foreground--65); } .composer-item__content { flex: 1; display: flex; min-width: 0; flex-direction: column; gap: 0.4rem; padding: 0.8rem 1.2rem; } .composer-item__header { font-size: 1.4rem; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .composer-item__header.is-placeholder, .composer-item__header.is-empty-state { font-style: italic; opacity: 0.65; } .composer-item__header.is-empty-state { white-space: normal; text-overflow: initial; text-wrap: pretty; } .composer-item__body { font-size: 1.2rem; } .composer-item.is-base .composer-item__body { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; } `" }, { - "kind": "custom-element-definition", + "kind": "variable", + "name": "composerItemCommitStyles", + "default": "css` .composer-item__commit { flex: none; position: relative; width: 2.2rem; align-self: stretch; margin-inline-start: 0.8rem; } .composer-item__commit::before { content: ''; position: absolute; top: 0; left: 50%; width: 0; height: 100%; border-left: 2px dashed var(--composer-item-icon-color); transform: translateX(-50%); } .composer-item.is-first .composer-item__commit::before { top: 50%; height: 50%; } .composer-item.is-last .composer-item__commit::before { display: none; } .composer-item__commit::after { content: ''; position: absolute; top: 50%; left: 0; width: 1.8rem; aspect-ratio: 1; transform: translateY(-50%); border-radius: 50%; background: var(--composer-item-background); border: 2px dashed var(--composer-item-icon-color); z-index: 1; } .composer-item.is-base .composer-item__commit::after { border-style: solid; } .composer-item.is-base .composer-item__commit::before { border-left-style: solid; } .composer-item__commit.is-empty::before, .composer-item__commit.is-empty::after { display: none; } `" + }, + { + "kind": "variable", + "name": "composerItemContentStyles", + "default": "css` .change-stats { display: flex; align-items: center; gap: 0.8rem; } .file-count { } .diff-stats { display: inline-flex; align-items: center; gap: 0.5rem; /* font-size: 0.8rem; */ font-weight: 500; } .diff-stats__additions { color: var(--vscode-gitDecoration-addedResourceForeground); color: light-dark( color-mix(in srgb, #fff 40%, var(--vscode-gitDecoration-addedResourceForeground)), var(--vscode-gitDecoration-addedResourceForeground) ); } .diff-stats__deletions { color: var(--vscode-gitDecoration-deletedResourceForeground); color: light-dark( color-mix(in srgb, #fff 40%, var(--vscode-gitDecoration-deletedResourceForeground)), var(--vscode-gitDecoration-deletedResourceForeground) ); } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "composerItemStyles", "declaration": { - "name": "GlActiveWork", - "module": "src/webviews/apps/plus/home/components/active-work.ts" + "name": "composerItemStyles", + "module": "src/webviews/apps/plus/composer/components/composer.css.ts" } }, { "kind": "js", - "name": "GlActiveBranchCard", + "name": "composerItemCommitStyles", "declaration": { - "name": "GlActiveBranchCard", - "module": "src/webviews/apps/plus/home/components/active-work.ts" + "name": "composerItemCommitStyles", + "module": "src/webviews/apps/plus/composer/components/composer.css.ts" } }, { - "kind": "custom-element-definition", - "name": "gl-active-branch-card", + "kind": "js", + "name": "composerItemContentStyles", "declaration": { - "name": "GlActiveBranchCard", - "module": "src/webviews/apps/plus/home/components/active-work.ts" + "name": "composerItemContentStyles", + "module": "src/webviews/apps/plus/composer/components/composer.css.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/branch-card.ts", + "path": "src/webviews/apps/plus/composer/components/details-panel.ts", "declarations": [ - { - "kind": "variable", - "name": "branchCardStyles", - "default": "css` * { box-sizing: border-box; } gl-avatar-list { --gl-avatar-size: 2.4rem; margin-block: -0.4rem; } .branch-item { position: relative; } .branch-item__container { display: flex; flex-direction: column; gap: 0.6rem; } .branch-item__container > * { margin-block: 0; } .branch-item__section { display: flex; flex-direction: column; gap: 0.4rem; } .branch-item__section > * { margin-block: 0; } .branch-item__section--details { font-size: 0.9em; color: var(--vscode-descriptionForeground); } .branch-item__actions { display: flex; align-items: center; gap: 0.8rem; flex-direction: row; justify-content: flex-end; font-size: 0.9em; } /* :empty selector doesn't work with lit */ .branch-item__actions:not(:has(*)) { display: none; } .branch-item__icon { color: var(--vscode-descriptionForeground); flex: none; } .branch-item__name { flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: bold; } .branch-item__name--secondary { font-weight: normal; } .branch-item__identifier { color: var(--vscode-descriptionForeground); text-decoration: none; } .branch-item__grouping { display: inline-flex; align-items: center; gap: 0.6rem; max-width: 100%; margin-block: 0; } .branch-item__changes { display: flex; align-items: center; gap: 1rem; justify-content: flex-end; flex-wrap: wrap; white-space: nowrap; } .branch-item__changes formatted-date { margin-inline-end: auto; } .branch-item__summary { display: flex; align-items: center; gap: 0.6rem; } .branch-item__collapsed-actions { position: absolute; z-index: var(--gl-branch-card-actions-zindex, 2); right: 0.4rem; bottom: 0.3rem; padding: 0.4rem 0.6rem; background-color: var(--gl-card-hover-background); } .branch-item:not(:focus-within):not(:hover) .branch-item__collapsed-actions { ${srOnlyStyles} } .pill { --gl-pill-border: color-mix(in srgb, transparent 80%, var(--color-foreground)); } .work-item { --gl-card-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 3%); --gl-card-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 1.5%); } .work-item::part(base) { margin-block-end: 0; } .branch-item__section.mb-1 { margin-block: 0.4rem; } .branch-item__merge-target { margin-inline-end: auto; } .branch-item__row { display: flex; gap: 0.8rem; } .branch-item__row [full] { flex-grow: 1; } .branch-item__missing { --button-foreground: inherit; } :host-context(.vscode-dark) .branch-item__missing, :host-context(.vscode-high-contrast) .branch-item__missing { --button-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 3%); --button-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 1.5%); --button-border: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 12%); } :host-context(.vscode-light) .branch-item__missing, :host-context(.vscode-high-contrast-light) .branch-item__missing { --button-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 8%); --button-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 10%); --button-border: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 14%); } .branch-item__category { margin-inline-start: 0.6rem; } .launchpad-grouping--mergeable { color: var(--vscode-gitlens-launchpadIndicatorMergeableColor); } .launchpad-grouping--blocked { color: var(--vscode-gitlens-launchpadIndicatorBlockedColor); } .launchpad-grouping--attention { color: var(--vscode-gitlens-launchpadIndicatorAttentionColor); } .tracking__pill, .wip__pill { display: flex; flex-direction: row; gap: 1rem; } .tracking__tooltip, .wip__tooltip { display: contents; vertical-align: middle; } .tracking__tooltip p, .wip__tooltip p { margin-block: 0; } p.tracking__tooltip--wip { margin-block-start: 1rem; } `" - }, { "kind": "class", "description": "", - "name": "GlBranchCardBase", + "name": "DetailsPanel", "members": [ { "kind": "field", - "name": "_homeState", + "name": "commits", "type": { - "text": "State" + "text": "ComposerCommit[]" }, - "privacy": "protected" + "default": "[]", + "attribute": "commits" }, { "kind": "field", - "name": "repo", + "name": "selectedCommits", "type": { - "text": "string" + "text": "ComposerCommit[]" }, - "attribute": "repo" + "default": "[]", + "attribute": "selectedCommits" }, { "kind": "field", - "name": "showUpgrade", + "name": "hunks", "type": { - "text": "boolean" + "text": "ComposerHunk[]" }, - "default": "false", - "attribute": "showUpgrade" + "default": "[]", + "attribute": "hunks" }, { "kind": "field", - "name": "_branch", + "name": "selectedUnassignedSection", "type": { - "text": "GetOverviewBranch" + "text": "'staged' | 'unstaged' | 'unassigned' | null" }, - "privacy": "private" + "default": "null", + "attribute": "selectedUnassignedSection" }, { "kind": "field", - "name": "branch", + "name": "commitMessageExpanded", "type": { - "text": "GetOverviewBranch" + "text": "boolean" }, - "attribute": "branch" + "default": "true", + "attribute": "commitMessageExpanded" }, { "kind": "field", - "name": "_autolinks", + "name": "aiExplanationExpanded", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private" + "default": "true", + "attribute": "aiExplanationExpanded" }, { "kind": "field", - "name": "autolinks", + "name": "filesChangedExpanded", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true + "default": "true", + "attribute": "filesChangedExpanded" }, { "kind": "field", - "name": "_autolinksPromise", + "name": "selectedHunkIds", "type": { - "text": "GetOverviewBranch['autolinks']" + "text": "Set" }, - "privacy": "private" + "default": "new Set()", + "attribute": "selectedHunkIds" }, { "kind": "field", - "name": "autolinksPromise", + "name": "generatingCommitMessage", "type": { - "text": "GetOverviewBranch['autolinks']" - } + "text": "string | null" + }, + "default": "null", + "attribute": "generatingCommitMessage" }, { "kind": "field", - "name": "_contributors", + "name": "committing", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private" + "default": "false", + "attribute": "committing" }, { "kind": "field", - "name": "contributors", + "name": "aiEnabled", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true + "default": "false", + "attribute": "aiEnabled" }, { "kind": "field", - "name": "_contributorsPromise", + "name": "aiDisabledReason", "type": { - "text": "GetOverviewBranch['contributors']" + "text": "string | null" }, - "privacy": "private" + "default": "null", + "attribute": "aiDisabledReason" }, { "kind": "field", - "name": "contributorsPromise", + "name": "isPreviewMode", "type": { - "text": "GetOverviewBranch['contributors']" - } + "text": "boolean" + }, + "default": "false", + "attribute": "isPreviewMode" }, { "kind": "field", - "name": "_issues", + "name": "compositionSummarySelected", "type": { - "text": "Awaited" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "issues", - "type": { - "text": "Awaited" - }, - "readonly": true - }, - { - "kind": "field", - "name": "_issuesPromise", - "type": { - "text": "GetOverviewBranch['issues']" + "text": "boolean" }, - "privacy": "private" - }, - { - "kind": "field", - "name": "issuesPromise", - "type": { - "text": "GetOverviewBranch['issues']" - } + "default": "false", + "attribute": "compositionSummarySelected" }, { "kind": "field", - "name": "_pr", + "name": "hasChanges", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private" + "default": "true", + "attribute": "hasChanges" }, { "kind": "field", - "name": "pr", + "name": "defaultFilesExpanded", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true + "privacy": "private", + "default": "true" }, { "kind": "field", - "name": "_prPromise", + "name": "hunksSortables", "type": { - "text": "GetOverviewBranch['pr']" + "text": "Sortable[]" }, - "privacy": "private" - }, - { - "kind": "field", - "name": "prPromise", - "type": { - "text": "GetOverviewBranch['pr']" - } + "privacy": "private", + "default": "[]" }, { "kind": "field", - "name": "_launchpadItem", + "name": "isDraggingHunks", "type": { - "text": "Awaited>['launchpad']>" + "text": "boolean" }, - "privacy": "private" + "privacy": "private", + "default": "false" }, { "kind": "field", - "name": "launchpadItem", + "name": "draggedHunkIds", "type": { - "text": "Awaited>['launchpad']>" + "text": "string[]" }, - "readonly": true + "privacy": "private", + "default": "[]" }, { "kind": "field", - "name": "_launchpadItemPromise", + "name": "autoScrollInterval", "type": { - "text": "NonNullable>['launchpad']" + "text": "number | undefined" }, "privacy": "private" }, { "kind": "field", - "name": "launchpadItemPromise", - "type": { - "text": "NonNullable>['launchpad']" - } - }, - { - "kind": "field", - "name": "_mergeTarget", + "name": "dragOverCleanupTimeout", "type": { - "text": "Awaited" + "text": "number | undefined" }, "privacy": "private" }, { "kind": "field", - "name": "mergeTarget", - "type": { - "text": "Awaited" - }, - "readonly": true - }, - { - "kind": "field", - "name": "_mergeTargetPromise", + "name": "detailsPanel", "type": { - "text": "GetOverviewBranch['mergeTarget']" + "text": "HTMLDivElement" }, "privacy": "private" }, { - "kind": "field", - "name": "mergeTargetPromise", - "type": { - "text": "GetOverviewBranch['mergeTarget']" - } - }, - { - "kind": "field", - "name": "_remote", - "type": { - "text": "Awaited" - }, + "kind": "method", + "name": "destroyHunksSortables", "privacy": "private" }, { - "kind": "field", - "name": "remote", - "type": { - "text": "Awaited" - }, - "readonly": true - }, - { - "kind": "field", - "name": "_remotePromise", - "type": { - "text": "GetOverviewBranch['remote']" - }, + "kind": "method", + "name": "initializeHunksSortable", "privacy": "private" }, { "kind": "field", - "name": "remotePromise", - "type": { - "text": "GetOverviewBranch['remote']" - } - }, - { - "kind": "field", - "name": "_wip", - "type": { - "text": "Awaited" - }, + "name": "handleFilesListDragOver", "privacy": "private" }, { "kind": "field", - "name": "wip", - "type": { - "text": "Awaited" - }, - "readonly": true - }, - { - "kind": "field", - "name": "_wipPromise", - "type": { - "text": "GetOverviewBranch['wip']" - }, + "name": "handleFilesListDrop", "privacy": "private" }, { - "kind": "field", - "name": "wipPromise", - "type": { - "text": "GetOverviewBranch['wip']" - } - }, - { - "kind": "field", - "name": "busy", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "busy", - "reflects": true - }, - { - "kind": "field", - "name": "expanded", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expanded", - "reflects": true - }, - { - "kind": "field", - "name": "expandable", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expandable", - "reflects": true - }, - { - "kind": "field", - "name": "eventController", - "type": { - "text": "AbortController | undefined" - }, + "kind": "method", + "name": "setupAutoScroll", "privacy": "private" }, { "kind": "method", - "name": "onExpandableChanged", + "name": "cleanupAutoScroll", "privacy": "private" }, { "kind": "field", - "name": "branchRef", - "type": { - "text": "BranchRef" - }, - "readonly": true - }, - { - "kind": "field", - "name": "isWorktree", - "type": { - "text": "boolean" - }, - "readonly": true - }, - { - "kind": "field", - "name": "cardIndicator", - "type": { - "text": "GlCard['indicator']" - }, - "readonly": true - }, - { - "kind": "field", - "name": "branchCardIndicator", - "type": { - "text": "GlCard['indicator']" - }, - "readonly": true - }, - { - "kind": "method", - "name": "attachFocusListener", + "name": "handleGlobalDragEnd", "privacy": "private" }, { "kind": "field", - "name": "onFocus", - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "renderIssues", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "handleDragOverForAutoScroll", + "privacy": "private" }, { "kind": "method", - "name": "renderWip", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" + "name": "dispatchHunkDragStart", + "privacy": "private", + "parameters": [ + { + "name": "hunkIds", + "type": { + "text": "string[]" + } } - } + ] }, { "kind": "method", - "name": "renderAvatars", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "dispatchHunkDragEnd", + "privacy": "private" }, { "kind": "method", - "name": "renderTracking", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - }, + "name": "handleCommitMessageChange", + "privacy": "private", "parameters": [ { - "name": "showWip", - "default": "false" + "name": "commitId", + "type": { + "text": "string" + } + }, + { + "name": "message", + "type": { + "text": "string" + } } ] }, { "kind": "method", - "name": "getBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" + "name": "handleGenerateCommitMessage", + "privacy": "private", + "parameters": [ + { + "name": "commitId", + "type": { + "text": "string" + } + }, + { + "name": "e", + "optional": true, + "type": { + "text": "CustomEvent" + } } - } + ] }, { "kind": "method", - "name": "renderBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "handleCollapseAllFiles", + "privacy": "private" }, { "kind": "method", - "name": "getPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } - } + "name": "handleExpandAllFiles", + "privacy": "private" }, { "kind": "method", - "name": "renderPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" + "name": "renderFilesChangedHeader", + "privacy": "private", + "parameters": [ + { + "name": "fileCount", + "type": { + "text": "number | string" + } } - } + ] }, { "kind": "method", - "name": "getCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" + "name": "renderFileHierarchy", + "privacy": "private", + "parameters": [ + { + "name": "hunks", + "type": { + "text": "ComposerHunk[]" + } } - } + ] }, { "kind": "method", - "name": "renderCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" + "name": "renderFile", + "privacy": "private", + "parameters": [ + { + "name": "fileName", + "type": { + "text": "string" + } + }, + { + "name": "fileHunks", + "type": { + "text": "ComposerHunk[]" + } } - } + ] }, { "kind": "method", - "name": "createWebviewCommandLink", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } - }, + "name": "dispatchHunkSelect", + "privacy": "private", "parameters": [ { - "name": "command", + "name": "hunkId", "type": { - "text": "WebviewCommands | WebviewViewCommands | PlusCommands" + "text": "string" } }, { - "name": "args", - "optional": true, + "name": "shiftKey", + "default": "false", "type": { - "text": "T | any" + "text": "boolean" } } ] }, { "kind": "method", - "name": "createCommandLink", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } - }, + "name": "focusCommitMessageInput", + "privacy": "public", "parameters": [ { - "name": "command", + "name": "commitId", "type": { - "text": "GlCommands" + "text": "string" } }, { - "name": "args", - "optional": true, - "type": { - "text": "T | any" - } + "name": "checkValidity", + "default": "false" } ] }, { "kind": "method", - "name": "renderTimestamp", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "renderUnassignedSectionDetails", + "privacy": "private" }, { "kind": "method", - "name": "renderBranchIndicator", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | undefined" + "name": "renderCommitDetails", + "privacy": "private", + "parameters": [ + { + "name": "commit", + "type": { + "text": "ComposerCommit" + } } - } + ] }, { "kind": "method", - "name": "renderBranchItem", - "privacy": "protected", + "name": "getHunksForSection", + "privacy": "private", "return": { "type": { - "text": "TemplateResult | NothingType" + "text": "ComposerHunk[]" } }, "parameters": [ { - "name": "actionsSection", - "optional": true, + "name": "section", "type": { - "text": "TemplateResult | NothingType" + "text": "'staged' | 'unstaged' | 'unassigned'" } } ] }, { "kind": "method", - "name": "renderBranchIcon", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderPrItem", - "privacy": "protected", + "name": "getSectionTitle", + "privacy": "private", "return": { "type": { - "text": "TemplateResult | NothingType" + "text": "string" } - } + }, + "parameters": [ + { + "name": "section", + "type": { + "text": "'staged' | 'unstaged' | 'unassigned'" + } + } + ] }, { "kind": "method", - "name": "renderLaunchpadItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "renderCompositionSummary", + "privacy": "private" }, { "kind": "method", - "name": "renderMergeTargetStatus", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "renderNoChangesState", + "privacy": "private" }, { "kind": "method", - "name": "renderIssuesItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } - } + "name": "handleClose", + "privacy": "private" }, { "kind": "method", - "name": "toggleExpanded", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "expanded", - "default": "!this.expanded" - } - ] + "name": "handleReload", + "privacy": "private" }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + "name": "renderDetails", + "privacy": "private" } ], - "attributes": [ + "events": [ { - "name": "repo", + "name": "hunk-drag-start", "type": { - "text": "string" - }, - "fieldName": "repo" + "text": "CustomEvent" + } }, { - "name": "showUpgrade", + "name": "hunk-drag-end", "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "showUpgrade" + "text": "CustomEvent" + } }, { - "name": "branch", + "name": "update-commit-message", "type": { - "text": "GetOverviewBranch" - }, - "fieldName": "branch" - }, - { - "name": "busy", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "busy" - }, - { - "name": "expanded", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "expanded" - }, - { - "name": "expandable", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "expandable" - } - ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } - }, - { - "kind": "class", - "description": "", - "name": "GlBranchCard", - "members": [ - { - "kind": "method", - "name": "getCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "CustomEvent" } }, { - "kind": "method", - "name": "getBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "generate-commit-message", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "getPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult[]" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "hunk-selected", + "type": { + "text": "CustomEvent" } }, { - "kind": "method", - "name": "renderBranchIndicator", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | undefined" - } - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "close-composer", + "type": { + "text": "CustomEvent" } }, { - "kind": "field", - "name": "_homeState", + "name": "reload-composer", "type": { - "text": "State" - }, - "privacy": "protected", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "CustomEvent" } - }, + } + ], + "attributes": [ { - "kind": "field", - "name": "repo", + "name": "commits", "type": { - "text": "string" + "text": "ComposerCommit[]" }, - "attribute": "repo", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "fieldName": "commits" }, { - "kind": "field", - "name": "showUpgrade", + "name": "selectedCommits", "type": { - "text": "boolean" + "text": "ComposerCommit[]" }, - "default": "false", - "attribute": "showUpgrade", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "fieldName": "selectedCommits" }, { - "kind": "field", - "name": "_branch", + "name": "hunks", "type": { - "text": "GetOverviewBranch" + "text": "ComposerHunk[]" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "[]", + "fieldName": "hunks" }, { - "kind": "field", - "name": "branch", + "name": "selectedUnassignedSection", "type": { - "text": "GetOverviewBranch" + "text": "'staged' | 'unstaged' | 'unassigned' | null" }, - "attribute": "branch", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "fieldName": "selectedUnassignedSection" }, { - "kind": "field", - "name": "_autolinks", + "name": "commitMessageExpanded", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "true", + "fieldName": "commitMessageExpanded" }, { - "kind": "field", - "name": "autolinks", + "name": "aiExplanationExpanded", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "true", + "fieldName": "aiExplanationExpanded" }, { - "kind": "field", - "name": "_autolinksPromise", + "name": "filesChangedExpanded", "type": { - "text": "GetOverviewBranch['autolinks']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "true", + "fieldName": "filesChangedExpanded" }, { - "kind": "field", - "name": "autolinksPromise", + "name": "selectedHunkIds", "type": { - "text": "GetOverviewBranch['autolinks']" + "text": "Set" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "new Set()", + "fieldName": "selectedHunkIds" }, { - "kind": "field", - "name": "_contributors", + "name": "generatingCommitMessage", "type": { - "text": "Awaited" + "text": "string | null" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "fieldName": "generatingCommitMessage" }, { - "kind": "field", - "name": "contributors", + "name": "committing", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "committing" }, { - "kind": "field", - "name": "_contributorsPromise", + "name": "aiEnabled", "type": { - "text": "GetOverviewBranch['contributors']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "aiEnabled" }, { - "kind": "field", - "name": "contributorsPromise", + "name": "aiDisabledReason", "type": { - "text": "GetOverviewBranch['contributors']" + "text": "string | null" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "null", + "fieldName": "aiDisabledReason" }, { - "kind": "field", - "name": "_issues", + "name": "isPreviewMode", "type": { - "text": "Awaited" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "isPreviewMode" }, { - "kind": "field", - "name": "issues", + "name": "compositionSummarySelected", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "fieldName": "compositionSummarySelected" }, { - "kind": "field", - "name": "_issuesPromise", + "name": "hasChanges", "type": { - "text": "GetOverviewBranch['issues']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "default": "true", + "fieldName": "hasChanges" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-details-panel", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "DetailsPanel", + "declaration": { + "name": "DetailsPanel", + "module": "src/webviews/apps/plus/composer/components/details-panel.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-details-panel", + "declaration": { + "name": "DetailsPanel", + "module": "src/webviews/apps/plus/composer/components/details-panel.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/hunk-item.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "HunkItem", + "members": [ { "kind": "field", - "name": "issuesPromise", + "name": "hunkId", "type": { - "text": "GetOverviewBranch['issues']" + "text": "string" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "hunkId" }, { "kind": "field", - "name": "_pr", + "name": "fileName", "type": { - "text": "Awaited" + "text": "string" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "fileName" }, { "kind": "field", - "name": "pr", + "name": "hunkHeader", "type": { - "text": "Awaited" + "text": "string | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "hunkHeader" }, { "kind": "field", - "name": "_prPromise", + "name": "content", "type": { - "text": "GetOverviewBranch['pr']" + "text": "string" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "content" }, { "kind": "field", - "name": "prPromise", + "name": "additions", "type": { - "text": "GetOverviewBranch['pr']" + "text": "number" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "additions" }, { "kind": "field", - "name": "_launchpadItem", + "name": "deletions", "type": { - "text": "Awaited>['launchpad']>" + "text": "number" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "deletions" }, { "kind": "field", - "name": "launchpadItem", + "name": "selected", "type": { - "text": "Awaited>['launchpad']>" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "selected" }, { "kind": "field", - "name": "_launchpadItemPromise", + "name": "multiSelected", "type": { - "text": "NonNullable>['launchpad']" + "text": "boolean" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "multiSelected" }, { "kind": "field", - "name": "launchpadItemPromise", + "name": "isRename", "type": { - "text": "NonNullable>['launchpad']" + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "isRename" }, { "kind": "field", - "name": "_mergeTarget", + "name": "originalFileName", "type": { - "text": "Awaited" + "text": "string | undefined" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "originalFileName" }, { "kind": "field", - "name": "mergeTarget", + "name": "isPreviewMode", "type": { - "text": "Awaited" + "text": "boolean" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "default": "false", + "attribute": "isPreviewMode" }, { - "kind": "field", - "name": "_mergeTargetPromise", - "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, + "kind": "method", + "name": "handleClick", "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + } + ] }, { - "kind": "field", - "name": "mergeTargetPromise", - "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "kind": "method", + "name": "renderHunkHeader", + "privacy": "private" }, { - "kind": "field", - "name": "_remote", - "type": { - "text": "Awaited" - }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "kind": "method", + "name": "renderDiffContent", + "privacy": "private" + } + ], + "events": [ { - "kind": "field", - "name": "remote", + "name": "hunk-selected", "type": { - "text": "Awaited" - }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "text": "CustomEvent" } - }, + } + ], + "attributes": [ { - "kind": "field", - "name": "_remotePromise", + "name": "hunkId", "type": { - "text": "GetOverviewBranch['remote']" + "text": "string" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "hunkId" }, { - "kind": "field", - "name": "remotePromise", + "name": "fileName", "type": { - "text": "GetOverviewBranch['remote']" + "text": "string" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "fileName" }, { - "kind": "field", - "name": "_wip", + "name": "hunkHeader", "type": { - "text": "Awaited" + "text": "string | undefined" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "hunkHeader" }, { - "kind": "field", - "name": "wip", + "name": "content", "type": { - "text": "Awaited" + "text": "string" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "content" }, { - "kind": "field", - "name": "_wipPromise", + "name": "additions", "type": { - "text": "GetOverviewBranch['wip']" + "text": "number" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "additions" }, { - "kind": "field", - "name": "wipPromise", + "name": "deletions", "type": { - "text": "GetOverviewBranch['wip']" + "text": "number" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "deletions" }, { - "kind": "field", - "name": "busy", + "name": "selected", "type": { "text": "boolean" }, "default": "false", - "attribute": "busy", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "selected" }, { - "kind": "field", - "name": "expanded", + "name": "multiSelected", "type": { "text": "boolean" }, "default": "false", - "attribute": "expanded", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "multiSelected" }, { - "kind": "field", - "name": "expandable", + "name": "isRename", "type": { "text": "boolean" }, "default": "false", - "attribute": "expandable", - "reflects": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "isRename" }, { - "kind": "field", - "name": "eventController", + "name": "originalFileName", "type": { - "text": "AbortController | undefined" + "text": "string | undefined" }, - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "originalFileName" }, { - "kind": "method", - "name": "onExpandableChanged", - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "name": "isPreviewMode", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "isPreviewMode" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-hunk-item", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "HunkItem", + "declaration": { + "name": "HunkItem", + "module": "src/webviews/apps/plus/composer/components/hunk-item.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-hunk-item", + "declaration": { + "name": "HunkItem", + "module": "src/webviews/apps/plus/composer/components/hunk-item.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GitActionsButtons", + "members": [ { "kind": "field", - "name": "branchRef", + "name": "branchState", "type": { - "text": "BranchRef" + "text": "BranchState | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "branchState" }, { "kind": "field", - "name": "isWorktree", + "name": "branchName", "type": { - "text": "boolean" + "text": "string | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "branchName" }, { "kind": "field", - "name": "cardIndicator", + "name": "lastFetched", "type": { - "text": "GlCard['indicator']" + "text": "Date | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "lastFetched" }, { "kind": "field", - "name": "branchCardIndicator", + "name": "state", "type": { - "text": "GlCard['indicator']" + "text": "State" }, - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "kind": "method", - "name": "attachFocusListener", - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "state" }, { "kind": "field", - "name": "onFocus", + "name": "fetchedText", "privacy": "private", - "readonly": true, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "readonly": true + } + ], + "attributes": [ { - "kind": "method", - "name": "renderIssues", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "branchState", + "type": { + "text": "BranchState | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "branchState" }, { - "kind": "method", - "name": "renderWip", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "branchName", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "branchName" }, { - "kind": "method", - "name": "renderAvatars", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "lastFetched", + "type": { + "text": "Date | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "lastFetched" }, { - "kind": "method", - "name": "renderTracking", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "state", + "type": { + "text": "State" }, - "parameters": [ - { - "name": "showWip", - "default": "false" - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "fieldName": "state" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-git-actions-buttons", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlFetchButton", + "members": [ { - "kind": "method", - "name": "renderBranchActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "state", + "type": { + "text": "State" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "state" }, { - "kind": "method", - "name": "renderPrActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "fetchedText", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "fetchedText" }, { - "kind": "method", - "name": "renderCollapsedActions", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "branchState", + "type": { + "text": "BranchState | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "branchState" }, { - "kind": "method", - "name": "createWebviewCommandLink", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } + "kind": "field", + "name": "upstream", + "privacy": "private", + "readonly": true + } + ], + "attributes": [ + { + "name": "state", + "type": { + "text": "State" }, - "parameters": [ - { - "name": "command", - "type": { - "text": "WebviewCommands | WebviewViewCommands | PlusCommands" - } - }, - { - "name": "args", - "optional": true, - "type": { - "text": "T | any" - } - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "state" }, { - "kind": "method", - "name": "createCommandLink", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } + "name": "fetchedText", + "type": { + "text": "string | undefined" }, - "parameters": [ - { - "name": "command", - "type": { - "text": "GlCommands" - } - }, - { - "name": "args", - "optional": true, - "type": { - "text": "T | any" - } - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "fetchedText" }, { - "kind": "method", - "name": "renderTimestamp", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "name": "branchState", + "type": { + "text": "BranchState | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, + "fieldName": "branchState" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-fetch-button", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "PushPullButton", + "members": [ { - "kind": "method", - "name": "renderBranchItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "branchState", + "type": { + "text": "BranchState | undefined" }, - "parameters": [ - { - "name": "actionsSection", - "optional": true, - "type": { - "text": "TemplateResult | NothingType" - } - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "branchState" }, { - "kind": "method", - "name": "renderBranchIcon", - "privacy": "private", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "attribute": "state" }, { - "kind": "method", - "name": "renderPrItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "fetchedText", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "fetchedText" }, { - "kind": "method", - "name": "renderLaunchpadItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "branchName", + "type": { + "text": "string | undefined" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "attribute": "branchName" }, { - "kind": "method", - "name": "renderMergeTargetStatus", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "isBehind", + "type": { + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "renderIssuesItem", - "privacy": "protected", - "return": { - "type": { - "text": "TemplateResult | NothingType" - } + "kind": "field", + "name": "isAhead", + "type": { + "text": "boolean" }, - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "upstream", + "privacy": "private", + "readonly": true }, { "kind": "method", - "name": "toggleExpanded", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "expanded", - "default": "!this.expanded" - } - ], - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "name": "renderBranchPrefix", + "privacy": "private" }, { "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, + "name": "renderTooltipContent", + "privacy": "private", "parameters": [ { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, + "name": "action", "type": { - "text": "Omit>, 'detail'>" + "text": "'pull' | 'push'" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + ] } ], - "superclass": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - }, - "tagName": "gl-branch-card", - "customElement": true, "attributes": [ { - "name": "repo", + "name": "branchState", "type": { - "text": "string" + "text": "BranchState | undefined" }, - "fieldName": "repo", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } + "fieldName": "branchState" }, { - "name": "showUpgrade", + "name": "state", "type": { - "text": "boolean" + "text": "State" }, - "default": "false", - "fieldName": "showUpgrade", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "name": "branch", - "type": { - "text": "GetOverviewBranch" - }, - "fieldName": "branch", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "name": "busy", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "busy", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "name": "expanded", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "expanded", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - }, - { - "name": "expandable", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "expandable", - "inheritedFrom": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" - } - } - ] - }, - { - "kind": "class", - "description": "", - "name": "GlWorkUnit", - "members": [ - { - "kind": "field", - "name": "primary", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "primary", - "reflects": true - }, - { - "kind": "field", - "name": "nested", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "nested", - "reflects": true - }, - { - "kind": "field", - "name": "indicator", - "type": { - "text": "GlCard['indicator'] | undefined" - }, - "attribute": "indicator", - "reflects": true - }, - { - "kind": "field", - "name": "expanded", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "expanded", - "reflects": true - }, - { - "kind": "method", - "name": "renderContent", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderSummary", - "privacy": "private" - } - ], - "attributes": [ - { - "name": "primary", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "primary" - }, - { - "name": "nested", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "nested" + "fieldName": "state" }, { - "name": "indicator", + "name": "fetchedText", "type": { - "text": "GlCard['indicator'] | undefined" + "text": "string | undefined" }, - "fieldName": "indicator" + "fieldName": "fetchedText" }, { - "name": "expanded", + "name": "branchName", "type": { - "text": "boolean" + "text": "string | undefined" }, - "default": "false", - "fieldName": "expanded" + "fieldName": "branchName" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-work-item", + "tagName": "gl-push-pull-button", "customElement": true } ], "exports": [ { "kind": "js", - "name": "branchCardStyles", + "name": "GitActionsButtons", "declaration": { - "name": "branchCardStyles", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "GitActionsButtons", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } }, { - "kind": "js", - "name": "GlBranchCardBase", + "kind": "custom-element-definition", + "name": "gl-git-actions-buttons", "declaration": { - "name": "GlBranchCardBase", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "GitActionsButtons", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } }, { "kind": "js", - "name": "GlBranchCard", + "name": "GlFetchButton", "declaration": { - "name": "GlBranchCard", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "GlFetchButton", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } }, { "kind": "custom-element-definition", - "name": "gl-branch-card", + "name": "gl-fetch-button", "declaration": { - "name": "GlBranchCard", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "GlFetchButton", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } }, { "kind": "js", - "name": "GlWorkUnit", + "name": "PushPullButton", "declaration": { - "name": "GlWorkUnit", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "PushPullButton", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } }, { "kind": "custom-element-definition", - "name": "gl-work-item", + "name": "gl-push-pull-button", "declaration": { - "name": "GlWorkUnit", - "module": "src/webviews/apps/plus/home/components/branch-card.ts" + "name": "PushPullButton", + "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/branch-section.ts", + "path": "src/webviews/apps/plus/graph/graph-wrapper/gl-graph.ts", "declarations": [ { "kind": "class", - "description": "", - "name": "GlSection", + "description": "A LitElement web component that encapsulates the GraphWrapperReact component.\nThis component mounts the React component once and then updates its state\nwithout remounting on subsequent property changes.", + "name": "GlGraph", "members": [ { "kind": "field", - "name": "loading", + "name": "reactRoot", "type": { - "text": "boolean" + "text": "ReturnType | null" }, - "default": "false", - "attribute": "loading" + "privacy": "private", + "default": "null" }, { "kind": "field", - "name": "headingLevel", + "name": "provideReactState", "type": { - "text": "ARIAMixin['ariaLevel']" + "text": "((props: Partial) => void) | null" }, - "default": "'3'", - "attribute": "heading-level" - } - ], - "attributes": [ + "privacy": "private", + "default": "null" + }, { - "name": "loading", + "kind": "field", + "name": "setReactStateProvider", + "privacy": "private" + }, + { + "kind": "field", + "name": "activeRow", "type": { - "text": "boolean" + "text": "GraphWrapperProps['activeRow'] | undefined" }, - "default": "false", - "fieldName": "loading" + "attribute": "activeRow" }, { - "name": "heading-level", + "kind": "field", + "name": "avatars", "type": { - "text": "ARIAMixin['ariaLevel']" + "text": "GraphWrapperProps['avatars'] | undefined" }, - "default": "'3'", - "fieldName": "headingLevel" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-section", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlBranchSection", - "members": [ + "attribute": "avatars" + }, { "kind": "field", - "name": "label", + "name": "columns", "type": { - "text": "string" + "text": "GraphWrapperProps['columns'] | undefined" }, - "attribute": "label" + "attribute": "columns" }, { "kind": "field", - "name": "repo", + "name": "context", "type": { - "text": "string" + "text": "GraphWrapperProps['context'] | undefined" }, - "attribute": "repo" + "attribute": "context" }, { "kind": "field", - "name": "branches", + "name": "config", "type": { - "text": "GetOverviewBranch[]" + "text": "GraphWrapperProps['config'] | undefined" }, - "attribute": "branches" + "attribute": "config" }, { "kind": "field", - "name": "isFetching", + "name": "downstreams", "type": { - "text": "boolean" + "text": "GraphWrapperProps['downstreams'] | undefined" }, - "default": "false", - "attribute": "isFetching" + "attribute": "downstreams" }, { "kind": "field", - "name": "branchCards", + "name": "rows", "type": { - "text": "GlBranchCardBase[]" + "text": "GraphWrapperProps['rows'] | undefined" }, - "privacy": "private" + "attribute": "rows" }, { "kind": "field", - "name": "onCardExpanded", - "privacy": "private", - "readonly": true + "name": "excludeRefs", + "type": { + "text": "GraphWrapperProps['excludeRefs'] | undefined" + }, + "attribute": "excludeRefs" }, { - "kind": "method", - "name": "toggleSiblingCards", - "privacy": "private", - "parameters": [ - { - "name": "card", - "optional": true, - "type": { - "text": "GlBranchCardBase" - } - } - ] + "kind": "field", + "name": "excludeTypes", + "type": { + "text": "GraphWrapperProps['excludeTypes'] | undefined" + }, + "attribute": "excludeTypes" }, { "kind": "field", - "name": "toggleSiblingCardsDebounced", - "privacy": "private" + "name": "paging", + "type": { + "text": "GraphWrapperProps['paging'] | undefined" + }, + "attribute": "paging" }, { - "kind": "method", - "name": "renderSectionLabel", - "privacy": "private" - } - ], - "attributes": [ + "kind": "field", + "name": "loading", + "type": { + "text": "GraphWrapperProps['loading'] | undefined" + }, + "attribute": "loading" + }, { - "name": "label", + "kind": "field", + "name": "selectedRows", "type": { - "text": "string" + "text": "GraphWrapperProps['selectedRows'] | undefined" }, - "fieldName": "label" + "attribute": "selectedRows" }, { - "name": "repo", + "kind": "field", + "name": "windowFocused", "type": { - "text": "string" + "text": "GraphWrapperProps['windowFocused'] | undefined" }, - "fieldName": "repo" + "attribute": "windowFocused" }, { - "name": "branches", + "kind": "field", + "name": "refsMetadata", "type": { - "text": "GetOverviewBranch[]" + "text": "GraphWrapperProps['refsMetadata'] | undefined" }, - "fieldName": "branches" + "attribute": "refsMetadata" }, { - "name": "isFetching", + "kind": "field", + "name": "includeOnlyRefs", "type": { - "text": "boolean" + "text": "GraphWrapperProps['includeOnlyRefs'] | undefined" }, - "default": "false", - "fieldName": "isFetching" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-branch-section", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlSection", - "declaration": { - "name": "GlSection", - "module": "src/webviews/apps/plus/home/components/branch-section.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-section", - "declaration": { - "name": "GlSection", - "module": "src/webviews/apps/plus/home/components/branch-section.ts" - } - }, - { - "kind": "js", - "name": "GlBranchSection", - "declaration": { - "name": "GlBranchSection", - "module": "src/webviews/apps/plus/home/components/branch-section.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-branch-section", - "declaration": { - "name": "GlBranchSection", - "module": "src/webviews/apps/plus/home/components/branch-section.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts", - "declarations": [ - { - "kind": "variable", - "name": "selectStyles", - "default": "css` .select { background: none; outline: none; border: none; text-decoration: none !important; font-weight: 500; color: var(--color-foreground--25); } .select option { color: var(--vscode-foreground); background-color: var(--vscode-dropdown-background); } .select:not(:disabled) { cursor: pointer; color: var(--color-foreground--50); } .select:not(:disabled):focus { outline: 1px solid var(--color-focus-border); } .select:not(:disabled):hover { color: var(--vscode-foreground); text-decoration: underline !important; } `" - }, - { - "kind": "class", - "description": "", - "name": "GlObjectSelect", - "members": [ + "attribute": "includeOnlyRefs" + }, { "kind": "field", - "name": "disabled", + "name": "rowsStats", "type": { - "text": "boolean" + "text": "GraphWrapperProps['rowsStats'] | undefined" }, - "default": "false", - "attribute": "disabled" + "attribute": "rowsStats" }, { "kind": "field", - "name": "value", + "name": "rowsStatsLoading", "type": { - "text": "V | undefined" + "text": "GraphWrapperProps['rowsStatsLoading'] | undefined" }, - "attribute": "value" + "attribute": "rowsStatsLoading" }, { "kind": "field", - "name": "options", + "name": "workingTreeStats", "type": { - "text": "T[] | undefined" + "text": "GraphWrapperProps['workingTreeStats'] | undefined" }, - "attribute": "options" + "attribute": "workingTreeStats" }, { - "kind": "method", - "name": "getValue", - "privacy": "protected", - "return": { - "type": { - "text": "V" - } + "kind": "field", + "name": "theming", + "type": { + "text": "GraphWrapperProps['theming'] | undefined" }, - "parameters": [ - { - "name": "option", - "type": { - "text": "T" - } - } - ] + "attribute": "theming" }, { - "kind": "method", - "name": "getLabel", - "privacy": "protected", - "return": { - "type": { - "text": "L" - } + "kind": "field", + "name": "searchResults", + "type": { + "text": "GraphWrapperProps['searchResults'] | undefined" }, - "parameters": [ - { - "name": "option", - "type": { - "text": "T" - } - } - ] + "attribute": "searchResults" }, { - "kind": "method", - "name": "onChange", - "privacy": "protected", - "return": { - "type": { - "text": "unknown" - } + "kind": "field", + "name": "filter", + "type": { + "text": "SearchQuery" }, - "parameters": [ - { - "name": "e", - "type": { - "text": "InputEvent" - } - } - ] + "attribute": "filter" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "kind": "field", + "name": "setRef", + "type": { + "text": "(ref: GraphContainer) => void" + } + }, + { + "kind": "field", + "name": "changedProps", + "type": { + "text": "Map" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ + "privacy": "private", + "default": "new Map()" + }, { - "name": "disabled", + "kind": "field", + "name": "updateScheduled", "type": { "text": "boolean" }, - "default": "false", - "fieldName": "disabled" + "privacy": "private", + "default": "false" }, { - "name": "value", - "type": { - "text": "V | undefined" - }, - "fieldName": "value" + "kind": "field", + "name": "handleChangeColumns", + "privacy": "private" }, { - "name": "options", - "type": { - "text": "T[] | undefined" - }, - "fieldName": "options" + "kind": "field", + "name": "handleChangeRefsVisibility", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleChangeSelection", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleChangeVisibleDays", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleMissingAvatars", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleMissingRefsMetadata", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleMoreRows", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleMouseLeave", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleRefDoubleClick", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleRowContextMenu", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleRowDoubleClick", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleRowHover", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleRowUnhover", + "privacy": "private" } ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } - }, - { - "kind": "class", - "description": "", - "name": "GlBranchThresholdFilter", - "members": [ + "attributes": [ { - "kind": "method", - "name": "getValue", - "privacy": "protected", - "return": { - "type": { - "text": "OverviewRecentThreshold | 'OneYear'" - } + "name": "activeRow", + "type": { + "text": "GraphWrapperProps['activeRow'] | undefined" }, - "parameters": [ - { - "name": "option", - "type": { - "text": "{\n\t\tvalue: OverviewRecentThreshold | OverviewStaleThreshold;\n\t}" - } - } - ], - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "activeRow" }, { - "kind": "method", - "name": "getLabel", - "privacy": "protected", - "return": { - "type": { - "text": "string" - } + "name": "avatars", + "type": { + "text": "GraphWrapperProps['avatars'] | undefined" }, - "parameters": [ - { - "name": "option", - "type": { - "text": "{ label: string }" - } - } - ], - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "avatars" }, { - "kind": "method", - "name": "onChange", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "name": "columns", + "type": { + "text": "GraphWrapperProps['columns'] | undefined" }, - "parameters": [ - { - "name": "e", - "type": { - "text": "InputEvent" - } - } - ], - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "columns" }, { - "kind": "field", - "name": "disabled", + "name": "context", "type": { - "text": "boolean" + "text": "GraphWrapperProps['context'] | undefined" }, - "default": "false", - "attribute": "disabled", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "context" }, { - "kind": "field", - "name": "value", + "name": "config", "type": { - "text": "V | undefined" + "text": "GraphWrapperProps['config'] | undefined" }, - "attribute": "value", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "config" }, { - "kind": "field", - "name": "options", + "name": "downstreams", "type": { - "text": "T[] | undefined" + "text": "GraphWrapperProps['downstreams'] | undefined" }, - "attribute": "options", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "downstreams" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "name": "rows", + "type": { + "text": "GraphWrapperProps['rows'] | undefined" }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "superclass": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - }, - "tagName": "gl-branch-threshold-filter", - "customElement": true, - "attributes": [ + "fieldName": "rows" + }, { - "name": "disabled", + "name": "excludeRefs", "type": { - "text": "boolean" + "text": "GraphWrapperProps['excludeRefs'] | undefined" }, - "default": "false", - "fieldName": "disabled", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "excludeRefs" }, { - "name": "value", + "name": "excludeTypes", "type": { - "text": "V | undefined" + "text": "GraphWrapperProps['excludeTypes'] | undefined" }, - "fieldName": "value", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } + "fieldName": "excludeTypes" }, { - "name": "options", + "name": "paging", "type": { - "text": "T[] | undefined" + "text": "GraphWrapperProps['paging'] | undefined" }, - "fieldName": "options", - "inheritedFrom": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } - } - ] - } - ], - "exports": [ - { - "kind": "js", - "name": "selectStyles", - "declaration": { - "name": "selectStyles", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } - }, - { - "kind": "js", - "name": "GlObjectSelect", - "declaration": { - "name": "GlObjectSelect", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } - }, - { - "kind": "js", - "name": "GlBranchThresholdFilter", - "declaration": { - "name": "GlBranchThresholdFilter", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-branch-threshold-filter", - "declaration": { - "name": "GlBranchThresholdFilter", - "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/launchpad.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlLaunchpad", - "members": [ + "fieldName": "paging" + }, { - "kind": "field", - "name": "shadowRootOptions", + "name": "loading", "type": { - "text": "ShadowRootInit" + "text": "GraphWrapperProps['loading'] | undefined" }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + "fieldName": "loading" }, { - "kind": "field", - "name": "_homeState", + "name": "selectedRows", "type": { - "text": "State" + "text": "GraphWrapperProps['selectedRows'] | undefined" }, - "privacy": "private" + "fieldName": "selectedRows" }, { - "kind": "field", - "name": "_ipc", + "name": "windowFocused", "type": { - "text": "HostIpc" + "text": "GraphWrapperProps['windowFocused'] | undefined" }, - "privacy": "private" + "fieldName": "windowFocused" }, { - "kind": "field", - "name": "_disposable", + "name": "refsMetadata", "type": { - "text": "Disposable[]" + "text": "GraphWrapperProps['refsMetadata'] | undefined" }, - "privacy": "private", - "default": "[]" + "fieldName": "refsMetadata" }, { - "kind": "field", - "name": "_summary", - "privacy": "private" + "name": "includeOnlyRefs", + "type": { + "text": "GraphWrapperProps['includeOnlyRefs'] | undefined" + }, + "fieldName": "includeOnlyRefs" }, { - "kind": "field", - "name": "_summaryState", - "privacy": "private", - "default": "new AsyncComputedState(async _abortSignal => { const rsp = await this._ipc.sendRequest(GetLaunchpadSummary, {}); return rsp; })" + "name": "rowsStats", + "type": { + "text": "GraphWrapperProps['rowsStats'] | undefined" + }, + "fieldName": "rowsStats" }, { - "kind": "field", - "name": "startWorkCommand", + "name": "rowsStatsLoading", "type": { - "text": "string" + "text": "GraphWrapperProps['rowsStatsLoading'] | undefined" }, - "readonly": true + "fieldName": "rowsStatsLoading" }, { - "kind": "field", - "name": "createBranchCommand", + "name": "workingTreeStats", "type": { - "text": "string" + "text": "GraphWrapperProps['workingTreeStats'] | undefined" }, - "readonly": true + "fieldName": "workingTreeStats" }, { - "kind": "method", - "name": "renderSummaryResult", - "privacy": "private" + "name": "theming", + "type": { + "text": "GraphWrapperProps['theming'] | undefined" + }, + "fieldName": "theming" }, { - "kind": "method", - "name": "renderPending", - "privacy": "private" + "name": "searchResults", + "type": { + "text": "GraphWrapperProps['searchResults'] | undefined" + }, + "fieldName": "searchResults" }, { - "kind": "method", - "name": "renderSummary", - "privacy": "private", - "parameters": [ - { - "name": "summary", - "type": { - "text": "LaunchpadSummary | undefined" - } - } - ] - } - ], - "mixins": [ - { - "name": "SignalWatcher", - "package": "@lit-labs/signals" + "name": "filter", + "type": { + "text": "SearchQuery" + }, + "fieldName": "filter" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-launchpad", + "tagName": "gl-graph", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlLaunchpad", + "name": "GlGraph", "declaration": { - "name": "GlLaunchpad", - "module": "src/webviews/apps/plus/home/components/launchpad.ts" + "name": "GlGraph", + "module": "src/webviews/apps/plus/graph/graph-wrapper/gl-graph.ts" } }, { "kind": "custom-element-definition", - "name": "gl-launchpad", + "name": "gl-graph", "declaration": { - "name": "GlLaunchpad", - "module": "src/webviews/apps/plus/home/components/launchpad.ts" + "name": "GlGraph", + "module": "src/webviews/apps/plus/graph/graph-wrapper/gl-graph.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/merge-target-status.ts", + "path": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlMergeTargetStatus", + "name": "GlGraphWrapper", "members": [ { "kind": "field", - "name": "shadowRootOptions", + "name": "disposables", "type": { - "text": "ShadowRootInit" + "text": "Disposable[]" }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + "privacy": "private", + "default": "[]" }, { "kind": "field", - "name": "branch", + "name": "graphState", "type": { - "text": "Pick" + "text": "typeof graphStateContext.__context__" }, - "attribute": "branch" + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "_target", + "name": "_ipc", "type": { - "text": "Awaited" + "text": "typeof ipcContext.__context__" }, - "privacy": "private" + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "target", + "name": "_telemetry", "type": { - "text": "Awaited" + "text": "TelemetryContext" }, + "privacy": "private", "readonly": true }, { "kind": "field", - "name": "_targetPromise", + "name": "graph", "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, - "privacy": "private" + "text": "typeof GlGraph" + } }, { "kind": "field", - "name": "targetPromise", + "name": "ref", "type": { - "text": "GetOverviewBranch['mergeTarget']" + "text": "GraphContainer | undefined" }, - "attribute": "targetPromise" - }, - { - "kind": "field", - "name": "conflicts", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "mergedStatus", - "privacy": "private", - "readonly": true + "privacy": "private" }, { "kind": "field", - "name": "status", - "privacy": "private", - "readonly": true + "name": "onSetRef", + "privacy": "private" }, { "kind": "field", - "name": "branchRef", + "name": "theming", "type": { - "text": "BranchRef | undefined" + "text": "GraphWrapperTheming | undefined" }, - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "targetBranchRef", - "type": { - "text": "BranchRef | undefined" - }, - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "renderContent", "privacy": "private" }, { "kind": "method", - "name": "renderHeader", - "privacy": "private", + "name": "selectCommits", "parameters": [ { - "name": "title", + "name": "shaList", "type": { - "text": "string" + "text": "string[]" } }, { - "name": "icon", + "name": "includeToPrevSel", "type": { - "text": "string" + "text": "boolean" } }, { - "name": "status", - "optional": true, + "name": "isAutoOrKeyScroll", "type": { - "text": "string" + "text": "boolean" } } ] }, { "kind": "method", - "name": "renderHeaderActions", - "privacy": "private" + "name": "onColumnsChanged", + "privacy": "private", + "parameters": [ + { + "name": "event", + "type": { + "text": "CustomEventType<'graph-changecolumns'>" + } + } + ] }, { "kind": "method", - "name": "renderInlineTargetEdit", + "name": "onGetMoreRows", "privacy": "private", "parameters": [ { - "name": "target", + "name": "{ detail: sha }", "type": { - "text": "Awaited" + "text": "CustomEventType<'graph-morerows'>" } } ] }, { "kind": "method", - "name": "renderFiles", + "name": "onMouseLeave", + "privacy": "private" + }, + { + "kind": "method", + "name": "onMissingAvatars", "privacy": "private", "parameters": [ { - "name": "files", + "name": "{ detail: emails }", "type": { - "text": "{ path: string }[]" + "text": "CustomEventType<'graph-missingavatars'>" } } ] }, { "kind": "method", - "name": "renderFile", + "name": "onMissingRefsMetadata", "privacy": "private", "parameters": [ { - "name": "path", + "name": "{ detail: metadata }", "type": { - "text": "string" + "text": "CustomEventType<'graph-missingrefsmetadata'>" } } ] - } - ], - "attributes": [ + }, { - "name": "branch", - "type": { - "text": "Pick" - }, - "fieldName": "branch" + "kind": "method", + "name": "onRefDoubleClick", + "privacy": "private", + "parameters": [ + { + "name": "{ detail: { ref, metadata } }", + "type": { + "text": "CustomEventType<'graph-doubleclickref'>" + } + } + ] }, { - "name": "targetPromise", - "type": { - "text": "GetOverviewBranch['mergeTarget']" - }, - "fieldName": "targetPromise" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-merge-target-status", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlMergeTargetUpgrade", - "members": [ + "kind": "method", + "name": "onRefsVisibilityChanged", + "privacy": "private", + "parameters": [ + { + "name": "{ detail }", + "type": { + "text": "CustomEventType<'graph-changerefsvisibility'>" + } + } + ] + }, { - "kind": "field", - "name": "shadowRootOptions", - "type": { - "text": "ShadowRootInit" - }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-merge-target-upgrade", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlMergeTargetStatus", - "declaration": { - "name": "GlMergeTargetStatus", - "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-merge-target-status", - "declaration": { - "name": "GlMergeTargetStatus", - "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" - } - }, - { - "kind": "js", - "name": "GlMergeTargetUpgrade", - "declaration": { - "name": "GlMergeTargetUpgrade", - "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-merge-target-upgrade", - "declaration": { - "name": "GlMergeTargetUpgrade", - "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/overview.ts", - "declarations": [ - { - "kind": "variable", - "name": "overviewTagName", - "type": { - "text": "string" - }, - "default": "'gl-overview'" - }, - { - "kind": "class", - "description": "", - "name": "GlOverview", - "members": [ + "kind": "method", + "name": "onRowContextMenu", + "privacy": "private", + "parameters": [ + { + "name": "{ detail: { graphRow, graphZoneType } }", + "type": { + "text": "CustomEventType<'graph-rowcontextmenu'>" + } + } + ] + }, { - "kind": "field", - "name": "_homeState", - "type": { - "text": "State" - }, - "privacy": "private" + "kind": "method", + "name": "onRowDoubleClick", + "privacy": "private", + "parameters": [ + { + "name": "{ detail: { row, preserveFocus } }", + "type": { + "text": "CustomEventType<'graph-doubleclickrow'>" + } + } + ] }, { - "kind": "field", - "name": "_inactiveOverviewState", - "type": { - "text": "InactiveOverviewState" - }, - "privacy": "private" + "kind": "method", + "name": "onRowHover", + "privacy": "private", + "parameters": [ + { + "name": "{ detail }", + "type": { + "text": "CustomEventType<'graph-graphrowhovered'>" + } + } + ] }, { "kind": "method", - "name": "renderLoader", - "privacy": "private" + "name": "onRowUnhover", + "privacy": "private", + "parameters": [ + { + "name": "{ detail }", + "type": { + "text": "CustomEventType<'graph-graphrowunhovered'>" + } + } + ] }, { "kind": "method", - "name": "renderPending", - "privacy": "private" + "name": "onSelectionChanged", + "privacy": "private", + "parameters": [ + { + "name": "{ detail: rows }", + "type": { + "text": "CustomEventType<'graph-changeselection'>" + } + } + ] }, { - "kind": "field", - "name": "_ipc", - "type": { - "text": "HostIpc" - }, + "kind": "method", + "name": "onVisibleDaysChanged", "privacy": "private", - "readonly": true + "parameters": [ + { + "name": "{ detail }", + "type": { + "text": "CustomEventType<'graph-changevisibledays'>" + } + } + ] }, { "kind": "field", - "name": "onChangeRecentThresholdFilter", + "name": "themingDefaults", + "type": { + "text": "{ cssVariables: CssVariables; themeOpacityFactor: number }" + }, "privacy": "private", - "readonly": true + "readonly": true, + "default": "{ cssVariables: (() => { const bgColor = getCssVariableValue('--color-background'); const mixedGraphColors: CssVariables = {}; let i = 0; let color; for (const [colorVar, colorDefault] of graphLaneThemeColors) { color = getCssVariableValue(colorVar, { fallbackValue: colorDefault }); mixedGraphColors[`--graph-color-${i}`] = color; for (const mixInt of [15, 25, 45, 50]) { mixedGraphColors[`--graph-color-${i}-bg${mixInt}`] = getCssMixedColorValue(bgColor, color, mixInt); } for (const mixInt of [10, 50]) { mixedGraphColors[`--graph-color-${i}-f${mixInt}`] = getCssOpacityColorValue(color, mixInt); } i++; } return { '--app__bg0': getCssVariableValue('--color-background'), '--panel__bg0': getCssVariableValue('--color-graph-background'), '--panel__bg1': getCssVariableValue('--color-graph-background2'), '--section-border': getCssVariableValue('--color-graph-background2'), '--selected-row': getCssVariableValue('--color-graph-selected-row'), '--selected-row-border': 'none', '--hover-row': getCssVariableValue('--color-graph-hover-row'), '--hover-row-border': 'none', '--scrollable-scrollbar-thickness': getCssVariableValue('--graph-column-scrollbar-thickness'), '--scroll-thumb-bg': getCssVariableValue('--vscode-scrollbarSlider-background'), '--scroll-marker-head-color': getCssVariableValue('--color-graph-scroll-marker-head'), '--scroll-marker-upstream-color': getCssVariableValue('--color-graph-scroll-marker-upstream'), '--scroll-marker-highlights-color': getCssVariableValue('--color-graph-scroll-marker-highlights'), '--scroll-marker-local-branches-color': getCssVariableValue( '--color-graph-scroll-marker-local-branches', ), '--scroll-marker-remote-branches-color': getCssVariableValue( '--color-graph-scroll-marker-remote-branches', ), '--scroll-marker-stashes-color': getCssVariableValue('--color-graph-scroll-marker-stashes'), '--scroll-marker-tags-color': getCssVariableValue('--color-graph-scroll-marker-tags'), '--scroll-marker-selection-color': getCssVariableValue('--color-graph-scroll-marker-selection'), '--scroll-marker-pull-requests-color': getCssVariableValue('--color-graph-scroll-marker-pull-requests'), '--stats-added-color': getCssVariableValue('--color-graph-stats-added'), '--stats-deleted-color': getCssVariableValue('--color-graph-stats-deleted'), '--stats-files-color': getCssVariableValue('--color-graph-stats-files'), '--stats-bar-border-radius': getCssVariableValue('--graph-stats-bar-border-radius'), '--stats-bar-height': getCssVariableValue('--graph-stats-bar-height'), '--text-selected': getCssVariableValue('--color-graph-text-selected'), '--text-selected-row': getCssVariableValue('--color-graph-text-selected-row'), '--text-hovered': getCssVariableValue('--color-graph-text-hovered'), '--text-dimmed-selected': getCssVariableValue('--color-graph-text-dimmed-selected'), '--text-dimmed': getCssVariableValue('--color-graph-text-dimmed'), '--text-normal': getCssVariableValue('--color-graph-text-normal'), '--text-secondary': getCssVariableValue('--color-graph-text-secondary'), '--text-disabled': getCssVariableValue('--color-graph-text-disabled'), '--text-accent': getCssVariableValue('--color-link-foreground'), '--text-inverse': getCssVariableValue('--vscode-input-background'), '--text-bright': getCssVariableValue('--vscode-input-background'), ...mixedGraphColors, }; })(), themeOpacityFactor: 1, }" }, { "kind": "method", - "name": "renderComplete", + "name": "getGraphTheming", "privacy": "private", + "return": { + "type": { + "text": "GraphWrapperTheming" + } + }, "parameters": [ { - "name": "overview", + "name": "e", + "optional": true, "type": { - "text": "GetInactiveOverviewResponse" + "text": "ThemeChangeEvent" } - }, - { - "name": "isFetching", - "default": "false" } ] } ], + "events": [ + { + "name": "gl-graph-mouse-leave", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-graph-row-context-menu", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-graph-row-hover", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-graph-row-unhover", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-graph-change-selection", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-graph-change-visible-days", + "type": { + "text": "CustomEvent" + } + } + ], "mixins": [ { "name": "SignalWatcher", @@ -20859,983 +20882,1179 @@ "name": "LitElement", "package": "lit" }, + "tagName": "gl-graph-wrapper", "customElement": true } ], "exports": [ { "kind": "js", - "name": "overviewTagName", - "declaration": { - "name": "overviewTagName", - "module": "src/webviews/apps/plus/home/components/overview.ts" - } - }, - { - "kind": "js", - "name": "GlOverview", + "name": "GlGraphWrapper", "declaration": { - "name": "GlOverview", - "module": "src/webviews/apps/plus/home/components/overview.ts" + "name": "GlGraphWrapper", + "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts" } }, { "kind": "custom-element-definition", + "name": "gl-graph-wrapper", "declaration": { - "name": "GlOverview", - "module": "src/webviews/apps/plus/home/components/overview.ts" + "name": "GlGraphWrapper", + "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/home/components/overviewState.ts", + "path": "src/webviews/apps/plus/graph/hover/graphHover.ts", "declarations": [ { "kind": "class", "description": "", - "name": "ActiveOverviewState", + "name": "GlGraphHover", "members": [ { "kind": "field", - "name": "_disposable", + "name": "anchor", "type": { - "text": "Disposable | undefined" + "text": "Anchor | undefined" }, - "privacy": "private", - "readonly": true + "attribute": "anchor" }, { - "kind": "method", - "name": "dispose" + "kind": "field", + "name": "distance", + "type": { + "text": "number | undefined | undefined" + }, + "attribute": "distance", + "reflects": true }, { - "kind": "method", - "name": "changeRepository", - "return": { - "type": { - "text": "void" - } - } + "kind": "field", + "name": "open", + "type": { + "text": "boolean | undefined" + }, + "default": "false", + "attribute": "open", + "reflects": true }, { "kind": "field", - "name": "_debounce", + "name": "placement", "type": { - "text": "number" + "text": "GlPopover['placement'] | undefined" }, - "privacy": "private", - "default": "500", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "default": "'bottom-start'", + "attribute": "placement", + "reflects": true }, { "kind": "field", - "name": "_invalidate", - "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "name": "markdown", + "type": { + "text": "Promise> | string | undefined" + }, + "attribute": "markdown" }, { "kind": "field", - "name": "_computed", + "name": "skidding", "type": { - "text": "AsyncComputed | undefined" + "text": "number | undefined | undefined" }, - "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "attribute": "skidding", + "reflects": true + }, + { + "kind": "field", + "name": "requestMarkdown", + "type": { + "text": "((row: GraphRow) => Promise) | undefined" + }, + "attribute": "requestMarkdown" + }, + { + "kind": "field", + "name": "popup", + "type": { + "text": "GlPopover" } }, { "kind": "field", - "name": "_state", + "name": "hoverMarkdownCache", "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "default": "new Map< string, Promise> | PromiseSettledResult | string >()" }, { "kind": "field", - "name": "state", + "name": "shaHovering", "type": { - "text": "T | undefined" + "text": "string | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "privacy": "private" }, { "kind": "field", - "name": "computed", + "name": "unhoverTimer", "type": { - "text": "AsyncComputed" + "text": "ReturnType | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "privacy": "private" }, { - "kind": "method", - "name": "_runCore", - "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "kind": "field", + "name": "previousSkidding", + "type": { + "text": "number | undefined" + }, + "privacy": "private" }, { "kind": "field", - "name": "_runDebounced", + "name": "recalculated", "type": { - "text": "Deferrable<() => void> | undefined" + "text": "boolean" }, "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "default": "false" }, { "kind": "method", - "name": "_run", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "immediate", - "default": "false" - } - ], - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "name": "onReposition", + "privacy": "private" }, { "kind": "method", - "name": "run", + "name": "reset", "return": { "type": { "text": "void" } - }, - "parameters": [ - { - "name": "force", - "default": "false" - } - ], - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" } }, { - "kind": "method", - "name": "invalidate", - "return": { - "type": { - "text": "void" - } - }, - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } - } - ], - "superclass": { - "name": "AsyncComputedState", - "module": "/src/webviews/apps/shared/components/signal-utils" - } - }, - { - "kind": "class", - "description": "", - "name": "InactiveOverviewState", - "members": [ + "kind": "field", + "name": "onParentMouseLeave", + "privacy": "private" + }, { "kind": "field", - "name": "_disposable", + "name": "onPopoverMouseLeave", + "privacy": "private" + }, + { + "kind": "field", + "name": "_showCoreDebounced", "type": { - "text": "Disposable | undefined" + "text": "Deferrable | undefined" }, "privacy": "private", - "readonly": true + "default": "undefined" }, { - "kind": "field", - "name": "filter" + "kind": "method", + "name": "onRowHovered", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "row", + "type": { + "text": "GraphRow" + } + }, + { + "name": "anchor", + "type": { + "text": "Anchor" + } + } + ] }, { "kind": "method", - "name": "dispose", + "name": "onRowUnhovered", "return": { "type": { "text": "void" } - } + }, + "parameters": [ + { + "name": "_row", + "type": { + "text": "GraphRow" + } + }, + { + "name": "relatedTarget", + "type": { + "text": "EventTarget | null" + } + } + ] }, { "kind": "field", - "name": "_debounce", - "type": { - "text": "number" - }, - "privacy": "private", - "default": "500", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "name": "onWindowKeydown", + "privacy": "private" }, { - "kind": "field", - "name": "_invalidate", + "kind": "method", + "name": "showCore", "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "parameters": [ + { + "name": "anchor", + "type": { + "text": "string | HTMLElement | { getBoundingClientRect: () => Omit }" + } + }, + { + "name": "markdown", + "type": { + "text": "Promise> | PromiseSettledResult | string" + } + } + ] }, { "kind": "field", - "name": "_computed", + "name": "_lastUnhoveredTimestamp", "type": { - "text": "AsyncComputed | undefined" + "text": "number" }, "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "default": "0" + }, + { + "kind": "method", + "name": "hide", + "return": { + "type": { + "text": "void" + } } }, { - "kind": "field", - "name": "_state", + "kind": "method", + "name": "resetUnhoverTimer", "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "return": { + "type": { + "text": "void" + } } }, { - "kind": "field", - "name": "state", - "type": { - "text": "T | undefined" + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } }, - "readonly": true, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" } + } + ], + "attributes": [ + { + "name": "anchor", + "type": { + "text": "Anchor | undefined" + }, + "fieldName": "anchor" }, { - "kind": "field", - "name": "computed", + "name": "distance", "type": { - "text": "AsyncComputed" + "text": "number | undefined | undefined" }, - "readonly": true, - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "fieldName": "distance" }, { - "kind": "method", - "name": "_runCore", - "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "name": "open", + "type": { + "text": "boolean | undefined" + }, + "default": "false", + "fieldName": "open" }, { - "kind": "field", - "name": "_runDebounced", + "name": "placement", "type": { - "text": "Deferrable<() => void> | undefined" + "text": "GlPopover['placement'] | undefined" }, - "privacy": "private", - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "default": "'bottom-start'", + "fieldName": "placement" }, { - "kind": "method", - "name": "_run", - "privacy": "protected", - "return": { - "type": { - "text": "void" - } + "name": "markdown", + "type": { + "text": "Promise> | string | undefined" }, - "parameters": [ - { - "name": "immediate", - "default": "false" - } - ], - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "fieldName": "markdown" }, { - "kind": "method", - "name": "run", - "return": { - "type": { - "text": "void" - } + "name": "skidding", + "type": { + "text": "number | undefined | undefined" }, - "parameters": [ - { - "name": "force", - "default": "false" - } - ], - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "fieldName": "skidding" }, { - "kind": "method", - "name": "invalidate", - "return": { - "type": { - "text": "void" - } + "name": "requestMarkdown", + "type": { + "text": "((row: GraphRow) => Promise) | undefined" }, - "inheritedFrom": { - "name": "AsyncComputedState", - "module": "src/webviews/apps/shared/components/signal-utils.ts" - } + "fieldName": "requestMarkdown" } ], "superclass": { - "name": "AsyncComputedState", - "module": "/src/webviews/apps/shared/components/signal-utils" - } - }, - { - "kind": "variable", - "name": "activeOverviewStateContext" - }, - { - "kind": "variable", - "name": "inactiveOverviewStateContext" + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + }, + "tagName": "gl-graph-hover", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "ActiveOverviewState", - "declaration": { - "name": "ActiveOverviewState", - "module": "src/webviews/apps/plus/home/components/overviewState.ts" - } - }, - { - "kind": "js", - "name": "InactiveOverviewState", - "declaration": { - "name": "InactiveOverviewState", - "module": "src/webviews/apps/plus/home/components/overviewState.ts" - } - }, - { - "kind": "js", - "name": "activeOverviewStateContext", + "name": "GlGraphHover", "declaration": { - "name": "activeOverviewStateContext", - "module": "src/webviews/apps/plus/home/components/overviewState.ts" + "name": "GlGraphHover", + "module": "src/webviews/apps/plus/graph/hover/graphHover.ts" } }, { - "kind": "js", - "name": "inactiveOverviewStateContext", + "kind": "custom-element-definition", + "name": "gl-graph-hover", "declaration": { - "name": "inactiveOverviewStateContext", - "module": "src/webviews/apps/plus/home/components/overviewState.ts" + "name": "GlGraphHover", + "module": "src/webviews/apps/plus/graph/hover/graphHover.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/account-chip.ts", + "path": "src/webviews/apps/plus/graph/minimap/minimap-container.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlAccountChip", + "name": "GlGraphMinimapContainer", "members": [ { "kind": "field", - "name": "shadowRootOptions", + "name": "activeDay", "type": { - "text": "ShadowRootInit" + "text": "number | undefined" }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + "attribute": "activeDay" }, { "kind": "field", - "name": "_showUpgrade", + "name": "disabled", "type": { "text": "boolean" }, - "privacy": "private", - "default": "false" + "default": "false", + "attribute": "disabled" }, { - "kind": "field", - "name": "showUpgrade", - "privacy": "private", - "attribute": "show-upgrade", - "reflects": true + "kind": "method", + "name": "onDisabledChanged", + "privacy": "private" }, { "kind": "field", - "name": "_chip", + "name": "dataType", "type": { - "text": "HTMLElement" + "text": "'commits' | 'lines'" }, - "privacy": "private" + "default": "'commits'", + "attribute": "dataType" }, { "kind": "field", - "name": "_popover", + "name": "downstreams", "type": { - "text": "GlPopover" + "text": "GraphDownstreams | undefined" }, - "privacy": "private" + "attribute": "downstreams" }, { "kind": "field", - "name": "_state", + "name": "markerTypes", "type": { - "text": "State" + "text": "GraphMinimapMarkerTypes[]" }, - "privacy": "private" - }, - { - "kind": "field", - "name": "accountAvatar", - "privacy": "private", - "readonly": true + "default": "[]", + "attribute": "markerTypes" }, { "kind": "field", - "name": "accountName", - "privacy": "private", - "readonly": true + "name": "refMetadata", + "type": { + "text": "GraphRefsMetadata | null | undefined" + }, + "attribute": "refMetadata" }, { "kind": "field", - "name": "accountEmail", - "privacy": "private", - "readonly": true + "name": "rows", + "type": { + "text": "GraphRow[]" + }, + "default": "[]", + "attribute": "rows" }, { "kind": "field", - "name": "hasAccount", - "privacy": "private", - "readonly": true + "name": "rowsStats", + "type": { + "text": "Record | undefined" + }, + "attribute": "rowsStats" }, { "kind": "field", - "name": "isReactivatedTrial", + "name": "searchResults", "type": { - "text": "boolean" + "text": "GraphSearchResults | GraphSearchResultsError | undefined" }, - "readonly": true + "attribute": "searchResults" }, { "kind": "field", - "name": "planId", - "privacy": "private", - "readonly": true + "name": "visibleDays", + "type": { + "text": "{ top: number; bottom: number } | undefined" + }, + "attribute": "visibleDays" }, { "kind": "field", - "name": "effectivePlanId", + "name": "markersByDay", "privacy": "private", - "readonly": true + "default": "new Map()" }, { "kind": "field", - "name": "planName", + "name": "searchResultsByDay", "privacy": "private", - "readonly": true + "default": "new Map()" }, { "kind": "field", - "name": "planTier", + "name": "statsByDay", "privacy": "private", - "readonly": true + "default": "new Map()" }, { "kind": "field", - "name": "promos", + "name": "pendingDataChange", "type": { - "text": "PromosContext" + "text": "boolean" }, - "privacy": "private" + "privacy": "private", + "default": "false" }, { - "kind": "field", - "name": "subscription", + "kind": "method", + "name": "handleDataChanged", "privacy": "private", - "readonly": true + "parameters": [ + { + "name": "changedKeys", + "type": { + "text": "PropertyKey[]" + } + } + ] }, { "kind": "field", - "name": "subscriptionState", + "name": "pendingSearchResultsChange", + "type": { + "text": "boolean" + }, "privacy": "private", - "readonly": true + "default": "false" + }, + { + "kind": "method", + "name": "handleSearchResultsChanged", + "privacy": "private" }, { "kind": "field", - "name": "trialDaysRemaining", - "privacy": "private", - "readonly": true + "name": "minimap", + "type": { + "text": "GlGraphMinimap | undefined" + }, + "privacy": "private" }, { "kind": "method", - "name": "focus", + "name": "select", "return": { "type": { "text": "void" } - } + }, + "parameters": [ + { + "name": "date", + "type": { + "text": "number | Date | undefined" + } + }, + { + "name": "trackOnly", + "default": "false", + "type": { + "text": "boolean" + } + } + ] }, { "kind": "method", - "name": "show", + "name": "unselect", "return": { "type": { "text": "void" } - } - }, - { - "kind": "method", - "name": "renderAccountInfo", - "privacy": "private" + }, + "parameters": [ + { + "name": "date", + "optional": true, + "type": { + "text": "number | Date" + } + }, + { + "name": "focus", + "default": "false", + "type": { + "text": "boolean" + } + } + ] }, { "kind": "method", - "name": "renderAccountState", + "name": "processRows", "privacy": "private" }, { "kind": "method", - "name": "renderIncludesDevEx", + "name": "processSearchResults", "privacy": "private" }, { "kind": "method", - "name": "renderReferFriend", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderUpgradeContent", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderPromo", - "privacy": "private", + "name": "emit", "return": { "type": { - "text": "unknown" + "text": "CustomEventType" } }, "parameters": [ { - "name": "plan", + "name": "name", "type": { - "text": "PromoPlans" + "text": "T" } }, { - "name": "type", - "default": "'info'", + "name": "detail", "type": { - "text": "GlPromo['type']" + "text": "CustomEventDetailType" } }, { - "name": "slot", + "name": "options", "optional": true, "type": { - "text": "string" + "text": "Omit>, 'detail'>" } } - ] + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } } ], "attributes": [ { - "name": "show-upgrade", - "fieldName": "showUpgrade" + "name": "activeDay", + "type": { + "text": "number | undefined" + }, + "fieldName": "activeDay" + }, + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "dataType", + "type": { + "text": "'commits' | 'lines'" + }, + "default": "'commits'", + "fieldName": "dataType" + }, + { + "name": "downstreams", + "type": { + "text": "GraphDownstreams | undefined" + }, + "fieldName": "downstreams" + }, + { + "name": "markerTypes", + "type": { + "text": "GraphMinimapMarkerTypes[]" + }, + "default": "[]", + "fieldName": "markerTypes" + }, + { + "name": "refMetadata", + "type": { + "text": "GraphRefsMetadata | null | undefined" + }, + "fieldName": "refMetadata" + }, + { + "name": "rows", + "type": { + "text": "GraphRow[]" + }, + "default": "[]", + "fieldName": "rows" + }, + { + "name": "rowsStats", + "type": { + "text": "Record | undefined" + }, + "fieldName": "rowsStats" + }, + { + "name": "searchResults", + "type": { + "text": "GraphSearchResults | GraphSearchResultsError | undefined" + }, + "fieldName": "searchResults" + }, + { + "name": "visibleDays", + "type": { + "text": "{ top: number; bottom: number } | undefined" + }, + "fieldName": "visibleDays" } ], "superclass": { - "name": "LitElement", - "package": "lit" + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" }, - "tagName": "gl-account-chip", + "tagName": "gl-graph-minimap-container", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlAccountChip", + "name": "GlGraphMinimapContainer", "declaration": { - "name": "GlAccountChip", - "module": "src/webviews/apps/plus/shared/components/account-chip.ts" + "name": "GlGraphMinimapContainer", + "module": "src/webviews/apps/plus/graph/minimap/minimap-container.ts" } }, { "kind": "custom-element-definition", - "name": "gl-account-chip", - "declaration": { - "name": "GlAccountChip", - "module": "src/webviews/apps/plus/shared/components/account-chip.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/chipStyles.ts", - "declarations": [ - { - "kind": "variable", - "name": "chipStyles", - "default": "css` :host { display: flex; } .chip { display: flex; gap: 0.6rem; align-items: center; border-radius: 0.3rem; padding: 0.2rem 0.4rem; cursor: pointer; } .chip:focus-visible { ${focusOutline} } .content { display: flex; flex-direction: column; gap: 0.4rem; padding-bottom: 0.4rem; } .header { display: flex; align-items: center; gap: 0.6rem; width: 100%; padding-bottom: 0.4rem; } .header__actions { flex: none; display: flex; gap: 0.2rem; flex-direction: row; align-items: center; justify-content: center; } .header__title { flex: 1; font-size: 1.5rem; line-height: 1.7; font-weight: 600; margin: 0; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "chipStyles", + "name": "gl-graph-minimap-container", "declaration": { - "name": "chipStyles", - "module": "src/webviews/apps/plus/shared/components/chipStyles.ts" + "name": "GlGraphMinimapContainer", + "module": "src/webviews/apps/plus/graph/minimap/minimap-container.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts", + "path": "src/webviews/apps/plus/graph/minimap/minimap.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlFeatureGatePlusState", + "name": "GlGraphMinimap", "members": [ { "kind": "field", - "name": "button", + "name": "chartContainer", "type": { - "text": "GlButton" + "text": "HTMLDivElement" + } + }, + { + "kind": "field", + "name": "_chart", + "type": { + "text": "Chart" }, - "privacy": "private", - "readonly": true + "privacy": "private" }, { "kind": "field", - "name": "featurePreview", + "name": "spinner", "type": { - "text": "FeaturePreview | undefined" + "text": "HTMLDivElement" + } + }, + { + "kind": "field", + "name": "_loadTimer", + "type": { + "text": "ReturnType | undefined" }, - "attribute": "featurePreview" + "privacy": "private" }, { "kind": "field", - "name": "featurePreviewCommandLink", + "name": "_markerRegions", "type": { - "text": "string | undefined" + "text": "Iterable | undefined" }, - "attribute": "featurePreviewCommandLink" + "privacy": "private" }, { "kind": "field", - "name": "appearance", + "name": "_regions", "type": { - "text": "'alert' | 'welcome' | undefined" + "text": "RegionOptions[] | undefined" }, - "attribute": "appearance" + "privacy": "private" }, { "kind": "field", - "name": "featureWithArticleIfNeeded", + "name": "activeDay", "type": { - "text": "string | undefined" + "text": "number | undefined" }, - "attribute": "featureWithArticleIfNeeded" + "attribute": "activeDay" + }, + { + "kind": "method", + "name": "onActiveDayChanged", + "privacy": "private" }, { "kind": "field", - "name": "promos", + "name": "data", "type": { - "text": "PromosContext" + "text": "Map | undefined" + }, + "attribute": "data" + }, + { + "kind": "field", + "name": "dataType", + "type": { + "text": "'commits' | 'lines'" }, + "default": "'commits'", + "attribute": "dataType" + }, + { + "kind": "method", + "name": "onDataChanged", "privacy": "private" }, { "kind": "field", - "name": "source", + "name": "markers", "type": { - "text": "Source | undefined" + "text": "Map | undefined" }, - "attribute": "source" + "attribute": "markers" + }, + { + "kind": "method", + "name": "onMarkersChanged", + "privacy": "private" }, { "kind": "field", - "name": "state", + "name": "searchResults", "type": { - "text": "SubscriptionState | undefined" - } + "text": "Map | undefined" + }, + "attribute": "searchResults" + }, + { + "kind": "method", + "name": "onSearchResultsChanged", + "privacy": "private" }, { "kind": "field", - "name": "webroot", + "name": "visibleDays", "type": { - "text": "string | undefined" + "text": "{ top: number; bottom: number } | undefined" }, - "attribute": "webroot" + "attribute": "visibleDays" }, { "kind": "method", - "name": "renderFeaturePreview", + "name": "onVisibleDaysChanged", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleDataChanged", "privacy": "private", "parameters": [ { - "name": "featurePreview", + "name": "markerChanged", "type": { - "text": "FeaturePreview" + "text": "boolean" } } ] }, { "kind": "method", - "name": "renderFeaturePreviewStep", + "name": "getInternalChart", "privacy": "private", + "return": { + "type": { + "text": "ChartInternal | undefined" + } + } + }, + { + "kind": "method", + "name": "select", + "return": { + "type": { + "text": "void" + } + }, "parameters": [ { - "name": "featurePreview", + "name": "date", "type": { - "text": "FeaturePreview" + "text": "number | Date | undefined" } }, { - "name": "used", + "name": "trackOnly", + "default": "false", "type": { - "text": "number" + "text": "boolean" } } ] }, { "kind": "method", - "name": "renderPromo", + "name": "unselect", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "date", + "optional": true, + "type": { + "text": "number | Date" + } + }, + { + "name": "focus", + "default": "false", + "type": { + "text": "boolean" + } + } + ] + }, + { + "kind": "method", + "name": "getDataPoint", + "privacy": "private", + "return": { + "type": { + "text": "DataItem | undefined" + } + }, + "parameters": [ + { + "name": "date", + "type": { + "text": "number | Date" + } + } + ] + }, + { + "kind": "method", + "name": "getIndex", + "privacy": "private", + "return": { + "type": { + "text": "number | undefined" + } + }, + "parameters": [ + { + "name": "date", + "type": { + "text": "number | Date" + } + } + ] + }, + { + "kind": "method", + "name": "getMarkerRegions", + "privacy": "private" + }, + { + "kind": "method", + "name": "getAllRegions", + "privacy": "private" + }, + { + "kind": "method", + "name": "getSearchResultsRegions", + "privacy": "private", + "return": { + "type": { + "text": "Iterable" + } + }, + "parameters": [ + { + "name": "searchResults", + "type": { + "text": "NonNullable" + } + } + ] + }, + { + "kind": "method", + "name": "getVisibleAreaRegion", + "privacy": "private", + "return": { + "type": { + "text": "RegionOptions" + } + }, + "parameters": [ + { + "name": "visibleDays", + "type": { + "text": "NonNullable" + } + } + ] + }, + { + "kind": "field", + "name": "_loading", + "type": { + "text": "Promise | undefined" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "loadChart", + "privacy": "private" + }, + { + "kind": "method", + "name": "loadChartCore", "privacy": "private" + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } } ], "attributes": [ { - "name": "featurePreview", + "name": "activeDay", "type": { - "text": "FeaturePreview | undefined" + "text": "number | undefined" }, - "fieldName": "featurePreview" + "fieldName": "activeDay" }, { - "name": "featurePreviewCommandLink", + "name": "data", "type": { - "text": "string | undefined" + "text": "Map | undefined" }, - "fieldName": "featurePreviewCommandLink" + "fieldName": "data" }, { - "name": "appearance", + "name": "dataType", "type": { - "text": "'alert' | 'welcome' | undefined" + "text": "'commits' | 'lines'" }, - "fieldName": "appearance" + "default": "'commits'", + "fieldName": "dataType" }, { - "name": "featureWithArticleIfNeeded", + "name": "markers", "type": { - "text": "string | undefined" + "text": "Map | undefined" }, - "fieldName": "featureWithArticleIfNeeded" + "fieldName": "markers" }, { - "name": "source", + "name": "searchResults", "type": { - "text": "Source | undefined" + "text": "Map | undefined" }, - "fieldName": "source" + "fieldName": "searchResults" }, { - "name": "webroot", + "name": "visibleDays", "type": { - "text": "string | undefined" + "text": "{ top: number; bottom: number } | undefined" }, - "fieldName": "webroot" + "fieldName": "visibleDays" } ], "superclass": { - "name": "LitElement", - "package": "lit" + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" }, - "tagName": "gl-feature-gate-plus-state", + "tagName": "gl-graph-minimap", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlFeatureGatePlusState", + "name": "GlGraphMinimap", "declaration": { - "name": "GlFeatureGatePlusState", - "module": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts" + "name": "GlGraphMinimap", + "module": "src/webviews/apps/plus/graph/minimap/minimap.ts" } }, { "kind": "custom-element-definition", - "name": "gl-feature-gate-plus-state", + "name": "gl-graph-minimap", "declaration": { - "name": "GlFeatureGatePlusState", - "module": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts" + "name": "GlGraphMinimap", + "module": "src/webviews/apps/plus/graph/minimap/minimap.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/home-header.ts", + "path": "src/webviews/apps/plus/graph/sidebar/sidebar.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlHomeHeader", + "name": "GlGraphSideBar", "members": [ { "kind": "field", - "name": "accountChip", + "name": "include", "type": { - "text": "GlAccountChip" + "text": "undefined | IconTypes[]" }, - "privacy": "private" + "readonly": true }, { "kind": "field", - "name": "promoBanner", + "name": "_ipc", "type": { - "text": "GlPromoBanner" - }, - "privacy": "private" - }, - { - "kind": "method", - "name": "show", - "return": { - "type": { - "text": "void" - } - } - }, - { - "kind": "method", - "name": "refreshPromo", - "return": { - "type": { - "text": "void" - } - } - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-home-header", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlHomeHeader", - "declaration": { - "name": "GlHomeHeader", - "module": "src/webviews/apps/plus/shared/components/home-header.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-home-header", - "declaration": { - "name": "GlHomeHeader", - "module": "src/webviews/apps/plus/shared/components/home-header.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/integrations-chip.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlIntegrationsChip", - "members": [ - { - "kind": "field", - "name": "shadowRootOptions", - "type": { - "text": "ShadowRootInit" - }, - "static": true, - "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" - }, - { - "kind": "field", - "name": "_chip", - "type": { - "text": "HTMLElement" + "text": "HostIpc" }, "privacy": "private" }, @@ -21843,2074 +22062,6960 @@ "kind": "field", "name": "_state", "type": { - "text": "State" + "text": "typeof graphStateContext.__context__" }, - "privacy": "private" - }, - { - "kind": "field", - "name": "hasAccount", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "isPaidAccount", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "isProAccount", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "hasConnectedIntegrations", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "ai", - "privacy": "private", - "readonly": true - }, - { - "kind": "field", - "name": "aiSettingEnabled", "privacy": "private", "readonly": true }, { "kind": "field", - "name": "aiOrgEnabled", - "privacy": "private", - "readonly": true + "name": "_disposable", + "type": { + "text": "Disposable | undefined" + }, + "privacy": "private" }, { "kind": "field", - "name": "aiEnabled", + "name": "_countsTask", "privacy": "private", - "readonly": true + "default": "new Task(this, { args: () => [this.fetchCounts()], task: ([counts]) => counts, autoRun: false, })" }, { "kind": "field", - "name": "integrations", - "privacy": "private", - "readonly": true + "name": "_counts", + "type": { + "text": "Promise | undefined" + }, + "privacy": "private" }, { "kind": "method", - "name": "focus", - "return": { - "type": { - "text": "void" - } - } + "name": "fetchCounts", + "privacy": "private" }, { "kind": "method", - "name": "renderIntegrationStatus", + "name": "renderIcon", "privacy": "private", "parameters": [ { - "name": "integration", + "name": "icon", "type": { - "text": "IntegrationState" + "text": "Icon" } } ] }, { "kind": "method", - "name": "renderIntegrationRow", + "name": "sendTelemetry", "privacy": "private", "parameters": [ { - "name": "integration", + "name": "command", "type": { - "text": "IntegrationState" + "text": "string" } } ] - }, - { - "kind": "method", - "name": "renderAIStatus", - "privacy": "private" - }, + } + ], + "mixins": [ { - "kind": "method", - "name": "renderAIRow", - "privacy": "private" + "name": "SignalWatcher", + "package": "@lit-labs/signals" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-integrations-chip", + "tagName": "gl-graph-sidebar", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlIntegrationsChip", + "name": "GlGraphSideBar", "declaration": { - "name": "GlIntegrationsChip", - "module": "src/webviews/apps/plus/shared/components/integrations-chip.ts" + "name": "GlGraphSideBar", + "module": "src/webviews/apps/plus/graph/sidebar/sidebar.ts" } }, { "kind": "custom-element-definition", - "name": "gl-integrations-chip", + "name": "gl-graph-sidebar", "declaration": { - "name": "GlIntegrationsChip", - "module": "src/webviews/apps/plus/shared/components/integrations-chip.ts" + "name": "GlGraphSideBar", + "module": "src/webviews/apps/plus/graph/sidebar/sidebar.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts", + "path": "src/webviews/apps/plus/graph/styles/graph.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "linkBase", + "default": "css` a { text-decoration: none; } a:focus { ${focusOutline} } a:hover { text-decoration: underline; } `" + }, + { + "kind": "variable", + "name": "actionButton", + "default": "css` .action-button { position: relative; appearance: none; font-family: inherit; font-size: 1.2rem; line-height: 2.2rem; // background-color: var(--color-graph-actionbar-background); background-color: transparent; border: none; color: inherit; color: var(--color-foreground); padding: 0 0.75rem; cursor: pointer; border-radius: 3px; height: auto; display: grid; grid-auto-flow: column; grid-gap: 0.5rem; gap: 0.5rem; max-width: fit-content; } .action-button[disabled] { pointer-events: none; cursor: default; opacity: 1; } .action-button:hover { background-color: var(--color-graph-actionbar-selectedBackground); color: var(--color-foreground); text-decoration: none; } .action-button[aria-checked] { border: 1px solid transparent; } .action-button[aria-checked='true'] { background-color: var(--vscode-inputOption-activeBackground); color: var(--vscode-inputOption-activeForeground); border-color: var(--vscode-inputOption-activeBorder); } .action-button code-icon { line-height: 2.2rem; vertical-align: bottom; } .action-button code-icon[icon='graph-line'] { transform: translateY(1px); } .is-ahead .action-button__pill { background-color: var(--branch-status-ahead-pill-background); } .is-behind .action-button__pill { background-color: var(--branch-status-behind-pill-background); } .is-ahead.is-behind .action-button__pill { background-color: var(--branch-status-both-pill-background); } .action-button__more, .action-button__more.codicon[class*='codicon-'] { font-size: 1rem; margin-right: -0.25rem; } code-icon.action-button__more::before { margin-left: -0.25rem; } .action-button__indicator { margin-left: -0.2rem; --gl-indicator-color: green; --gl-indicator-size: 0.4rem; } .action-button__small { font-size: smaller; opacity: 0.6; text-overflow: ellipsis; overflow: hidden; } .action-button.is-ahead { background-color: var(--branch-status-ahead-background); } .action-button.is-ahead:hover { background-color: var(--branch-status-ahead-hover-background); } .action-button.is-behind { background-color: var(--branch-status-behind-background); } .action-button.is-behind:hover { background-color: var(--branch-status-behind-hover-background); } .action-button.is-ahead.is-behind { background-color: var(--branch-status-both-background); } .action-button.is-ahead.is-behind:hover { background-color: var(--branch-status-both-hover-background); } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "linkBase", + "declaration": { + "name": "linkBase", + "module": "src/webviews/apps/plus/graph/styles/graph.css.ts" + } + }, + { + "kind": "js", + "name": "actionButton", + "declaration": { + "name": "actionButton", + "module": "src/webviews/apps/plus/graph/styles/graph.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/graph/styles/header.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "repoHeaderStyles", + "default": "css` .jump-to-ref { --button-foreground: var(--color-foreground); } .merge-conflict-warning { flex: 0 0 100%; min-width: 0; } `" + }, + { + "kind": "variable", + "name": "progressStyles", + "default": "css` .progress-container { position: absolute; left: 0; bottom: 0; z-index: 5; height: 2px; width: 100%; overflow: hidden; } .progress-container .progress-bar { background-color: var(--vscode-progressBar-background); display: none; position: absolute; left: 0; width: 2%; height: 2px; } .progress-container.active .progress-bar { display: inherit; } .progress-container.discrete .progress-bar { left: 0; transition: width 0.1s linear; } .progress-container.discrete.done .progress-bar { width: 100%; } .progress-container.infinite .progress-bar { animation-name: progress; animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: steps(100); transform: translateZ(0); } @keyframes progress { 0% { transform: translateX(0) scaleX(1); } 50% { transform: translateX(2500%) scaleX(3); } to { transform: translateX(4900%) scaleX(1); } } `" + }, + { + "kind": "variable", + "name": "titlebarStyles", + "default": "css` .titlebar { background: var(--titlebar-bg); color: var(--titlebar-fg); padding: 0.6rem 0.8rem; font-size: 1.3rem; flex-wrap: wrap; } .titlebar, .titlebar__row, .titlebar__group { display: flex; flex-direction: row; align-items: center; gap: 0.5rem; } .titlebar > *, .titlebar__row > *, .titlebar__group > * { margin: 0; } .titlebar, .titlebar__row { justify-content: space-between; } .titlebar__row { flex: 0 0 100%; } .titlebar__row--wrap { display: grid; grid-auto-flow: column; justify-content: start; grid-template-columns: 1fr min-content; } .titlebar__group { flex: auto 1 1; } .titlebar__row--wrap .titlebar__group { white-space: nowrap; } .titlebar__row--wrap .titlebar__group:nth-child(odd) { min-width: 0; } .titlebar__debugging > * { display: inline-block; } .titlebar gl-feature-badge { color: var(--color-foreground); } `" + }, + { + "kind": "variable", + "name": "graphHeaderControlStyles", + "default": "css` .popover::part(body) { padding: 0; font-size: var(--vscode-font-size); background-color: var(--vscode-menu-background); } .titlebar__group gl-repo-button-group, .titlebar__group gl-ref-button { font-size: 1.2rem; } .shrink { max-width: fit-content; transition: all 0.2s; } .shrink.hidden { max-width: 0; overflow: hidden; } .titlebar__group .shrink.hidden:not(:first-child) { // compensate the parent gap margin-left: -0.5rem; } .branch-menu { display: flex; gap: 0.5em; align-items: center; } .branch-menu__avatar { width: 1.4rem; aspect-ratio: 1; vertical-align: text-bottom; } .action-divider { display: inline-block; width: 0.1rem; height: 2.2rem; vertical-align: middle; background-color: var(--titlebar-fg); opacity: 0.4; margin: { // left: 0.2rem; right: 0.2rem; } } .button-group { display: flex; flex-direction: row; align-items: stretch; } .button-group:hover, .button-group:focus-within { background-color: var(--color-graph-actionbar-selectedBackground); border-radius: 3px; } .button-group > *:not(:first-child), .button-group > *:not(:first-child) .action-button { display: flex; border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group > *:not(:first-child) .action-button { padding-left: 0.5rem; padding-right: 0.5rem; height: 100%; } .button-group:hover > *:not(:last-child), .button-group:active > *:not(:last-child), .button-group:focus-within > *:not(:last-child), .button-group:hover > *:not(:last-child) .action-button, .button-group:active > *:not(:last-child) .action-button, .button-group:focus-within > *:not(:last-child) .action-button { border-top-right-radius: 0; border-bottom-right-radius: 0; } .minimap-marker-swatch { display: inline-block; width: 1rem; height: 1rem; border-radius: 2px; transform: scale(1.6); margin-left: 0.3rem; margin-right: 1rem; } .minimap-marker-swatch[data-marker='localBranches'] { background-color: var(--color-graph-minimap-marker-local-branches); } .minimap-marker-swatch[data-marker='pullRequests'] { background-color: var(--color-graph-minimap-marker-pull-requests); } .minimap-marker-swatch[data-marker='remoteBranches'] { background-color: var(--color-graph-minimap-marker-remote-branches); } .minimap-marker-swatch[data-marker='stashes'] { background-color: var(--color-graph-minimap-marker-stashes); } .minimap-marker-swatch[data-marker='tags'] { background-color: var(--color-graph-minimap-marker-tags); } gl-search-box::part(search) { --gl-search-input-background: var(--color-graph-actionbar-background); --gl-search-input-border: var(--sl-input-border-color); } sl-option::part(base) { padding: 0.2rem 0.4rem; } sl-option[aria-selected='true']::part(base), sl-option:not([aria-selected='true']):hover::part(base), sl-option:not([aria-selected='true']):focus::part(base) { background-color: var(--vscode-list-activeSelectionBackground); color: var(--vscode-list-activeSelectionForeground); } sl-option::part(checked-icon) { display: none; } sl-select::part(listbox) { padding-block: 0.2rem 0; width: max-content; } sl-select::part(combobox) { --sl-input-background-color: var(--color-graph-actionbar-background); --sl-input-color: var(--color-foreground); --sl-input-color-hover: var(--color-foreground); padding: 0 0.75rem; color: var(--color-foreground); border-radius: var(--sl-border-radius-small); } sl-select::part(display-input) { field-sizing: content; } sl-select::part(expand-icon) { margin-inline-start: var(--sl-spacing-x-small); } sl-select[open]::part(combobox) { background-color: var(--color-graph-actionbar-background); } sl-select:hover::part(combobox), sl-select:focus::part(combobox) { background-color: var(--color-graph-actionbar-selectedBackground); } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "repoHeaderStyles", + "declaration": { + "name": "repoHeaderStyles", + "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + } + }, + { + "kind": "js", + "name": "progressStyles", + "declaration": { + "name": "progressStyles", + "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + } + }, + { + "kind": "js", + "name": "titlebarStyles", + "declaration": { + "name": "titlebarStyles", + "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + } + }, + { + "kind": "js", + "name": "graphHeaderControlStyles", + "declaration": { + "name": "graphHeaderControlStyles", + "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/active-work.ts", "declarations": [ + { + "kind": "variable", + "name": "activeWorkTagName", + "type": { + "text": "string" + }, + "default": "'gl-active-work'" + }, { "kind": "class", "description": "", - "name": "GlMergeConflictWarning", + "name": "GlActiveWork", "members": [ { "kind": "field", - "name": "conflicts", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "conflicts", - "reflects": true - }, - { - "kind": "field", - "name": "pausedOpStatus", - "type": { - "text": "GitPausedOperationStatus | undefined" - }, - "attribute": "pausedOpStatus" - }, - { - "kind": "field", - "name": "skipCommand", + "name": "_homeState", "type": { - "text": "string" + "text": "State" }, - "default": "'gitlens.home.skipPausedOperation'", - "attribute": "skipCommand" + "privacy": "private" }, { "kind": "field", - "name": "continueCommand", + "name": "_activeOverviewState", "type": { - "text": "string" + "text": "ActiveOverviewState" }, - "default": "'gitlens.home.continuePausedOperation'", - "attribute": "continueCommand" + "privacy": "private" }, { "kind": "field", - "name": "abortCommand", + "name": "_ipc", "type": { - "text": "string" + "text": "typeof ipcContext.__context__" }, - "default": "'gitlens.home.abortPausedOperation'", - "attribute": "abortCommand" + "privacy": "private" }, { "kind": "field", - "name": "openEditorCommand", + "name": "repoCollapsed", "type": { - "text": "string" + "text": "boolean" }, - "default": "'gitlens.home.openRebaseEditor'", - "attribute": "openEditorCommand" + "privacy": "private", + "default": "true" }, { "kind": "field", - "name": "webviewCommandContext", - "type": { - "text": "{ webview: string; webviewInstance: string | undefined } | undefined" - }, - "attribute": "webviewCommandContext" + "name": "isPro", + "readonly": true }, { - "kind": "field", - "name": "onSkipUrl", - "privacy": "private", - "readonly": true + "kind": "method", + "name": "onBranchSelectorClicked", + "privacy": "private" }, { - "kind": "field", - "name": "onContinueUrl", - "privacy": "private", - "readonly": true + "kind": "method", + "name": "renderLoader", + "privacy": "private" }, { - "kind": "field", - "name": "onAbortUrl", - "privacy": "private", - "readonly": true + "kind": "method", + "name": "renderPending", + "privacy": "private" }, { - "kind": "field", - "name": "onOpenEditorUrl", + "kind": "method", + "name": "renderComplete", "privacy": "private", - "readonly": true + "parameters": [ + { + "name": "overview", + "type": { + "text": "GetActiveOverviewResponse" + } + }, + { + "name": "isFetching", + "default": "false" + } + ] }, { "kind": "method", - "name": "createCommandLink", + "name": "renderRepoBranchCard", "privacy": "private", "parameters": [ { - "name": "command", + "name": "branch", + "type": { + "text": "GetOverviewBranch" + } + }, + { + "name": "repo", "type": { "text": "string" } }, { - "name": "args", - "optional": true, + "name": "isFetching", "type": { - "text": "any" + "text": "boolean" } } ] }, { "kind": "method", - "name": "renderStatus", + "name": "onRepositorySelectorClicked", "privacy": "private", "parameters": [ { - "name": "pausedOpStatus", + "name": "e", "type": { - "text": "GitPausedOperationStatus" + "text": "CustomEvent" } } ] + } + ], + "mixins": [ + { + "name": "SignalWatcher", + "package": "@lit-labs/signals" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlActiveBranchCard", + "members": [ + { + "kind": "method", + "name": "renderActionsMenu", + "privacy": "private" }, { "kind": "method", - "name": "renderActions", + "name": "renderBranchStateActions", "privacy": "private" - } - ], - "attributes": [ + }, { - "name": "conflicts", - "type": { - "text": "boolean" + "kind": "method", + "name": "renderBranchIndicator", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | undefined" + } }, - "default": "false", - "fieldName": "conflicts" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "pausedOpStatus", - "type": { - "text": "GitPausedOperationStatus | undefined" + "kind": "method", + "name": "getBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } }, - "fieldName": "pausedOpStatus" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "skipCommand", - "type": { - "text": "string" + "kind": "method", + "name": "getPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } }, - "default": "'gitlens.home.skipPausedOperation'", - "fieldName": "skipCommand" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "continueCommand", - "type": { - "text": "string" + "kind": "method", + "name": "getCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } }, - "default": "'gitlens.home.continuePausedOperation'", - "fieldName": "continueCommand" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "abortCommand", - "type": { - "text": "string" + "kind": "method", + "name": "renderIssuesItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "default": "'gitlens.home.abortPausedOperation'", - "fieldName": "abortCommand" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "openEditorCommand", + "kind": "field", + "name": "_homeState", "type": { - "text": "string" + "text": "State" }, - "default": "'gitlens.home.openRebaseEditor'", - "fieldName": "openEditorCommand" + "privacy": "protected", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, - { - "name": "webviewCommandContext", - "type": { - "text": "{ webview: string; webviewInstance: string | undefined } | undefined" - }, - "fieldName": "webviewCommandContext" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-merge-rebase-status", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlMergeConflictWarning", - "declaration": { - "name": "GlMergeConflictWarning", - "module": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-merge-rebase-status", - "declaration": { - "name": "GlMergeConflictWarning", - "module": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/shared/components/vscode.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "linkStyles", - "default": "css` a { border: 0; color: var(--link-foreground); font-weight: 400; outline: none; text-decoration: var(--link-decoration-default, none); } a:focus-visible { outline: 1px solid var(--color-focus-border); border-radius: 0.2rem; } a:hover { color: var(--link-foreground-active); text-decoration: underline; } `" - }, - { - "kind": "variable", - "name": "ruleStyles", - "default": "css` hr { border: none; border-top: 1px solid var(--color-foreground--25); } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "linkStyles", - "declaration": { - "name": "linkStyles", - "module": "src/webviews/apps/plus/shared/components/vscode.css.ts" - } - }, - { - "kind": "js", - "name": "ruleStyles", - "declaration": { - "name": "ruleStyles", - "module": "src/webviews/apps/plus/shared/components/vscode.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GitActionsButtons", - "members": [ { "kind": "field", - "name": "branchState", + "name": "repo", "type": { - "text": "BranchState | undefined" + "text": "string" }, - "attribute": "branchState" + "attribute": "repo", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "branchName", + "name": "showUpgrade", "type": { - "text": "string | undefined" + "text": "boolean" }, - "attribute": "branchName" + "default": "false", + "attribute": "showUpgrade", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "lastFetched", + "name": "_branch", "type": { - "text": "Date | undefined" + "text": "GetOverviewBranch" }, - "attribute": "lastFetched" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "state", + "name": "branch", "type": { - "text": "State" + "text": "GetOverviewBranch" }, - "attribute": "state" + "attribute": "branch", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "fetchedText", - "privacy": "private", - "readonly": true - } - ], - "attributes": [ - { - "name": "branchState", + "name": "_autolinks", "type": { - "text": "BranchState | undefined" + "text": "Awaited" }, - "fieldName": "branchState" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "branchName", + "kind": "field", + "name": "autolinks", "type": { - "text": "string | undefined" + "text": "Awaited" }, - "fieldName": "branchName" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "lastFetched", + "kind": "field", + "name": "_autolinksPromise", "type": { - "text": "Date | undefined" + "text": "GetOverviewBranch['autolinks']" }, - "fieldName": "lastFetched" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, - { - "name": "state", - "type": { - "text": "State" - }, - "fieldName": "state" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-git-actions-buttons", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "GlFetchButton", - "members": [ { "kind": "field", - "name": "state", + "name": "autolinksPromise", "type": { - "text": "State" + "text": "GetOverviewBranch['autolinks']" }, - "attribute": "state" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "fetchedText", + "name": "_contributors", "type": { - "text": "string | undefined" + "text": "Awaited" }, - "attribute": "fetchedText" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "branchState", + "name": "contributors", "type": { - "text": "BranchState | undefined" + "text": "Awaited" }, - "attribute": "branchState" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "upstream", - "privacy": "private", - "readonly": true - } - ], - "attributes": [ - { - "name": "state", + "name": "_contributorsPromise", "type": { - "text": "State" + "text": "GetOverviewBranch['contributors']" }, - "fieldName": "state" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "fetchedText", + "kind": "field", + "name": "contributorsPromise", "type": { - "text": "string | undefined" + "text": "GetOverviewBranch['contributors']" }, - "fieldName": "fetchedText" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, - { - "name": "branchState", - "type": { - "text": "BranchState | undefined" - }, - "fieldName": "branchState" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-fetch-button", - "customElement": true - }, - { - "kind": "class", - "description": "", - "name": "PushPullButton", - "members": [ { "kind": "field", - "name": "branchState", + "name": "_issues", "type": { - "text": "BranchState | undefined" + "text": "Awaited" }, - "attribute": "branchState" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "state", + "name": "issues", "type": { - "text": "State" + "text": "Awaited" }, - "attribute": "state" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "fetchedText", + "name": "_issuesPromise", "type": { - "text": "string | undefined" + "text": "GetOverviewBranch['issues']" }, - "attribute": "fetchedText" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "branchName", + "name": "issuesPromise", "type": { - "text": "string | undefined" + "text": "GetOverviewBranch['issues']" }, - "attribute": "branchName" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "isBehind", + "name": "_pr", "type": { - "text": "boolean" + "text": "Awaited" }, "privacy": "private", - "readonly": true + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "isAhead", + "name": "pr", "type": { - "text": "boolean" + "text": "Awaited" }, - "privacy": "private", - "readonly": true + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "upstream", - "privacy": "private", - "readonly": true - }, - { - "kind": "method", - "name": "renderBranchPrefix", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderTooltipContent", - "privacy": "private", - "parameters": [ - { - "name": "action", - "type": { - "text": "'pull' | 'push'" - } - } - ] - } - ], - "attributes": [ - { - "name": "branchState", + "name": "_prPromise", "type": { - "text": "BranchState | undefined" + "text": "GetOverviewBranch['pr']" }, - "fieldName": "branchState" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "state", + "kind": "field", + "name": "prPromise", "type": { - "text": "State" + "text": "GetOverviewBranch['pr']" }, - "fieldName": "state" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "fetchedText", + "kind": "field", + "name": "_launchpadItem", "type": { - "text": "string | undefined" + "text": "Awaited>['launchpad']>" }, - "fieldName": "fetchedText" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, - { - "name": "branchName", - "type": { - "text": "string | undefined" - }, - "fieldName": "branchName" - } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-push-pull-button", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GitActionsButtons", - "declaration": { - "name": "GitActionsButtons", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-git-actions-buttons", - "declaration": { - "name": "GitActionsButtons", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - }, - { - "kind": "js", - "name": "GlFetchButton", - "declaration": { - "name": "GlFetchButton", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-fetch-button", - "declaration": { - "name": "GlFetchButton", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - }, - { - "kind": "js", - "name": "PushPullButton", - "declaration": { - "name": "PushPullButton", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-push-pull-button", - "declaration": { - "name": "PushPullButton", - "module": "src/webviews/apps/plus/graph/actions/gitActionsButtons.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper-element.ts", - "declarations": [ - { - "kind": "class", - "description": "A LitElement web component that encapsulates the GraphWrapperReact component.\nThis component mounts the React component once and then updates its state\nwithout remounting on subsequent property changes.", - "name": "GlGraph", - "members": [ { "kind": "field", - "name": "reactRoot", + "name": "launchpadItem", "type": { - "text": "ReturnType | null" + "text": "Awaited>['launchpad']>" }, - "privacy": "private", - "default": "null" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "provideReactState", + "name": "_launchpadItemPromise", "type": { - "text": "((props: Partial) => void) | null" + "text": "NonNullable>['launchpad']" }, "privacy": "private", - "default": "null" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "setReactStateProvider", - "privacy": "private" + "name": "launchpadItemPromise", + "type": { + "text": "NonNullable>['launchpad']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "activeRow", + "name": "_mergeTarget", "type": { - "text": "GraphWrapperProps['activeRow'] | undefined" + "text": "Awaited" }, - "attribute": "activeRow" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "avatars", + "name": "mergeTarget", "type": { - "text": "GraphWrapperProps['avatars'] | undefined" + "text": "Awaited" }, - "attribute": "avatars" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "columns", + "name": "_mergeTargetPromise", "type": { - "text": "GraphWrapperProps['columns'] | undefined" + "text": "GetOverviewBranch['mergeTarget']" }, - "attribute": "columns" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "context", + "name": "mergeTargetPromise", "type": { - "text": "GraphWrapperProps['context'] | undefined" + "text": "GetOverviewBranch['mergeTarget']" }, - "attribute": "context" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "config", + "name": "_remote", "type": { - "text": "GraphWrapperProps['config'] | undefined" + "text": "Awaited" }, - "attribute": "config" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "downstreams", + "name": "remote", "type": { - "text": "GraphWrapperProps['downstreams'] | undefined" + "text": "Awaited" }, - "attribute": "downstreams" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "rows", + "name": "_remotePromise", "type": { - "text": "GraphWrapperProps['rows'] | undefined" + "text": "GetOverviewBranch['remote']" }, - "attribute": "rows" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "excludeRefs", + "name": "remotePromise", "type": { - "text": "GraphWrapperProps['excludeRefs'] | undefined" + "text": "GetOverviewBranch['remote']" }, - "attribute": "excludeRefs" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "excludeTypes", + "name": "_wip", "type": { - "text": "GraphWrapperProps['excludeTypes'] | undefined" + "text": "Awaited" }, - "attribute": "excludeTypes" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "paging", + "name": "wip", "type": { - "text": "GraphWrapperProps['paging'] | undefined" + "text": "Awaited" }, - "attribute": "paging" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "loading", + "name": "_wipPromise", "type": { - "text": "GraphWrapperProps['loading'] | undefined" + "text": "GetOverviewBranch['wip']" }, - "attribute": "loading" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "selectedRows", + "name": "wipPromise", "type": { - "text": "GraphWrapperProps['selectedRows'] | undefined" + "text": "GetOverviewBranch['wip']" }, - "attribute": "selectedRows" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "windowFocused", + "name": "busy", "type": { - "text": "GraphWrapperProps['windowFocused'] | undefined" + "text": "boolean" }, - "attribute": "windowFocused" + "default": "false", + "attribute": "busy", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "refsMetadata", + "name": "expanded", "type": { - "text": "GraphWrapperProps['refsMetadata'] | undefined" + "text": "boolean" }, - "attribute": "refsMetadata" + "default": "false", + "attribute": "expanded", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "includeOnlyRefs", + "name": "expandable", "type": { - "text": "GraphWrapperProps['includeOnlyRefs'] | undefined" + "text": "boolean" }, - "attribute": "includeOnlyRefs" + "default": "false", + "attribute": "expandable", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "rowsStats", + "name": "eventController", "type": { - "text": "GraphWrapperProps['rowsStats'] | undefined" + "text": "AbortController | undefined" }, - "attribute": "rowsStats" + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "kind": "field", - "name": "rowsStatsLoading", - "type": { - "text": "GraphWrapperProps['rowsStatsLoading'] | undefined" - }, - "attribute": "rowsStatsLoading" + "kind": "method", + "name": "onExpandableChanged", + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "workingTreeStats", + "name": "branchRef", "type": { - "text": "GraphWrapperProps['workingTreeStats'] | undefined" + "text": "BranchRef" }, - "attribute": "workingTreeStats" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "theming", + "name": "isWorktree", "type": { - "text": "GraphWrapperProps['theming'] | undefined" + "text": "boolean" }, - "attribute": "theming" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "searchResults", + "name": "cardIndicator", "type": { - "text": "GraphWrapperProps['searchResults'] | undefined" + "text": "GlCard['indicator']" }, - "attribute": "searchResults" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "filter", + "name": "branchCardIndicator", "type": { - "text": "SearchQuery" + "text": "GlCard['indicator']" }, - "attribute": "filter" - }, - { - "kind": "field", - "name": "setRef", - "type": { - "text": "(ref: GraphContainer) => void" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" } }, { - "kind": "field", - "name": "changedProps", - "type": { - "text": "Map" - }, + "kind": "method", + "name": "attachFocusListener", "privacy": "private", - "default": "new Map()" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { "kind": "field", - "name": "updateScheduled", - "type": { - "text": "boolean" - }, + "name": "onFocus", "privacy": "private", - "default": "false" - }, - { - "kind": "field", - "name": "handleChangeColumns", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleChangeRefsVisibility", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleChangeSelection", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleChangeVisibleDays", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleMissingAvatars", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleMissingRefsMetadata", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleMoreRows", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleMouseLeave", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleRefDoubleClick", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleRowContextMenu", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleRowDoubleClick", - "privacy": "private" - }, - { - "kind": "field", - "name": "handleRowHover", - "privacy": "private" + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "kind": "field", - "name": "handleRowUnhover", - "privacy": "private" - } - ], - "attributes": [ - { - "name": "activeRow", - "type": { - "text": "GraphWrapperProps['activeRow'] | undefined" + "kind": "method", + "name": "renderIssues", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "activeRow" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "avatars", - "type": { - "text": "GraphWrapperProps['avatars'] | undefined" + "kind": "method", + "name": "renderWip", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "avatars" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "columns", - "type": { - "text": "GraphWrapperProps['columns'] | undefined" + "kind": "method", + "name": "renderAvatars", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "columns" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "context", - "type": { - "text": "GraphWrapperProps['context'] | undefined" + "kind": "method", + "name": "renderTracking", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "context" + "parameters": [ + { + "name": "showWip", + "default": "false" + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "config", - "type": { - "text": "GraphWrapperProps['config'] | undefined" + "kind": "method", + "name": "renderBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "config" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "downstreams", - "type": { - "text": "GraphWrapperProps['downstreams'] | undefined" + "kind": "method", + "name": "renderPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "downstreams" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "rows", - "type": { - "text": "GraphWrapperProps['rows'] | undefined" + "kind": "method", + "name": "renderCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "rows" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "excludeRefs", - "type": { - "text": "GraphWrapperProps['excludeRefs'] | undefined" + "kind": "method", + "name": "createWebviewCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } }, - "fieldName": "excludeRefs" + "parameters": [ + { + "name": "command", + "type": { + "text": "WebviewCommands | WebviewViewCommands | PlusCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "excludeTypes", - "type": { - "text": "GraphWrapperProps['excludeTypes'] | undefined" + "kind": "method", + "name": "createCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } }, - "fieldName": "excludeTypes" + "parameters": [ + { + "name": "command", + "type": { + "text": "GlCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "paging", - "type": { - "text": "GraphWrapperProps['paging'] | undefined" + "kind": "method", + "name": "renderTimestamp", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "paging" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "loading", - "type": { - "text": "GraphWrapperProps['loading'] | undefined" + "kind": "method", + "name": "renderBranchItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "loading" + "parameters": [ + { + "name": "actionsSection", + "optional": true, + "type": { + "text": "TemplateResult | NothingType" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "selectedRows", - "type": { - "text": "GraphWrapperProps['selectedRows'] | undefined" - }, - "fieldName": "selectedRows" + "kind": "method", + "name": "renderBranchIcon", + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "windowFocused", - "type": { - "text": "GraphWrapperProps['windowFocused'] | undefined" + "kind": "method", + "name": "renderPrItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "windowFocused" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "refsMetadata", - "type": { - "text": "GraphWrapperProps['refsMetadata'] | undefined" - }, - "fieldName": "refsMetadata" + "kind": "method", + "name": "renderLaunchpadItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "includeOnlyRefs", - "type": { - "text": "GraphWrapperProps['includeOnlyRefs'] | undefined" + "kind": "method", + "name": "renderMergeTargetStatus", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } }, - "fieldName": "includeOnlyRefs" + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "rowsStats", + "kind": "method", + "name": "toggleExpanded", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "expanded", + "default": "!this.expanded" + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "superclass": { + "name": "GlBranchCardBase", + "module": "/src/webviews/apps/plus/home/components/branch-card" + }, + "tagName": "gl-active-branch-card", + "customElement": true, + "attributes": [ + { + "name": "repo", "type": { - "text": "GraphWrapperProps['rowsStats'] | undefined" + "text": "string" }, - "fieldName": "rowsStats" + "fieldName": "repo", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "rowsStatsLoading", + "name": "showUpgrade", "type": { - "text": "GraphWrapperProps['rowsStatsLoading'] | undefined" + "text": "boolean" }, - "fieldName": "rowsStatsLoading" + "default": "false", + "fieldName": "showUpgrade", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "workingTreeStats", + "name": "branch", "type": { - "text": "GraphWrapperProps['workingTreeStats'] | undefined" + "text": "GetOverviewBranch" }, - "fieldName": "workingTreeStats" + "fieldName": "branch", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "theming", + "name": "busy", "type": { - "text": "GraphWrapperProps['theming'] | undefined" + "text": "boolean" }, - "fieldName": "theming" + "default": "false", + "fieldName": "busy", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "searchResults", + "name": "expanded", "type": { - "text": "GraphWrapperProps['searchResults'] | undefined" + "text": "boolean" }, - "fieldName": "searchResults" + "default": "false", + "fieldName": "expanded", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } }, { - "name": "filter", + "name": "expandable", "type": { - "text": "SearchQuery" + "text": "boolean" }, - "fieldName": "filter" + "default": "false", + "fieldName": "expandable", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } } - ], - "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-graph", - "customElement": true + ] } ], "exports": [ { "kind": "js", - "name": "GlGraph", + "name": "activeWorkTagName", "declaration": { - "name": "GlGraph", - "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper-element.ts" + "name": "activeWorkTagName", + "module": "src/webviews/apps/plus/home/components/active-work.ts" + } + }, + { + "kind": "js", + "name": "GlActiveWork", + "declaration": { + "name": "GlActiveWork", + "module": "src/webviews/apps/plus/home/components/active-work.ts" } }, { "kind": "custom-element-definition", - "name": "gl-graph", "declaration": { - "name": "GlGraph", - "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper-element.ts" + "name": "GlActiveWork", + "module": "src/webviews/apps/plus/home/components/active-work.ts" + } + }, + { + "kind": "js", + "name": "GlActiveBranchCard", + "declaration": { + "name": "GlActiveBranchCard", + "module": "src/webviews/apps/plus/home/components/active-work.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-active-branch-card", + "declaration": { + "name": "GlActiveBranchCard", + "module": "src/webviews/apps/plus/home/components/active-work.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts", + "path": "src/webviews/apps/plus/home/components/branch-card.ts", "declarations": [ + { + "kind": "variable", + "name": "branchCardStyles", + "default": "css` * { box-sizing: border-box; } gl-avatar-list { --gl-avatar-size: 2.4rem; margin-block: -0.4rem; } .branch-item { position: relative; } .branch-item__container { display: flex; flex-direction: column; gap: 0.6rem; } .branch-item__container > * { margin-block: 0; } .branch-item__section { display: flex; flex-direction: column; gap: 0.4rem; } .branch-item__section > * { margin-block: 0; } .branch-item__section--details { font-size: 0.9em; color: var(--vscode-descriptionForeground); } .branch-item__actions { display: flex; align-items: center; gap: 0.8rem; flex-direction: row; justify-content: flex-end; font-size: 0.9em; } /* :empty selector doesn't work with lit */ .branch-item__actions:not(:has(*)) { display: none; } .branch-item__icon { color: var(--vscode-descriptionForeground); flex: none; } .branch-item__name { flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: bold; } .branch-item__name--secondary { font-weight: normal; } .branch-item__identifier { color: var(--vscode-descriptionForeground); text-decoration: none; } .branch-item__grouping { display: inline-flex; align-items: center; gap: 0.6rem; max-width: 100%; margin-block: 0; } .branch-item__changes { display: flex; align-items: center; gap: 1rem; justify-content: flex-end; flex-wrap: wrap; white-space: nowrap; } .branch-item__changes formatted-date { margin-inline-end: auto; } .branch-item__summary { display: flex; align-items: center; gap: 0.6rem; } .branch-item__collapsed-actions { position: absolute; z-index: var(--gl-branch-card-actions-zindex, 2); right: 0.4rem; bottom: 0.3rem; padding: 0.4rem 0.6rem; background-color: var(--gl-card-hover-background); } .branch-item:not(:focus-within):not(:hover) .branch-item__collapsed-actions { ${srOnlyStyles} } .pill { --gl-pill-border: color-mix(in srgb, transparent 80%, var(--color-foreground)); } .work-item { --gl-card-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 3%); --gl-card-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 1.5%); } .work-item::part(base) { margin-block-end: 0; } .branch-item__section.mb-1 { margin-block: 0.4rem; } .branch-item__merge-target { margin-inline-end: auto; } .branch-item__row { display: flex; gap: 0.8rem; } .branch-item__row [full] { flex-grow: 1; } .branch-item__missing { --button-foreground: inherit; } :host-context(.vscode-dark) .branch-item__missing, :host-context(.vscode-high-contrast) .branch-item__missing { --button-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 3%); --button-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 1.5%); --button-border: color-mix(in lab, var(--vscode-sideBar-background) 100%, #fff 12%); } :host-context(.vscode-light) .branch-item__missing, :host-context(.vscode-high-contrast-light) .branch-item__missing { --button-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 8%); --button-hover-background: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 10%); --button-border: color-mix(in lab, var(--vscode-sideBar-background) 100%, #000 14%); } .branch-item__category { margin-inline-start: 0.6rem; } .launchpad-grouping--mergeable { color: var(--vscode-gitlens-launchpadIndicatorMergeableColor); } .launchpad-grouping--blocked { color: var(--vscode-gitlens-launchpadIndicatorBlockedColor); } .launchpad-grouping--attention { color: var(--vscode-gitlens-launchpadIndicatorAttentionColor); } .tracking__pill, .wip__pill { display: flex; flex-direction: row; gap: 1rem; } .tracking__tooltip, .wip__tooltip { display: contents; vertical-align: middle; } .tracking__tooltip p, .wip__tooltip p { margin-block: 0; } p.tracking__tooltip--wip { margin-block-start: 1rem; } `" + }, { "kind": "class", "description": "", - "name": "GlGraphWrapper", + "name": "GlBranchCardBase", "members": [ { "kind": "field", - "name": "graphAppState", + "name": "_homeState", "type": { - "text": "typeof graphStateContext.__context__" + "text": "State" + }, + "privacy": "protected" + }, + { + "kind": "field", + "name": "repo", + "type": { + "text": "string" + }, + "attribute": "repo" + }, + { + "kind": "field", + "name": "showUpgrade", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "showUpgrade" + }, + { + "kind": "field", + "name": "_branch", + "type": { + "text": "GetOverviewBranch" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "branch", + "type": { + "text": "GetOverviewBranch" + }, + "attribute": "branch" + }, + { + "kind": "field", + "name": "_autolinks", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "autolinks", + "type": { + "text": "Awaited" }, - "privacy": "private", "readonly": true }, { "kind": "field", - "name": "hostState", + "name": "_autolinksPromise", "type": { - "text": "typeof stateContext.__context__" + "text": "GetOverviewBranch['autolinks']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "autolinksPromise", + "type": { + "text": "GetOverviewBranch['autolinks']" + } + }, + { + "kind": "field", + "name": "_contributors", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "contributors", + "type": { + "text": "Awaited" }, - "privacy": "private", "readonly": true }, { "kind": "field", - "name": "_ipc", + "name": "_contributorsPromise", "type": { - "text": "typeof ipcContext.__context__" + "text": "GetOverviewBranch['contributors']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "contributorsPromise", + "type": { + "text": "GetOverviewBranch['contributors']" + } + }, + { + "kind": "field", + "name": "_issues", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "issues", + "type": { + "text": "Awaited" }, - "privacy": "private", "readonly": true }, { "kind": "field", - "name": "_telemetry", + "name": "_issuesPromise", "type": { - "text": "TelemetryContext" + "text": "GetOverviewBranch['issues']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "issuesPromise", + "type": { + "text": "GetOverviewBranch['issues']" + } + }, + { + "kind": "field", + "name": "_pr", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "pr", + "type": { + "text": "Awaited" }, - "privacy": "private", "readonly": true }, { "kind": "field", - "name": "graph", + "name": "_prPromise", "type": { - "text": "typeof GlGraph" + "text": "GetOverviewBranch['pr']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "prPromise", + "type": { + "text": "GetOverviewBranch['pr']" } }, { "kind": "field", - "name": "ref", + "name": "_launchpadItem", "type": { - "text": "GraphContainer | undefined" + "text": "Awaited>['launchpad']>" }, "privacy": "private" }, { "kind": "field", - "name": "onSetRef", + "name": "launchpadItem", + "type": { + "text": "Awaited>['launchpad']>" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_launchpadItemPromise", + "type": { + "text": "NonNullable>['launchpad']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "launchpadItemPromise", + "type": { + "text": "NonNullable>['launchpad']" + } + }, + { + "kind": "field", + "name": "_mergeTarget", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "mergeTarget", + "type": { + "text": "Awaited" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_mergeTargetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "mergeTargetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + } + }, + { + "kind": "field", + "name": "_remote", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "remote", + "type": { + "text": "Awaited" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_remotePromise", + "type": { + "text": "GetOverviewBranch['remote']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "remotePromise", + "type": { + "text": "GetOverviewBranch['remote']" + } + }, + { + "kind": "field", + "name": "_wip", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "wip", + "type": { + "text": "Awaited" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_wipPromise", + "type": { + "text": "GetOverviewBranch['wip']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "wipPromise", + "type": { + "text": "GetOverviewBranch['wip']" + } + }, + { + "kind": "field", + "name": "busy", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "busy", + "reflects": true + }, + { + "kind": "field", + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "expanded", + "reflects": true + }, + { + "kind": "field", + "name": "expandable", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "expandable", + "reflects": true + }, + { + "kind": "field", + "name": "eventController", + "type": { + "text": "AbortController | undefined" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "onExpandableChanged", "privacy": "private" }, + { + "kind": "field", + "name": "branchRef", + "type": { + "text": "BranchRef" + }, + "readonly": true + }, + { + "kind": "field", + "name": "isWorktree", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "cardIndicator", + "type": { + "text": "GlCard['indicator']" + }, + "readonly": true + }, + { + "kind": "field", + "name": "branchCardIndicator", + "type": { + "text": "GlCard['indicator']" + }, + "readonly": true + }, + { + "kind": "method", + "name": "attachFocusListener", + "privacy": "private" + }, + { + "kind": "field", + "name": "onFocus", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "renderIssues", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderWip", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderAvatars", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderTracking", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "parameters": [ + { + "name": "showWip", + "default": "false" + } + ] + }, + { + "kind": "method", + "name": "getBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + } + }, + { + "kind": "method", + "name": "renderBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "getPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + } + }, + { + "kind": "method", + "name": "renderPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "getCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + } + }, + { + "kind": "method", + "name": "renderCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "createWebviewCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "WebviewCommands | WebviewViewCommands | PlusCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ] + }, + { + "kind": "method", + "name": "createCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "GlCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ] + }, + { + "kind": "method", + "name": "renderTimestamp", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderBranchIndicator", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | undefined" + } + } + }, + { + "kind": "method", + "name": "renderBranchItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "parameters": [ + { + "name": "actionsSection", + "optional": true, + "type": { + "text": "TemplateResult | NothingType" + } + } + ] + }, + { + "kind": "method", + "name": "renderBranchIcon", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPrItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderLaunchpadItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderMergeTargetStatus", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "renderIssuesItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + } + }, + { + "kind": "method", + "name": "toggleExpanded", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "expanded", + "default": "!this.expanded" + } + ] + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "repo", + "type": { + "text": "string" + }, + "fieldName": "repo" + }, + { + "name": "showUpgrade", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "showUpgrade" + }, + { + "name": "branch", + "type": { + "text": "GetOverviewBranch" + }, + "fieldName": "branch" + }, + { + "name": "busy", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "busy" + }, + { + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expanded" + }, + { + "name": "expandable", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expandable" + } + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } + }, + { + "kind": "class", + "description": "", + "name": "GlBranchCard", + "members": [ + { + "kind": "method", + "name": "getCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "getBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "getPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult[]" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderBranchIndicator", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | undefined" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_homeState", + "type": { + "text": "State" + }, + "privacy": "protected", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "repo", + "type": { + "text": "string" + }, + "attribute": "repo", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "showUpgrade", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "showUpgrade", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_branch", + "type": { + "text": "GetOverviewBranch" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "branch", + "type": { + "text": "GetOverviewBranch" + }, + "attribute": "branch", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_autolinks", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "autolinks", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_autolinksPromise", + "type": { + "text": "GetOverviewBranch['autolinks']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "autolinksPromise", + "type": { + "text": "GetOverviewBranch['autolinks']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_contributors", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "contributors", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_contributorsPromise", + "type": { + "text": "GetOverviewBranch['contributors']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "contributorsPromise", + "type": { + "text": "GetOverviewBranch['contributors']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_issues", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "issues", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_issuesPromise", + "type": { + "text": "GetOverviewBranch['issues']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "issuesPromise", + "type": { + "text": "GetOverviewBranch['issues']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_pr", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "pr", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_prPromise", + "type": { + "text": "GetOverviewBranch['pr']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "prPromise", + "type": { + "text": "GetOverviewBranch['pr']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_launchpadItem", + "type": { + "text": "Awaited>['launchpad']>" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "launchpadItem", + "type": { + "text": "Awaited>['launchpad']>" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_launchpadItemPromise", + "type": { + "text": "NonNullable>['launchpad']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "launchpadItemPromise", + "type": { + "text": "NonNullable>['launchpad']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_mergeTarget", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "mergeTarget", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_mergeTargetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "mergeTargetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_remote", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "remote", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_remotePromise", + "type": { + "text": "GetOverviewBranch['remote']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "remotePromise", + "type": { + "text": "GetOverviewBranch['remote']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_wip", + "type": { + "text": "Awaited" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "wip", + "type": { + "text": "Awaited" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "_wipPromise", + "type": { + "text": "GetOverviewBranch['wip']" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "wipPromise", + "type": { + "text": "GetOverviewBranch['wip']" + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "busy", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "busy", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "expanded", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "expandable", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "expandable", + "reflects": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "eventController", + "type": { + "text": "AbortController | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "onExpandableChanged", + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "branchRef", + "type": { + "text": "BranchRef" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "isWorktree", + "type": { + "text": "boolean" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "cardIndicator", + "type": { + "text": "GlCard['indicator']" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "branchCardIndicator", + "type": { + "text": "GlCard['indicator']" + }, + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "attachFocusListener", + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "field", + "name": "onFocus", + "privacy": "private", + "readonly": true, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderIssues", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderWip", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderAvatars", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderTracking", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "parameters": [ + { + "name": "showWip", + "default": "false" + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderBranchActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderPrActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderCollapsedActions", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "createWebviewCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "WebviewCommands | WebviewViewCommands | PlusCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "createCommandLink", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "command", + "type": { + "text": "GlCommands" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "T | any" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderTimestamp", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderBranchItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "parameters": [ + { + "name": "actionsSection", + "optional": true, + "type": { + "text": "TemplateResult | NothingType" + } + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderBranchIcon", + "privacy": "private", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderPrItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderLaunchpadItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderMergeTargetStatus", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "renderIssuesItem", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | NothingType" + } + }, + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "toggleExpanded", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "expanded", + "default": "!this.expanded" + } + ], + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "superclass": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + }, + "tagName": "gl-branch-card", + "customElement": true, + "attributes": [ + { + "name": "repo", + "type": { + "text": "string" + }, + "fieldName": "repo", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "name": "showUpgrade", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "showUpgrade", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "name": "branch", + "type": { + "text": "GetOverviewBranch" + }, + "fieldName": "branch", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "name": "busy", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "busy", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expanded", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "name": "expandable", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expandable", + "inheritedFrom": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + } + ] + }, + { + "kind": "class", + "description": "", + "name": "GlWorkUnit", + "members": [ + { + "kind": "field", + "name": "primary", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "primary", + "reflects": true + }, + { + "kind": "field", + "name": "nested", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "nested", + "reflects": true + }, + { + "kind": "field", + "name": "indicator", + "type": { + "text": "GlCard['indicator'] | undefined" + }, + "attribute": "indicator", + "reflects": true + }, + { + "kind": "field", + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "expanded", + "reflects": true + }, + { + "kind": "method", + "name": "renderContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSummary", + "privacy": "private" + } + ], + "attributes": [ + { + "name": "primary", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "primary" + }, + { + "name": "nested", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "nested" + }, + { + "name": "indicator", + "type": { + "text": "GlCard['indicator'] | undefined" + }, + "fieldName": "indicator" + }, + { + "name": "expanded", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "expanded" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-work-item", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "branchCardStyles", + "declaration": { + "name": "branchCardStyles", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "js", + "name": "GlBranchCardBase", + "declaration": { + "name": "GlBranchCardBase", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "js", + "name": "GlBranchCard", + "declaration": { + "name": "GlBranchCard", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-branch-card", + "declaration": { + "name": "GlBranchCard", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "js", + "name": "GlWorkUnit", + "declaration": { + "name": "GlWorkUnit", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-work-item", + "declaration": { + "name": "GlWorkUnit", + "module": "src/webviews/apps/plus/home/components/branch-card.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/branch-section.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlSection", + "members": [ + { + "kind": "field", + "name": "loading", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "loading" + }, + { + "kind": "field", + "name": "headingLevel", + "type": { + "text": "ARIAMixin['ariaLevel']" + }, + "default": "'3'", + "attribute": "heading-level" + } + ], + "attributes": [ + { + "name": "loading", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "loading" + }, + { + "name": "heading-level", + "type": { + "text": "ARIAMixin['ariaLevel']" + }, + "default": "'3'", + "fieldName": "headingLevel" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-section", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlBranchSection", + "members": [ + { + "kind": "field", + "name": "label", + "type": { + "text": "string" + }, + "attribute": "label" + }, + { + "kind": "field", + "name": "repo", + "type": { + "text": "string" + }, + "attribute": "repo" + }, + { + "kind": "field", + "name": "branches", + "type": { + "text": "GetOverviewBranch[]" + }, + "attribute": "branches" + }, + { + "kind": "field", + "name": "isFetching", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "isFetching" + }, + { + "kind": "field", + "name": "branchCards", + "type": { + "text": "GlBranchCardBase[]" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "onCardExpanded", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "toggleSiblingCards", + "privacy": "private", + "parameters": [ + { + "name": "card", + "optional": true, + "type": { + "text": "GlBranchCardBase" + } + } + ] + }, + { + "kind": "field", + "name": "toggleSiblingCardsDebounced", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSectionLabel", + "privacy": "private" + } + ], + "attributes": [ + { + "name": "label", + "type": { + "text": "string" + }, + "fieldName": "label" + }, + { + "name": "repo", + "type": { + "text": "string" + }, + "fieldName": "repo" + }, + { + "name": "branches", + "type": { + "text": "GetOverviewBranch[]" + }, + "fieldName": "branches" + }, + { + "name": "isFetching", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "isFetching" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-branch-section", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlSection", + "declaration": { + "name": "GlSection", + "module": "src/webviews/apps/plus/home/components/branch-section.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-section", + "declaration": { + "name": "GlSection", + "module": "src/webviews/apps/plus/home/components/branch-section.ts" + } + }, + { + "kind": "js", + "name": "GlBranchSection", + "declaration": { + "name": "GlBranchSection", + "module": "src/webviews/apps/plus/home/components/branch-section.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-branch-section", + "declaration": { + "name": "GlBranchSection", + "module": "src/webviews/apps/plus/home/components/branch-section.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts", + "declarations": [ + { + "kind": "variable", + "name": "selectStyles", + "default": "css` .select { background: none; outline: none; border: none; text-decoration: none !important; font-weight: 500; color: var(--color-foreground--25); } .select option { color: var(--vscode-foreground); background-color: var(--vscode-dropdown-background); } .select:not(:disabled) { cursor: pointer; color: var(--color-foreground--50); } .select:not(:disabled):focus { outline: 1px solid var(--color-focus-border); } .select:not(:disabled):hover { color: var(--vscode-foreground); text-decoration: underline !important; } `" + }, + { + "kind": "class", + "description": "", + "name": "GlObjectSelect", + "members": [ + { + "kind": "field", + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "disabled" + }, + { + "kind": "field", + "name": "value", + "type": { + "text": "V | undefined" + }, + "attribute": "value" + }, + { + "kind": "field", + "name": "options", + "type": { + "text": "T[] | undefined" + }, + "attribute": "options" + }, + { + "kind": "method", + "name": "getValue", + "privacy": "protected", + "return": { + "type": { + "text": "V" + } + }, + "parameters": [ + { + "name": "option", + "type": { + "text": "T" + } + } + ] + }, + { + "kind": "method", + "name": "getLabel", + "privacy": "protected", + "return": { + "type": { + "text": "L" + } + }, + "parameters": [ + { + "name": "option", + "type": { + "text": "T" + } + } + ] + }, + { + "kind": "method", + "name": "onChange", + "privacy": "protected", + "return": { + "type": { + "text": "unknown" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "InputEvent" + } + } + ] + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "value", + "type": { + "text": "V | undefined" + }, + "fieldName": "value" + }, + { + "name": "options", + "type": { + "text": "T[] | undefined" + }, + "fieldName": "options" + } + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } + }, + { + "kind": "class", + "description": "", + "name": "GlBranchThresholdFilter", + "members": [ + { + "kind": "method", + "name": "getValue", + "privacy": "protected", + "return": { + "type": { + "text": "OverviewRecentThreshold | 'OneYear'" + } + }, + "parameters": [ + { + "name": "option", + "type": { + "text": "{\n\t\tvalue: OverviewRecentThreshold | OverviewStaleThreshold;\n\t}" + } + } + ], + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "method", + "name": "getLabel", + "privacy": "protected", + "return": { + "type": { + "text": "string" + } + }, + "parameters": [ + { + "name": "option", + "type": { + "text": "{ label: string }" + } + } + ], + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "method", + "name": "onChange", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "InputEvent" + } + } + ], + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "field", + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "disabled", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "field", + "name": "value", + "type": { + "text": "V | undefined" + }, + "attribute": "value", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "field", + "name": "options", + "type": { + "text": "T[] | undefined" + }, + "attribute": "options", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "superclass": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + }, + "tagName": "gl-branch-threshold-filter", + "customElement": true, + "attributes": [ + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "name": "value", + "type": { + "text": "V | undefined" + }, + "fieldName": "value", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "name": "options", + "type": { + "text": "T[] | undefined" + }, + "fieldName": "options", + "inheritedFrom": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "selectStyles", + "declaration": { + "name": "selectStyles", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "js", + "name": "GlObjectSelect", + "declaration": { + "name": "GlObjectSelect", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "js", + "name": "GlBranchThresholdFilter", + "declaration": { + "name": "GlBranchThresholdFilter", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-branch-threshold-filter", + "declaration": { + "name": "GlBranchThresholdFilter", + "module": "src/webviews/apps/plus/home/components/branch-threshold-filter.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/launchpad.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlLaunchpad", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "_homeState", + "type": { + "text": "State" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_ipc", + "type": { + "text": "HostIpc" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_disposable", + "type": { + "text": "Disposable[]" + }, + "privacy": "private", + "default": "[]" + }, + { + "kind": "field", + "name": "_summary", + "privacy": "private" + }, + { + "kind": "field", + "name": "_summaryState", + "privacy": "private", + "default": "new AsyncComputedState(async _abortSignal => { const rsp = await this._ipc.sendRequest(GetLaunchpadSummary, {}); return rsp; })" + }, + { + "kind": "field", + "name": "startWorkCommand", + "type": { + "text": "string" + }, + "readonly": true + }, + { + "kind": "field", + "name": "createBranchCommand", + "type": { + "text": "string" + }, + "readonly": true + }, + { + "kind": "method", + "name": "renderSummaryResult", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPending", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSummary", + "privacy": "private", + "parameters": [ + { + "name": "summary", + "type": { + "text": "LaunchpadSummary | undefined" + } + } + ] + } + ], + "mixins": [ + { + "name": "SignalWatcher", + "package": "@lit-labs/signals" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-launchpad", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlLaunchpad", + "declaration": { + "name": "GlLaunchpad", + "module": "src/webviews/apps/plus/home/components/launchpad.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-launchpad", + "declaration": { + "name": "GlLaunchpad", + "module": "src/webviews/apps/plus/home/components/launchpad.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/merge-target-status.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlMergeTargetStatus", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "branch", + "type": { + "text": "Pick" + }, + "attribute": "branch" + }, + { + "kind": "field", + "name": "_target", + "type": { + "text": "Awaited" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "target", + "type": { + "text": "Awaited" + }, + "readonly": true + }, + { + "kind": "field", + "name": "_targetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "targetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "attribute": "targetPromise" + }, + { + "kind": "field", + "name": "conflicts", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "mergedStatus", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "status", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "branchRef", + "type": { + "text": "BranchRef | undefined" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "targetBranchRef", + "type": { + "text": "BranchRef | undefined" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "renderContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderHeader", + "privacy": "private", + "parameters": [ + { + "name": "title", + "type": { + "text": "string" + } + }, + { + "name": "icon", + "type": { + "text": "string" + } + }, + { + "name": "status", + "optional": true, + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "method", + "name": "renderHeaderActions", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderInlineTargetEdit", + "privacy": "private", + "parameters": [ + { + "name": "target", + "type": { + "text": "Awaited" + } + } + ] + }, + { + "kind": "method", + "name": "renderFiles", + "privacy": "private", + "parameters": [ + { + "name": "files", + "type": { + "text": "{ path: string }[]" + } + } + ] + }, + { + "kind": "method", + "name": "renderFile", + "privacy": "private", + "parameters": [ + { + "name": "path", + "type": { + "text": "string" + } + } + ] + } + ], + "attributes": [ + { + "name": "branch", + "type": { + "text": "Pick" + }, + "fieldName": "branch" + }, + { + "name": "targetPromise", + "type": { + "text": "GetOverviewBranch['mergeTarget']" + }, + "fieldName": "targetPromise" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-merge-target-status", + "customElement": true + }, + { + "kind": "class", + "description": "", + "name": "GlMergeTargetUpgrade", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-merge-target-upgrade", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlMergeTargetStatus", + "declaration": { + "name": "GlMergeTargetStatus", + "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-merge-target-status", + "declaration": { + "name": "GlMergeTargetStatus", + "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" + } + }, + { + "kind": "js", + "name": "GlMergeTargetUpgrade", + "declaration": { + "name": "GlMergeTargetUpgrade", + "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-merge-target-upgrade", + "declaration": { + "name": "GlMergeTargetUpgrade", + "module": "src/webviews/apps/plus/home/components/merge-target-status.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/overview.ts", + "declarations": [ + { + "kind": "variable", + "name": "overviewTagName", + "type": { + "text": "string" + }, + "default": "'gl-overview'" + }, + { + "kind": "class", + "description": "", + "name": "GlOverview", + "members": [ + { + "kind": "field", + "name": "_homeState", + "type": { + "text": "State" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_inactiveOverviewState", + "type": { + "text": "InactiveOverviewState" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "renderLoader", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPending", + "privacy": "private" + }, + { + "kind": "field", + "name": "_ipc", + "type": { + "text": "HostIpc" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "onChangeRecentThresholdFilter", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "renderComplete", + "privacy": "private", + "parameters": [ + { + "name": "overview", + "type": { + "text": "GetInactiveOverviewResponse" + } + }, + { + "name": "isFetching", + "default": "false" + } + ] + } + ], + "mixins": [ + { + "name": "SignalWatcher", + "package": "@lit-labs/signals" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "overviewTagName", + "declaration": { + "name": "overviewTagName", + "module": "src/webviews/apps/plus/home/components/overview.ts" + } + }, + { + "kind": "js", + "name": "GlOverview", + "declaration": { + "name": "GlOverview", + "module": "src/webviews/apps/plus/home/components/overview.ts" + } + }, + { + "kind": "custom-element-definition", + "declaration": { + "name": "GlOverview", + "module": "src/webviews/apps/plus/home/components/overview.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/home/components/overviewState.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "ActiveOverviewState", + "members": [ + { + "kind": "field", + "name": "_disposable", + "type": { + "text": "Disposable | undefined" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "dispose" + }, + { + "kind": "method", + "name": "changeRepository", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "field", + "name": "_debounce", + "type": { + "text": "number" + }, + "privacy": "private", + "default": "500", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_invalidate", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_computed", + "type": { + "text": "AsyncComputed | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_state", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "T | undefined" + }, + "readonly": true, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "computed", + "type": { + "text": "AsyncComputed" + }, + "readonly": true, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "_runCore", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_runDebounced", + "type": { + "text": "Deferrable<() => void> | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "_run", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "immediate", + "default": "false" + } + ], + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "run", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "force", + "default": "false" + } + ], + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "invalidate", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + } + ], + "superclass": { + "name": "AsyncComputedState", + "module": "/src/webviews/apps/shared/components/signal-utils" + } + }, + { + "kind": "class", + "description": "", + "name": "InactiveOverviewState", + "members": [ + { + "kind": "field", + "name": "_disposable", + "type": { + "text": "Disposable | undefined" + }, + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "filter" + }, + { + "kind": "method", + "name": "dispose", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "field", + "name": "_debounce", + "type": { + "text": "number" + }, + "privacy": "private", + "default": "500", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_invalidate", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_computed", + "type": { + "text": "AsyncComputed | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_state", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "T | undefined" + }, + "readonly": true, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "computed", + "type": { + "text": "AsyncComputed" + }, + "readonly": true, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "_runCore", + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "field", + "name": "_runDebounced", + "type": { + "text": "Deferrable<() => void> | undefined" + }, + "privacy": "private", + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "_run", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "immediate", + "default": "false" + } + ], + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "run", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "force", + "default": "false" + } + ], + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + }, + { + "kind": "method", + "name": "invalidate", + "return": { + "type": { + "text": "void" + } + }, + "inheritedFrom": { + "name": "AsyncComputedState", + "module": "src/webviews/apps/shared/components/signal-utils.ts" + } + } + ], + "superclass": { + "name": "AsyncComputedState", + "module": "/src/webviews/apps/shared/components/signal-utils" + } + }, + { + "kind": "variable", + "name": "activeOverviewStateContext" + }, + { + "kind": "variable", + "name": "inactiveOverviewStateContext" + } + ], + "exports": [ + { + "kind": "js", + "name": "ActiveOverviewState", + "declaration": { + "name": "ActiveOverviewState", + "module": "src/webviews/apps/plus/home/components/overviewState.ts" + } + }, + { + "kind": "js", + "name": "InactiveOverviewState", + "declaration": { + "name": "InactiveOverviewState", + "module": "src/webviews/apps/plus/home/components/overviewState.ts" + } + }, + { + "kind": "js", + "name": "activeOverviewStateContext", + "declaration": { + "name": "activeOverviewStateContext", + "module": "src/webviews/apps/plus/home/components/overviewState.ts" + } + }, + { + "kind": "js", + "name": "inactiveOverviewStateContext", + "declaration": { + "name": "inactiveOverviewStateContext", + "module": "src/webviews/apps/plus/home/components/overviewState.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlDraftDetails", + "members": [ + { + "kind": "field", + "name": "state", + "type": { + "text": "State" + }, + "attribute": "state" + }, + { + "kind": "field", + "name": "explainBusy", + "type": { + "text": "boolean" + }, + "default": "false" + }, + { + "kind": "field", + "name": "explain", + "type": { + "text": "ExplainState | undefined" + }, + "attribute": "explain" + }, + { + "kind": "field", + "name": "selectedPatches", + "type": { + "text": "string[]" + }, + "default": "[]" + }, + { + "kind": "field", + "name": "validityMessage", + "type": { + "text": "string | undefined" + } + }, + { + "kind": "field", + "name": "_copiedLink", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "cloudDraft", + "readonly": true + }, + { + "kind": "field", + "name": "isCodeSuggestion", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "canSubmit", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "method", + "name": "renderEmptyContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPatchMessage", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderExplainAi", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderChangedFiles", + "privacy": "private" + }, + { + "kind": "field", + "name": "treeModel", + "type": { + "text": "TreeModel[]" + }, + "readonly": true + }, + { + "kind": "method", + "name": "renderUserSelection", + "privacy": "private", + "parameters": [ + { + "name": "userSelection", + "type": { + "text": "DraftUserSelection" + } + }, + { + "name": "role", + "type": { + "text": "DraftRole" + } + } + ] + }, + { + "kind": "method", + "name": "renderUserSelectionList", + "privacy": "private", + "parameters": [ + { + "name": "draft", + "type": { + "text": "CloudDraftDetails" + } + }, + { + "name": "includeOwner", + "default": "false" + } + ] + }, + { + "kind": "method", + "name": "renderPatchPermissions", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderCodeSuggectionActions", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPatches", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderActionbar", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderDraftInfo", + "privacy": "private" + }, + { + "kind": "method", + "name": "onInviteUsers", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onChangeSelectionRole", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + }, + { + "name": "selection", + "type": { + "text": "DraftUserSelection" + } + }, + { + "name": "role", + "type": { + "text": "PatchDetailsUpdateSelectionEventDetail['role']" + } + } + ] + }, + { + "kind": "method", + "name": "onVisibilityChange", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onUpdatePatch", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onExplainChanges", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent | KeyboardEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onTreeItemActionClicked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "fireFileEvent", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + }, + { + "name": "file", + "type": { + "text": "DraftPatchFileChange" + } + }, + { + "name": "showOptions", + "optional": true, + "type": { + "text": "TextDocumentShowOptions" + } + } + ] + }, + { + "kind": "method", + "name": "onCompareWorking", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onOpenFile", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onTreeItemChecked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "onTreeItemSelected", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "onApplyPatch", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } + }, + { + "name": "target", + "default": "'current'", + "type": { + "text": "'current' | 'branch' | 'worktree'" + } + } + ] + }, + { + "kind": "method", + "name": "onArchiveDraft", + "privacy": "private", + "parameters": [ + { + "name": "reason", + "type": { + "text": "DraftReasonEventDetail['reason']" + } + } + ] + }, + { + "kind": "method", + "name": "onSelectApplyOption", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent<{ target: MenuItem }>" + } + } + ] + }, + { + "kind": "method", + "name": "onChangePatchBase", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onSelectPatchRepo", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onShowInGraph", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "optional": true, + "type": { + "text": "MouseEvent | KeyboardEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onCopyCloudLink", + "privacy": "private" + }, + { + "kind": "method", + "name": "onShareLocalPatch", + "privacy": "private" + }, + { + "kind": "method", + "name": "draftPatchToTreeModel", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "patch", + "type": { + "text": "NonNullable[0]" + } + }, + { + "name": "isTree", + "default": "false" + }, + { + "name": "compact", + "default": "true" + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + } + ] + }, + { + "kind": "method", + "name": "getFileActions", + "privacy": "protected", + "return": { + "type": { + "text": "{ icon: string; label: string; action: string }[]" + } + }, + "parameters": [ + { + "name": "_file", + "type": { + "text": "DraftPatchFileChange" + } + }, + { + "name": "_options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderLoading", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderLayoutAction", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | typeof nothing" + } + }, + "parameters": [ + { + "name": "layout", + "type": { + "text": "string" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderTreeView", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "parameters": [ + { + "name": "treeModel", + "type": { + "text": "TreeModel[]" + } + }, + { + "name": "guides", + "default": "'none'", + "type": { + "text": "'none' | 'onHover' | 'always'" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderFiles", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel[]" + } + }, + "parameters": [ + { + "name": "files", + "type": { + "text": "GitFileChangeShape[]" + } + }, + { + "name": "isTree", + "default": "false" + }, + { + "name": "compact", + "default": "false" + }, + { + "name": "level", + "default": "2" + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "walkFileTree", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "item", + "type": { + "text": "HierarchicalItem" + } + }, + { + "name": "options", + "default": "{ level: 1 }", + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "folderToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "getRepoActions", + "privacy": "protected", + "return": { + "type": { + "text": "TreeItemAction[]" + } + }, + "parameters": [ + { + "name": "_name", + "type": { + "text": "string" + } + }, + { + "name": "_path", + "type": { + "text": "string" + } + }, + { + "name": "_options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "emptyTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "repoToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + }, + { + "name": "path", + "type": { + "text": "string" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + }, + { + "name": "description", + "optional": true, + "type": { + "text": "string" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "fileToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, + "parameters": [ + { + "name": "file", + "type": { + "text": "GitFileChangeShape" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + }, + { + "name": "flat", + "default": "false" + }, + { + "name": "glue", + "default": "'/'" + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "state", + "type": { + "text": "State" + }, + "fieldName": "state" + }, + { + "name": "explain", + "type": { + "text": "ExplainState | undefined" + }, + "fieldName": "explain" + } + ], + "superclass": { + "name": "GlTreeBase", + "module": "/src/webviews/apps/plus/patchDetails/components/gl-tree-base" + }, + "tagName": "gl-draft-details", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlDraftDetails", + "declaration": { + "name": "GlDraftDetails", + "module": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-draft-details", + "declaration": { + "name": "GlDraftDetails", + "module": "src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlPatchCreate", + "members": [ + { + "kind": "field", + "name": "state", + "type": { + "text": "Serialized | undefined" + }, + "attribute": "state" + }, + { + "kind": "field", + "name": "review", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "review" + }, + { + "kind": "field", + "name": "generate", + "type": { + "text": "GenerateState | undefined" + }, + "attribute": "generate" + }, + { + "kind": "field", + "name": "generateBusy", + "type": { + "text": "boolean" + }, + "default": "false" + }, + { + "kind": "field", + "name": "creationBusy", + "type": { + "text": "boolean" + }, + "default": "false" + }, + { + "kind": "field", + "name": "titleInput", + "type": { + "text": "HTMLInputElement" + } + }, + { + "kind": "field", + "name": "descInput", + "type": { + "text": "HTMLInputElement" + } + }, + { + "kind": "field", + "name": "generateAiButton", + "type": { + "text": "HTMLElement" + } + }, + { + "kind": "field", + "name": "validityMessage", + "type": { + "text": "string | undefined" + } + }, + { + "kind": "field", + "name": "create", + "type": { + "text": "NonNullable" + }, + "readonly": true + }, + { + "kind": "field", + "name": "createChanges", + "type": { + "text": "Change[]" + }, + "readonly": true + }, + { + "kind": "field", + "name": "createEntries", + "type": { + "text": "[string, Change][]" + }, + "readonly": true + }, + { + "kind": "field", + "name": "hasWipChanges", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "selectedChanges", + "type": { + "text": "[string, Change][]" + }, + "readonly": true + }, + { + "kind": "field", + "name": "canSubmit", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "fileLayout", + "type": { + "text": "ViewFilesLayout" + }, + "readonly": true + }, + { + "kind": "field", + "name": "isCompact", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "filesModified", + "type": { + "text": "number" + }, + "readonly": true + }, + { + "kind": "field", + "name": "draftVisibility", + "type": { + "text": "DraftVisibility" + }, + "readonly": true + }, + { + "kind": "method", + "name": "renderUserSelection", + "privacy": "private", + "parameters": [ + { + "name": "userSelection", + "type": { + "text": "DraftUserSelection" + } + } + ] + }, + { + "kind": "method", + "name": "renderUserSelectionList", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderForm", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderChangedFiles", + "privacy": "private" + }, + { + "kind": "method", + "name": "onTreeItemChecked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "onTreeItemSelected", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderTreeViewWithModel", + "privacy": "private" + }, + { + "kind": "method", + "name": "getTreeForChange", + "privacy": "private", + "return": { + "type": { + "text": "TreeModel[] | undefined" + } + }, + "parameters": [ + { + "name": "change", + "type": { + "text": "Change" + } + }, + { + "name": "isMulti", + "default": "false" + }, + { + "name": "isTree", + "default": "false" + }, + { + "name": "compact", + "default": "true" + } + ] + }, + { + "kind": "method", + "name": "isTree", + "privacy": "private", + "parameters": [ + { + "name": "count", + "type": { + "text": "number" + } + } + ] + }, + { + "kind": "method", + "name": "createPatch", + "privacy": "private" + }, + { + "kind": "method", + "name": "onCreateAll", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onSelectCreateOption", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "CustomEvent<{ target: MenuItem }>" + } + } + ] + }, + { + "kind": "method", + "name": "getChangeForRepo", + "privacy": "private", + "return": { + "type": { + "text": "Change | undefined" + } + }, + "parameters": [ + { + "name": "repoUri", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "method", + "name": "onTitleInput", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "InputEvent" + } + } + ] + }, + { + "kind": "field", + "name": "onDebounceTitleInput", + "privacy": "private" + }, + { + "kind": "method", + "name": "onDescriptionInput", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "InputEvent" + } + } + ] + }, + { + "kind": "field", + "name": "onDebounceDescriptionInput", + "privacy": "private" + }, + { + "kind": "method", + "name": "onInviteUsers", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onChangeSelectionRole", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + }, + { + "name": "selection", + "type": { + "text": "DraftUserSelection" + } + }, + { + "name": "role", + "type": { + "text": "CreatePatchUpdateSelectionEventDetail['role']" + } + } + ] + }, + { + "kind": "method", + "name": "onVisibilityChange", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onGenerateTitleClick", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "fireMetadataUpdate", + "privacy": "private" + }, + { + "kind": "method", + "name": "onTreeItemActionClicked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "onOpenFile", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onStageFile", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onUnstageFile", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onShowInGraph", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "CustomEvent" + } + } + ] + }, + { + "kind": "method", + "name": "onCancel", + "privacy": "private" + }, + { + "kind": "method", + "name": "getFileActions", + "privacy": "protected", + "return": { + "type": { + "text": "{ icon: string; label: string; action: string }[]" + } + }, + "parameters": [ + { + "name": "file", + "type": { + "text": "GitFileChangeShape" + } + }, + { + "name": "_options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "getRepoActions", + "privacy": "protected", + "return": { + "type": { + "text": "{ icon: string; label: string; action: string }[]" + } + }, + "parameters": [ + { + "name": "_name", + "type": { + "text": "string" + } + }, + { + "name": "_path", + "type": { + "text": "string" + } + }, + { + "name": "_options", + "optional": true, + "type": { + "text": "Partial" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderLoading", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderLayoutAction", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | typeof nothing" + } + }, + "parameters": [ + { + "name": "layout", + "type": { + "text": "string" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderTreeView", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult" + } + }, + "parameters": [ + { + "name": "treeModel", + "type": { + "text": "TreeModel[]" + } + }, + { + "name": "guides", + "default": "'none'", + "type": { + "text": "'none' | 'onHover' | 'always'" + } + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, + { + "kind": "method", + "name": "renderFiles", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel[]" + } + }, + "parameters": [ + { + "name": "files", + "type": { + "text": "GitFileChangeShape[]" + } + }, + { + "name": "isTree", + "default": "false" + }, + { + "name": "compact", + "default": "false" + }, + { + "name": "level", + "default": "2" + } + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + }, { "kind": "method", - "name": "selectCommits", + "name": "walkFileTree", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "shaList", - "type": { - "text": "string[]" - } - }, - { - "name": "includeToPrevSel", + "name": "item", "type": { - "text": "boolean" + "text": "HierarchicalItem" } }, { - "name": "isAutoOrKeyScroll", + "name": "options", + "default": "{ level: 1 }", "type": { - "text": "boolean" + "text": "Partial" } } - ] + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } }, { "kind": "method", - "name": "onColumnsChanged", - "privacy": "private", + "name": "folderToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "event", + "name": "name", "type": { - "text": "CustomEventType<'graph-changecolumns'>" + "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "onGetMoreRows", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail: sha }", + "name": "options", + "optional": true, "type": { - "text": "CustomEventType<'graph-morerows'>" + "text": "Partial" } } - ] - }, - { - "kind": "method", - "name": "onMouseLeave", - "privacy": "private" + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } }, { "kind": "method", - "name": "onMissingAvatars", - "privacy": "private", + "name": "emptyTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "{ detail: emails }", + "name": "name", "type": { - "text": "CustomEventType<'graph-missingavatars'>" + "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "onMissingRefsMetadata", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail: metadata }", + "name": "options", + "optional": true, "type": { - "text": "CustomEventType<'graph-missingrefsmetadata'>" + "text": "Partial" } } - ] + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } }, { "kind": "method", - "name": "onRefDoubleClick", - "privacy": "private", + "name": "repoToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "{ detail: { ref, metadata } }", + "name": "name", "type": { - "text": "CustomEventType<'graph-doubleclickref'>" + "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "onRefsVisibilityChanged", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail }", + "name": "path", "type": { - "text": "CustomEventType<'graph-changerefsvisibility'>" + "text": "string" } - } - ] - }, - { - "kind": "method", - "name": "onRowContextMenu", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail: { graphRow, graphZoneType } }", + "name": "options", + "optional": true, "type": { - "text": "CustomEventType<'graph-rowcontextmenu'>" + "text": "Partial" } - } - ] - }, - { - "kind": "method", - "name": "onRowDoubleClick", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail: { row, preserveFocus } }", + "name": "description", + "optional": true, "type": { - "text": "CustomEventType<'graph-doubleclickrow'>" + "text": "string" } } - ] + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } }, { "kind": "method", - "name": "onRowHover", - "privacy": "private", + "name": "fileToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "{ detail }", + "name": "file", "type": { - "text": "CustomEventType<'graph-graphrowhovered'>" + "text": "GitFileChangeShape" } - } - ] - }, - { - "kind": "method", - "name": "onRowUnhover", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail }", + "name": "options", + "optional": true, "type": { - "text": "CustomEventType<'graph-graphrowunhovered'>" + "text": "Partial" } + }, + { + "name": "flat", + "default": "false" + }, + { + "name": "glue", + "default": "'/'" } - ] + ], + "inheritedFrom": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } }, { "kind": "method", - "name": "onSelectionChanged", - "privacy": "private", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, "parameters": [ { - "name": "{ detail: rows }", + "name": "name", "type": { - "text": "CustomEventType<'graph-changeselection'>" + "text": "T" } - } - ] - }, - { - "kind": "method", - "name": "onVisibleDaysChanged", - "privacy": "private", - "parameters": [ + }, { - "name": "{ detail }", + "name": "detail", "type": { - "text": "CustomEventType<'graph-changevisibledays'>" + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" } } - ] + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } } ], - "events": [ - { - "name": "gl-graph-mouse-leave", - "type": { - "text": "CustomEvent" - } - }, - { - "name": "gl-graph-row-context-menu", - "type": { - "text": "CustomEvent" - } - }, - { - "name": "gl-graph-row-hover", - "type": { - "text": "CustomEvent" - } - }, + "attributes": [ { - "name": "gl-graph-row-unhover", + "name": "state", "type": { - "text": "CustomEvent" - } + "text": "Serialized | undefined" + }, + "fieldName": "state" }, { - "name": "gl-graph-change-selection", + "name": "review", "type": { - "text": "CustomEvent" - } + "text": "boolean" + }, + "default": "false", + "fieldName": "review" }, { - "name": "gl-graph-change-visible-days", + "name": "generate", "type": { - "text": "CustomEvent" - } - } - ], - "mixins": [ - { - "name": "SignalWatcher", - "package": "@lit-labs/signals" + "text": "GenerateState | undefined" + }, + "fieldName": "generate" } ], "superclass": { - "name": "LitElement", - "package": "lit" + "name": "GlTreeBase", + "module": "/src/webviews/apps/plus/patchDetails/components/gl-tree-base" }, - "tagName": "gl-graph-wrapper", + "tagName": "gl-patch-create", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlGraphWrapper", + "name": "GlPatchCreate", "declaration": { - "name": "GlGraphWrapper", - "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts" + "name": "GlPatchCreate", + "module": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts" } }, { "kind": "custom-element-definition", - "name": "gl-graph-wrapper", + "name": "gl-patch-create", "declaration": { - "name": "GlGraphWrapper", - "module": "src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts" + "name": "GlPatchCreate", + "module": "src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/hover/graphHover.ts", + "path": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlGraphHover", + "name": "GlTreeBase", "members": [ { - "kind": "field", - "name": "anchor", - "type": { - "text": "Anchor | undefined" - }, - "attribute": "anchor" - }, - { - "kind": "field", - "name": "distance", - "type": { - "text": "number | undefined | undefined" - }, - "attribute": "distance", - "reflects": true - }, - { - "kind": "field", - "name": "open", - "type": { - "text": "boolean | undefined" - }, - "default": "false", - "attribute": "open", - "reflects": true - }, - { - "kind": "field", - "name": "placement", - "type": { - "text": "GlPopover['placement'] | undefined" - }, - "default": "'bottom-start'", - "attribute": "placement", - "reflects": true - }, - { - "kind": "field", - "name": "markdown", - "type": { - "text": "Promise> | string | undefined" + "kind": "method", + "name": "onTreeItemActionClicked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "attribute": "markdown" + "parameters": [ + { + "name": "_e", + "type": { + "text": "CustomEvent" + } + } + ] }, { - "kind": "field", - "name": "skidding", - "type": { - "text": "number | undefined | undefined" + "kind": "method", + "name": "onTreeItemChecked", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "attribute": "skidding", - "reflects": true + "parameters": [ + { + "name": "_e", + "type": { + "text": "CustomEvent" + } + } + ] }, { - "kind": "field", - "name": "requestMarkdown", - "type": { - "text": "((row: GraphRow) => Promise) | undefined" + "kind": "method", + "name": "onTreeItemSelected", + "privacy": "protected", + "return": { + "type": { + "text": "void" + } }, - "attribute": "requestMarkdown" + "parameters": [ + { + "name": "_e", + "type": { + "text": "CustomEvent" + } + } + ] }, { - "kind": "field", - "name": "popup", - "type": { - "text": "GlPopover" + "kind": "method", + "name": "renderLoading", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult" + } } }, - { - "kind": "field", - "name": "hoverMarkdownCache", - "privacy": "private", - "default": "new Map< string, Promise> | PromiseSettledResult | string >()" - }, - { - "kind": "field", - "name": "shaHovering", - "type": { - "text": "string | undefined" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "unhoverTimer", - "type": { - "text": "ReturnType | undefined" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "previousSkidding", - "type": { - "text": "number | undefined" - }, - "privacy": "private" - }, - { - "kind": "field", - "name": "recalculated", - "type": { - "text": "boolean" - }, - "privacy": "private", - "default": "false" - }, { "kind": "method", - "name": "onReposition", - "privacy": "private" + "name": "renderLayoutAction", + "privacy": "protected", + "return": { + "type": { + "text": "TemplateResult | typeof nothing" + } + }, + "parameters": [ + { + "name": "layout", + "type": { + "text": "string" + } + } + ] }, { "kind": "method", - "name": "reset", + "name": "renderTreeView", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TemplateResult" } - } - }, - { - "kind": "field", - "name": "onParentMouseLeave", - "privacy": "private" - }, - { - "kind": "field", - "name": "_showCoreDebounced", - "type": { - "text": "Deferrable | undefined" }, - "privacy": "private", - "default": "undefined" + "parameters": [ + { + "name": "treeModel", + "type": { + "text": "TreeModel[]" + } + }, + { + "name": "guides", + "default": "'none'", + "type": { + "text": "'none' | 'onHover' | 'always'" + } + } + ] }, { "kind": "method", - "name": "onRowHovered", + "name": "renderFiles", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeModel[]" } }, "parameters": [ { - "name": "row", + "name": "files", "type": { - "text": "GraphRow" + "text": "GitFileChangeShape[]" } }, { - "name": "anchor", - "type": { - "text": "Anchor" - } + "name": "isTree", + "default": "false" + }, + { + "name": "compact", + "default": "false" + }, + { + "name": "level", + "default": "2" } ] }, { "kind": "method", - "name": "onRowUnhovered", + "name": "walkFileTree", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeModel" } }, "parameters": [ { - "name": "_row", + "name": "item", "type": { - "text": "GraphRow" + "text": "HierarchicalItem" } }, { - "name": "relatedTarget", + "name": "options", + "default": "{ level: 1 }", "type": { - "text": "EventTarget | null" + "text": "Partial" } } ] }, - { - "kind": "field", - "name": "onWindowKeydown", - "privacy": "private" - }, { "kind": "method", - "name": "showCore", - "privacy": "private", + "name": "folderToTreeModel", + "privacy": "protected", + "return": { + "type": { + "text": "TreeModel" + } + }, "parameters": [ { - "name": "anchor", + "name": "name", "type": { - "text": "string | HTMLElement | { getBoundingClientRect: () => Omit }" + "text": "string" } }, { - "name": "markdown", + "name": "options", + "optional": true, "type": { - "text": "Promise> | PromiseSettledResult | string" + "text": "Partial" } } ] }, - { - "kind": "field", - "name": "_lastUnhoveredTimestamp", - "type": { - "text": "number" - }, - "privacy": "private", - "default": "0" - }, { "kind": "method", - "name": "hide", + "name": "getRepoActions", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeItemAction[]" } - } + }, + "parameters": [ + { + "name": "_name", + "type": { + "text": "string" + } + }, + { + "name": "_path", + "type": { + "text": "string" + } + }, + { + "name": "_options", + "optional": true, + "type": { + "text": "Partial" + } + } + ] }, { "kind": "method", - "name": "resetUnhoverTimer", - "privacy": "private", + "name": "emptyTreeModel", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeModel" } - } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "string" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Partial" + } + } + ] }, { "kind": "method", - "name": "emit", + "name": "repoToTreeModel", + "privacy": "protected", "return": { "type": { - "text": "CustomEventType" + "text": "TreeModel" } }, "parameters": [ { "name": "name", "type": { - "text": "T" + "text": "string" } }, { - "name": "detail", + "name": "path", "type": { - "text": "CustomEventDetailType" + "text": "string" } }, { "name": "options", "optional": true, "type": { - "text": "Omit>, 'detail'>" + "text": "Partial" } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ - { - "name": "anchor", - "type": { - "text": "Anchor | undefined" - }, - "fieldName": "anchor" - }, - { - "name": "distance", - "type": { - "text": "number | undefined | undefined" - }, - "fieldName": "distance" - }, - { - "name": "open", - "type": { - "text": "boolean | undefined" - }, - "default": "false", - "fieldName": "open" - }, - { - "name": "placement", - "type": { - "text": "GlPopover['placement'] | undefined" - }, - "default": "'bottom-start'", - "fieldName": "placement" - }, - { - "name": "markdown", - "type": { - "text": "Promise> | string | undefined" - }, - "fieldName": "markdown" - }, - { - "name": "skidding", - "type": { - "text": "number | undefined | undefined" - }, - "fieldName": "skidding" - }, - { - "name": "requestMarkdown", - "type": { - "text": "((row: GraphRow) => Promise) | undefined" - }, - "fieldName": "requestMarkdown" - } - ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - }, - "tagName": "gl-graph-hover", - "customElement": true - } - ], - "exports": [ - { - "kind": "js", - "name": "GlGraphHover", - "declaration": { - "name": "GlGraphHover", - "module": "src/webviews/apps/plus/graph/hover/graphHover.ts" - } - }, - { - "kind": "custom-element-definition", - "name": "gl-graph-hover", - "declaration": { - "name": "GlGraphHover", - "module": "src/webviews/apps/plus/graph/hover/graphHover.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/minimap/minimap-container.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlGraphMinimapContainer", - "members": [ - { - "kind": "field", - "name": "activeDay", - "type": { - "text": "number | undefined" - }, - "attribute": "activeDay" - }, - { - "kind": "field", - "name": "disabled", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "disabled" - }, - { - "kind": "method", - "name": "onDisabledChanged", - "privacy": "private" - }, - { - "kind": "field", - "name": "dataType", - "type": { - "text": "'commits' | 'lines'" - }, - "default": "'commits'", - "attribute": "dataType" - }, - { - "kind": "field", - "name": "downstreams", - "type": { - "text": "GraphDownstreams | undefined" - }, - "attribute": "downstreams" - }, - { - "kind": "field", - "name": "markerTypes", - "type": { - "text": "GraphMinimapMarkerTypes[]" - }, - "default": "[]", - "attribute": "markerTypes" - }, - { - "kind": "field", - "name": "refMetadata", - "type": { - "text": "GraphRefsMetadata | null | undefined" - }, - "attribute": "refMetadata" - }, - { - "kind": "field", - "name": "rows", - "type": { - "text": "GraphRow[]" - }, - "default": "[]", - "attribute": "rows" - }, - { - "kind": "field", - "name": "rowsStats", - "type": { - "text": "Record | undefined" - }, - "attribute": "rowsStats" - }, - { - "kind": "field", - "name": "searchResults", - "type": { - "text": "GraphSearchResults | GraphSearchResultsError | undefined" - }, - "attribute": "searchResults" - }, - { - "kind": "field", - "name": "visibleDays", - "type": { - "text": "{ top: number; bottom: number } | undefined" - }, - "attribute": "visibleDays" - }, - { - "kind": "field", - "name": "markersByDay", - "privacy": "private", - "default": "new Map()" - }, - { - "kind": "field", - "name": "searchResultsByDay", - "privacy": "private", - "default": "new Map()" - }, - { - "kind": "field", - "name": "statsByDay", - "privacy": "private", - "default": "new Map()" - }, - { - "kind": "field", - "name": "pendingDataChange", - "type": { - "text": "boolean" - }, - "privacy": "private", - "default": "false" - }, - { - "kind": "method", - "name": "handleDataChanged", - "privacy": "private", - "parameters": [ + }, { - "name": "changedKeys", + "name": "description", + "optional": true, "type": { - "text": "PropertyKey[]" + "text": "string" } } ] }, - { - "kind": "field", - "name": "pendingSearchResultsChange", - "type": { - "text": "boolean" - }, - "privacy": "private", - "default": "false" - }, - { - "kind": "method", - "name": "handleSearchResultsChanged", - "privacy": "private" - }, - { - "kind": "field", - "name": "minimap", - "type": { - "text": "GlGraphMinimap | undefined" - }, - "privacy": "private" - }, { "kind": "method", - "name": "select", + "name": "getFileActions", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeItemAction[]" } }, "parameters": [ { - "name": "date", + "name": "_file", "type": { - "text": "number | Date | undefined" + "text": "GitFileChangeShape" } }, { - "name": "trackOnly", - "default": "false", + "name": "_options", + "optional": true, "type": { - "text": "boolean" + "text": "Partial" } } ] }, { "kind": "method", - "name": "unselect", + "name": "fileToTreeModel", + "privacy": "protected", "return": { "type": { - "text": "void" + "text": "TreeModel" } }, "parameters": [ { - "name": "date", - "optional": true, + "name": "file", "type": { - "text": "number | Date" + "text": "GitFileChangeShape" } }, { - "name": "focus", - "default": "false", + "name": "options", + "optional": true, "type": { - "text": "boolean" + "text": "Partial" } + }, + { + "name": "flat", + "default": "false" + }, + { + "name": "glue", + "default": "'/'" } ] }, - { - "kind": "method", - "name": "processRows", - "privacy": "private" - }, - { - "kind": "method", - "name": "processSearchResults", - "privacy": "private" - }, { "kind": "method", "name": "emit", @@ -23946,539 +29051,737 @@ } } ], - "attributes": [ + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "GlTreeBase", + "declaration": { + "name": "GlTreeBase", + "module": "src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlPatchDetailsApp", + "members": [ { - "name": "activeDay", + "kind": "field", + "name": "state", "type": { - "text": "number | undefined" + "text": "State" }, - "fieldName": "activeDay" + "attribute": "state" }, { - "name": "disabled", + "kind": "field", + "name": "explain", "type": { - "text": "boolean" + "text": "ExplainState | undefined" }, - "default": "false", - "fieldName": "disabled" + "attribute": "explain" }, { - "name": "dataType", + "kind": "field", + "name": "generate", "type": { - "text": "'commits' | 'lines'" + "text": "GenerateState | undefined" }, - "default": "'commits'", - "fieldName": "dataType" + "attribute": "generate" }, { - "name": "downstreams", + "kind": "field", + "name": "app", "type": { - "text": "GraphDownstreams | undefined" - }, - "fieldName": "downstreams" + "text": "PatchDetailsApp | undefined" + } }, { - "name": "markerTypes", + "kind": "field", + "name": "wipChangesCount", "type": { - "text": "GraphMinimapMarkerTypes[]" + "text": "number" }, - "default": "[]", - "fieldName": "markerTypes" + "readonly": true }, { - "name": "refMetadata", + "kind": "field", + "name": "wipChangeState", + "readonly": true + }, + { + "kind": "field", + "name": "mode", "type": { - "text": "GraphRefsMetadata | null | undefined" + "text": "Mode" }, - "fieldName": "refMetadata" + "readonly": true }, { - "name": "rows", + "kind": "field", + "name": "indentPreference", "type": { - "text": "GraphRow[]" + "text": "number" }, - "default": "[]", - "fieldName": "rows" + "privacy": "private", + "default": "16" }, { - "name": "rowsStats", + "kind": "method", + "name": "updateDocumentProperties", + "privacy": "private" + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "state", "type": { - "text": "Record | undefined" + "text": "State" }, - "fieldName": "rowsStats" + "fieldName": "state" }, { - "name": "searchResults", + "name": "explain", "type": { - "text": "GraphSearchResults | GraphSearchResultsError | undefined" + "text": "ExplainState | undefined" }, - "fieldName": "searchResults" + "fieldName": "explain" }, { - "name": "visibleDays", + "name": "generate", "type": { - "text": "{ top: number; bottom: number } | undefined" + "text": "GenerateState | undefined" }, - "fieldName": "visibleDays" + "fieldName": "generate" } ], "superclass": { "name": "GlElement", "module": "/src/webviews/apps/shared/components/element" }, - "tagName": "gl-graph-minimap-container", + "tagName": "gl-patch-details-app", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlGraphMinimapContainer", + "name": "GlPatchDetailsApp", "declaration": { - "name": "GlGraphMinimapContainer", - "module": "src/webviews/apps/plus/graph/minimap/minimap-container.ts" + "name": "GlPatchDetailsApp", + "module": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts" } }, { "kind": "custom-element-definition", - "name": "gl-graph-minimap-container", + "name": "gl-patch-details-app", "declaration": { - "name": "GlGraphMinimapContainer", - "module": "src/webviews/apps/plus/graph/minimap/minimap-container.ts" + "name": "GlPatchDetailsApp", + "module": "src/webviews/apps/plus/patchDetails/components/patch-details-app.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/minimap/minimap.ts", + "path": "src/webviews/apps/plus/shared/components/account-chip.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlGraphMinimap", + "name": "GlAccountChip", "members": [ { "kind": "field", - "name": "chartContainer", + "name": "shadowRootOptions", "type": { - "text": "HTMLDivElement" - } + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" }, { "kind": "field", - "name": "_chart", + "name": "_showUpgrade", "type": { - "text": "Chart" + "text": "boolean" }, - "privacy": "private" + "privacy": "private", + "default": "false" }, { "kind": "field", - "name": "spinner", - "type": { - "text": "HTMLDivElement" - } + "name": "showUpgrade", + "privacy": "private", + "attribute": "show-upgrade", + "reflects": true }, { "kind": "field", - "name": "_loadTimer", + "name": "_chip", "type": { - "text": "ReturnType | undefined" + "text": "HTMLElement" }, "privacy": "private" }, { "kind": "field", - "name": "_markerRegions", + "name": "_popover", "type": { - "text": "Iterable | undefined" + "text": "GlPopover" }, "privacy": "private" }, { "kind": "field", - "name": "_regions", + "name": "_state", "type": { - "text": "RegionOptions[] | undefined" + "text": "State" }, "privacy": "private" }, { "kind": "field", - "name": "activeDay", - "type": { - "text": "number | undefined" - }, - "attribute": "activeDay" + "name": "accountAvatar", + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onActiveDayChanged", - "privacy": "private" + "kind": "field", + "name": "accountName", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "data", - "type": { - "text": "Map | undefined" - }, - "attribute": "data" + "name": "accountEmail", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "dataType", + "name": "hasAccount", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "isReactivatedTrial", "type": { - "text": "'commits' | 'lines'" + "text": "boolean" }, - "default": "'commits'", - "attribute": "dataType" + "readonly": true }, { - "kind": "method", - "name": "onDataChanged", - "privacy": "private" + "kind": "field", + "name": "planId", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "markers", - "type": { - "text": "Map | undefined" - }, - "attribute": "markers" + "name": "effectivePlanId", + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onMarkersChanged", - "privacy": "private" + "kind": "field", + "name": "planName", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "searchResults", - "type": { - "text": "Map | undefined" - }, - "attribute": "searchResults" + "name": "planTier", + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onSearchResultsChanged", + "kind": "field", + "name": "promos", + "type": { + "text": "PromosContext" + }, "privacy": "private" }, { "kind": "field", - "name": "visibleDays", - "type": { - "text": "{ top: number; bottom: number } | undefined" - }, - "attribute": "visibleDays" + "name": "subscription", + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "onVisibleDaysChanged", - "privacy": "private" + "kind": "field", + "name": "subscriptionState", + "privacy": "private", + "readonly": true }, { - "kind": "method", - "name": "handleDataChanged", + "kind": "field", + "name": "trialDaysRemaining", "privacy": "private", - "parameters": [ - { - "name": "markerChanged", - "type": { - "text": "boolean" - } - } - ] + "readonly": true }, { "kind": "method", - "name": "getInternalChart", - "privacy": "private", + "name": "focus", "return": { "type": { - "text": "ChartInternal | undefined" + "text": "void" } } }, { "kind": "method", - "name": "select", + "name": "show", "return": { "type": { "text": "void" } - }, - "parameters": [ - { - "name": "date", - "type": { - "text": "number | Date | undefined" - } - }, - { - "name": "trackOnly", - "default": "false", - "type": { - "text": "boolean" - } - } - ] + } }, { "kind": "method", - "name": "unselect", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "date", - "optional": true, - "type": { - "text": "number | Date" - } - }, - { - "name": "focus", - "default": "false", - "type": { - "text": "boolean" - } - } - ] + "name": "renderAccountInfo", + "privacy": "private" }, { "kind": "method", - "name": "getDataPoint", - "privacy": "private", - "return": { - "type": { - "text": "DataItem | undefined" - } - }, - "parameters": [ - { - "name": "date", - "type": { - "text": "number | Date" - } - } - ] + "name": "renderAccountState", + "privacy": "private" }, { "kind": "method", - "name": "getIndex", - "privacy": "private", - "return": { - "type": { - "text": "number | undefined" - } - }, - "parameters": [ - { - "name": "date", - "type": { - "text": "number | Date" - } - } - ] + "name": "renderIncludesDevEx", + "privacy": "private" }, { "kind": "method", - "name": "getMarkerRegions", + "name": "renderReferFriend", "privacy": "private" }, { "kind": "method", - "name": "getAllRegions", + "name": "renderUpgradeContent", "privacy": "private" }, { "kind": "method", - "name": "getSearchResultsRegions", + "name": "renderPromo", "privacy": "private", "return": { "type": { - "text": "Iterable" + "text": "unknown" } }, "parameters": [ { - "name": "searchResults", + "name": "plan", "type": { - "text": "NonNullable" + "text": "PromoPlans" } - } - ] - }, - { - "kind": "method", - "name": "getVisibleAreaRegion", - "privacy": "private", - "return": { - "type": { - "text": "RegionOptions" - } - }, - "parameters": [ + }, { - "name": "visibleDays", + "name": "type", + "default": "'info'", "type": { - "text": "NonNullable" + "text": "GlPromo['type']" + } + }, + { + "name": "slot", + "optional": true, + "type": { + "text": "string" } } ] + } + ], + "attributes": [ + { + "name": "show-upgrade", + "fieldName": "showUpgrade" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-account-chip", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlAccountChip", + "declaration": { + "name": "GlAccountChip", + "module": "src/webviews/apps/plus/shared/components/account-chip.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-account-chip", + "declaration": { + "name": "GlAccountChip", + "module": "src/webviews/apps/plus/shared/components/account-chip.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/shared/components/chipStyles.ts", + "declarations": [ + { + "kind": "variable", + "name": "chipStyles", + "default": "css` :host { display: flex; } .chip { display: flex; gap: 0.6rem; align-items: center; border-radius: 0.3rem; padding: 0.2rem 0.4rem; cursor: pointer; } .chip:focus-visible { ${focusOutline} } .content { display: flex; flex-direction: column; gap: 0.4rem; padding-bottom: 0.4rem; } .header { display: flex; align-items: center; gap: 0.6rem; width: 100%; padding-bottom: 0.4rem; } .header__actions { flex: none; display: flex; gap: 0.2rem; flex-direction: row; align-items: center; justify-content: center; } .header__title { flex: 1; font-size: 1.5rem; line-height: 1.7; font-weight: 600; margin: 0; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "chipStyles", + "declaration": { + "name": "chipStyles", + "module": "src/webviews/apps/plus/shared/components/chipStyles.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlFeatureGatePlusState", + "members": [ + { + "kind": "field", + "name": "button", + "type": { + "text": "GlButton" + }, + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "_loading", + "name": "featurePreview", "type": { - "text": "Promise | undefined" + "text": "FeaturePreview | undefined" }, - "privacy": "private" + "attribute": "featurePreview" }, { - "kind": "method", - "name": "loadChart", - "privacy": "private" + "kind": "field", + "name": "featurePreviewCommandLink", + "type": { + "text": "string | undefined" + }, + "attribute": "featurePreviewCommandLink" }, { - "kind": "method", - "name": "loadChartCore", + "kind": "field", + "name": "appearance", + "type": { + "text": "'alert' | 'welcome' | undefined" + }, + "attribute": "appearance" + }, + { + "kind": "field", + "name": "featureWithArticleIfNeeded", + "type": { + "text": "string | undefined" + }, + "attribute": "featureWithArticleIfNeeded" + }, + { + "kind": "field", + "name": "promos", + "type": { + "text": "PromosContext" + }, "privacy": "private" }, { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } + "kind": "field", + "name": "source", + "type": { + "text": "Source | undefined" + }, + "attribute": "source" + }, + { + "kind": "field", + "name": "state", + "type": { + "text": "SubscriptionState | undefined" + } + }, + { + "kind": "field", + "name": "webroot", + "type": { + "text": "string | undefined" }, + "attribute": "webroot" + }, + { + "kind": "method", + "name": "renderFeaturePreview", + "privacy": "private", "parameters": [ { - "name": "name", + "name": "featurePreview", "type": { - "text": "T" + "text": "FeaturePreview" } - }, + } + ] + }, + { + "kind": "method", + "name": "renderFeaturePreviewStep", + "privacy": "private", + "parameters": [ { - "name": "detail", + "name": "featurePreview", "type": { - "text": "CustomEventDetailType" + "text": "FeaturePreview" } }, { - "name": "options", - "optional": true, + "name": "used", "type": { - "text": "Omit>, 'detail'>" + "text": "number" } } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } + ] + }, + { + "kind": "method", + "name": "renderPromo", + "privacy": "private" } ], "attributes": [ { - "name": "activeDay", + "name": "featurePreview", "type": { - "text": "number | undefined" + "text": "FeaturePreview | undefined" }, - "fieldName": "activeDay" + "fieldName": "featurePreview" }, { - "name": "data", + "name": "featurePreviewCommandLink", "type": { - "text": "Map | undefined" + "text": "string | undefined" }, - "fieldName": "data" + "fieldName": "featurePreviewCommandLink" }, { - "name": "dataType", + "name": "appearance", "type": { - "text": "'commits' | 'lines'" + "text": "'alert' | 'welcome' | undefined" }, - "default": "'commits'", - "fieldName": "dataType" + "fieldName": "appearance" }, { - "name": "markers", + "name": "featureWithArticleIfNeeded", "type": { - "text": "Map | undefined" + "text": "string | undefined" }, - "fieldName": "markers" + "fieldName": "featureWithArticleIfNeeded" }, { - "name": "searchResults", + "name": "source", "type": { - "text": "Map | undefined" + "text": "Source | undefined" }, - "fieldName": "searchResults" + "fieldName": "source" }, { - "name": "visibleDays", + "name": "webroot", "type": { - "text": "{ top: number; bottom: number } | undefined" + "text": "string | undefined" }, - "fieldName": "visibleDays" + "fieldName": "webroot" } ], "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" + "name": "LitElement", + "package": "lit" }, - "tagName": "gl-graph-minimap", + "tagName": "gl-feature-gate-plus-state", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlGraphMinimap", + "name": "GlFeatureGatePlusState", "declaration": { - "name": "GlGraphMinimap", - "module": "src/webviews/apps/plus/graph/minimap/minimap.ts" + "name": "GlFeatureGatePlusState", + "module": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts" } }, { "kind": "custom-element-definition", - "name": "gl-graph-minimap", + "name": "gl-feature-gate-plus-state", "declaration": { - "name": "GlGraphMinimap", - "module": "src/webviews/apps/plus/graph/minimap/minimap.ts" + "name": "GlFeatureGatePlusState", + "module": "src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/sidebar/sidebar.ts", + "path": "src/webviews/apps/plus/shared/components/home-header.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlGraphSideBar", + "name": "GlHomeHeader", "members": [ { "kind": "field", - "name": "include", + "name": "accountChip", "type": { - "text": "undefined | IconTypes[]" + "text": "GlAccountChip" }, - "readonly": true + "privacy": "private" }, { "kind": "field", - "name": "_ipc", + "name": "promoBanner", "type": { - "text": "HostIpc" + "text": "GlPromoBanner" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "show", + "return": { + "type": { + "text": "void" + } + } + }, + { + "kind": "method", + "name": "refreshPromo", + "return": { + "type": { + "text": "void" + } + } + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-home-header", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlHomeHeader", + "declaration": { + "name": "GlHomeHeader", + "module": "src/webviews/apps/plus/shared/components/home-header.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-home-header", + "declaration": { + "name": "GlHomeHeader", + "module": "src/webviews/apps/plus/shared/components/home-header.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/shared/components/integrations-chip.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlIntegrationsChip", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "_chip", + "type": { + "text": "HTMLElement" }, "privacy": "private" }, @@ -24488,180 +29791,382 @@ "type": { "text": "State" }, + "privacy": "private" + }, + { + "kind": "field", + "name": "hasAccount", "privacy": "private", "readonly": true }, { "kind": "field", - "name": "_disposable", - "type": { - "text": "Disposable | undefined" - }, - "privacy": "private" + "name": "isPaidAccount", + "privacy": "private", + "readonly": true }, { "kind": "field", - "name": "_countsTask", + "name": "isProAccount", "privacy": "private", - "default": "new Task(this, { args: () => [this.fetchCounts()], task: ([counts]) => counts, autoRun: false, })" + "readonly": true }, { "kind": "field", - "name": "_counts", - "type": { - "text": "Promise | undefined" - }, - "privacy": "private" + "name": "hasConnectedIntegrations", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "ai", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "aiSettingEnabled", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "aiOrgEnabled", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "aiEnabled", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "integrations", + "privacy": "private", + "readonly": true }, { "kind": "method", - "name": "fetchCounts", - "privacy": "private" + "name": "focus", + "return": { + "type": { + "text": "void" + } + } }, { "kind": "method", - "name": "renderIcon", + "name": "renderIntegrationStatus", "privacy": "private", "parameters": [ { - "name": "icon", + "name": "integration", "type": { - "text": "Icon" + "text": "IntegrationState" } } ] }, { "kind": "method", - "name": "sendTelemetry", + "name": "renderIntegrationRow", "privacy": "private", "parameters": [ { - "name": "command", + "name": "integration", "type": { - "text": "string" + "text": "IntegrationState" } } ] + }, + { + "kind": "method", + "name": "renderAIStatus", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderAIRow", + "privacy": "private" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-graph-sidebar", + "tagName": "gl-integrations-chip", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlGraphSideBar", + "name": "GlIntegrationsChip", "declaration": { - "name": "GlGraphSideBar", - "module": "src/webviews/apps/plus/graph/sidebar/sidebar.ts" + "name": "GlIntegrationsChip", + "module": "src/webviews/apps/plus/shared/components/integrations-chip.ts" } }, { "kind": "custom-element-definition", - "name": "gl-graph-sidebar", + "name": "gl-integrations-chip", "declaration": { - "name": "GlGraphSideBar", - "module": "src/webviews/apps/plus/graph/sidebar/sidebar.ts" + "name": "GlIntegrationsChip", + "module": "src/webviews/apps/plus/shared/components/integrations-chip.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/styles/graph.css.ts", + "path": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts", "declarations": [ { - "kind": "variable", - "name": "linkBase", - "default": "css` a { text-decoration: none; } a:focus { ${focusOutline} } a:hover { text-decoration: underline; } `" - }, - { - "kind": "variable", - "name": "actionButton", - "default": "css` .action-button { position: relative; appearance: none; font-family: inherit; font-size: 1.2rem; line-height: 2.2rem; // background-color: var(--color-graph-actionbar-background); background-color: transparent; border: none; color: inherit; color: var(--color-foreground); padding: 0 0.75rem; cursor: pointer; border-radius: 3px; height: auto; display: grid; grid-auto-flow: column; grid-gap: 0.5rem; gap: 0.5rem; max-width: fit-content; } .action-button[disabled] { pointer-events: none; cursor: default; opacity: 1; } .action-button:hover { background-color: var(--color-graph-actionbar-selectedBackground); color: var(--color-foreground); text-decoration: none; } .action-button[aria-checked] { border: 1px solid transparent; } .action-button[aria-checked='true'] { background-color: var(--vscode-inputOption-activeBackground); color: var(--vscode-inputOption-activeForeground); border-color: var(--vscode-inputOption-activeBorder); } .action-button code-icon { line-height: 2.2rem; vertical-align: bottom; } .action-button code-icon[icon='graph-line'] { transform: translateY(1px); } .is-ahead .action-button__pill { background-color: var(--branch-status-ahead-pill-background); } .is-behind .action-button__pill { background-color: var(--branch-status-behind-pill-background); } .is-ahead.is-behind .action-button__pill { background-color: var(--branch-status-both-pill-background); } .action-button__more, .action-button__more.codicon[class*='codicon-'] { font-size: 1rem; margin-right: -0.25rem; } code-icon.action-button__more::before { margin-left: -0.25rem; } .action-button__indicator { margin-left: -0.2rem; --gl-indicator-color: green; --gl-indicator-size: 0.4rem; } .action-button__small { font-size: smaller; opacity: 0.6; text-overflow: ellipsis; overflow: hidden; } .action-button.is-ahead { background-color: var(--branch-status-ahead-background); } .action-button.is-ahead:hover { background-color: var(--branch-status-ahead-hover-background); } .action-button.is-behind { background-color: var(--branch-status-behind-background); } .action-button.is-behind:hover { background-color: var(--branch-status-behind-hover-background); } .action-button.is-ahead.is-behind { background-color: var(--branch-status-both-background); } .action-button.is-ahead.is-behind:hover { background-color: var(--branch-status-both-hover-background); } `" + "kind": "class", + "description": "", + "name": "GlMergeConflictWarning", + "members": [ + { + "kind": "field", + "name": "conflicts", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "conflicts", + "reflects": true + }, + { + "kind": "field", + "name": "pausedOpStatus", + "type": { + "text": "GitPausedOperationStatus | undefined" + }, + "attribute": "pausedOpStatus" + }, + { + "kind": "field", + "name": "skipCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.skipPausedOperation'", + "attribute": "skipCommand" + }, + { + "kind": "field", + "name": "continueCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.continuePausedOperation'", + "attribute": "continueCommand" + }, + { + "kind": "field", + "name": "abortCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.abortPausedOperation'", + "attribute": "abortCommand" + }, + { + "kind": "field", + "name": "openEditorCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.openRebaseEditor'", + "attribute": "openEditorCommand" + }, + { + "kind": "field", + "name": "webviewCommandContext", + "type": { + "text": "{ webview: string; webviewInstance: string | undefined } | undefined" + }, + "attribute": "webviewCommandContext" + }, + { + "kind": "field", + "name": "onSkipUrl", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "onContinueUrl", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "onAbortUrl", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "onOpenEditorUrl", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "createCommandLink", + "privacy": "private", + "parameters": [ + { + "name": "command", + "type": { + "text": "string" + } + }, + { + "name": "args", + "optional": true, + "type": { + "text": "any" + } + } + ] + }, + { + "kind": "method", + "name": "renderStatus", + "privacy": "private", + "parameters": [ + { + "name": "pausedOpStatus", + "type": { + "text": "GitPausedOperationStatus" + } + } + ] + }, + { + "kind": "method", + "name": "renderActions", + "privacy": "private" + } + ], + "attributes": [ + { + "name": "conflicts", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "conflicts" + }, + { + "name": "pausedOpStatus", + "type": { + "text": "GitPausedOperationStatus | undefined" + }, + "fieldName": "pausedOpStatus" + }, + { + "name": "skipCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.skipPausedOperation'", + "fieldName": "skipCommand" + }, + { + "name": "continueCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.continuePausedOperation'", + "fieldName": "continueCommand" + }, + { + "name": "abortCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.abortPausedOperation'", + "fieldName": "abortCommand" + }, + { + "name": "openEditorCommand", + "type": { + "text": "string" + }, + "default": "'gitlens.home.openRebaseEditor'", + "fieldName": "openEditorCommand" + }, + { + "name": "webviewCommandContext", + "type": { + "text": "{ webview: string; webviewInstance: string | undefined } | undefined" + }, + "fieldName": "webviewCommandContext" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-merge-rebase-status", + "customElement": true } ], "exports": [ { "kind": "js", - "name": "linkBase", + "name": "GlMergeConflictWarning", "declaration": { - "name": "linkBase", - "module": "src/webviews/apps/plus/graph/styles/graph.css.ts" + "name": "GlMergeConflictWarning", + "module": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts" } }, { - "kind": "js", - "name": "actionButton", + "kind": "custom-element-definition", + "name": "gl-merge-rebase-status", "declaration": { - "name": "actionButton", - "module": "src/webviews/apps/plus/graph/styles/graph.css.ts" + "name": "GlMergeConflictWarning", + "module": "src/webviews/apps/plus/shared/components/merge-rebase-status.ts" } } ] }, { "kind": "javascript-module", - "path": "src/webviews/apps/plus/graph/styles/header.css.ts", + "path": "src/webviews/apps/plus/shared/components/vscode.css.ts", "declarations": [ { "kind": "variable", - "name": "repoHeaderStyles", - "default": "css` .jump-to-ref { --button-foreground: var(--color-foreground); } .merge-conflict-warning { flex: 0 0 100%; min-width: 0; } `" - }, - { - "kind": "variable", - "name": "progressStyles", - "default": "css` .progress-container { position: absolute; left: 0; bottom: 0; z-index: 5; height: 2px; width: 100%; overflow: hidden; } .progress-container .progress-bar { background-color: var(--vscode-progressBar-background); display: none; position: absolute; left: 0; width: 2%; height: 2px; } .progress-container.active .progress-bar { display: inherit; } .progress-container.discrete .progress-bar { left: 0; transition: width 0.1s linear; } .progress-container.discrete.done .progress-bar { width: 100%; } .progress-container.infinite .progress-bar { animation-name: progress; animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: steps(100); transform: translateZ(0); } @keyframes progress { 0% { transform: translateX(0) scaleX(1); } 50% { transform: translateX(2500%) scaleX(3); } to { transform: translateX(4900%) scaleX(1); } } `" - }, - { - "kind": "variable", - "name": "titlebarStyles", - "default": "css` .titlebar { background: var(--titlebar-bg); color: var(--titlebar-fg); padding: 0.6rem 0.8rem; font-size: 1.3rem; flex-wrap: wrap; } .titlebar, .titlebar__row, .titlebar__group { display: flex; flex-direction: row; align-items: center; gap: 0.5rem; } .titlebar > *, .titlebar__row > *, .titlebar__group > * { margin: 0; } .titlebar, .titlebar__row { justify-content: space-between; } .titlebar__row { flex: 0 0 100%; } .titlebar__row--wrap { display: grid; grid-auto-flow: column; justify-content: start; grid-template-columns: 1fr min-content; } .titlebar__group { flex: auto 1 1; } .titlebar__row--wrap .titlebar__group { white-space: nowrap; } .titlebar__row--wrap .titlebar__group:nth-child(odd) { min-width: 0; } .titlebar__debugging > * { display: inline-block; } .titlebar gl-feature-badge { color: var(--color-foreground); } `" + "name": "linkStyles", + "default": "css` a { border: 0; color: var(--link-foreground); font-weight: 400; outline: none; text-decoration: var(--link-decoration-default, none); } a:focus-visible { outline: 1px solid var(--color-focus-border); border-radius: 0.2rem; } a:hover { color: var(--link-foreground-active); text-decoration: underline; } `" }, { "kind": "variable", - "name": "graphHeaderControlStyles", - "default": "css` .popover::part(body) { padding: 0; font-size: var(--vscode-font-size); background-color: var(--vscode-menu-background); } .titlebar__group gl-repo-button-group, .titlebar__group gl-ref-button { font-size: 1.2rem; } .shrink { max-width: fit-content; transition: all 0.2s; } .shrink.hidden { max-width: 0; overflow: hidden; } .titlebar__group .shrink.hidden:not(:first-child) { // compensate the parent gap margin-left: -0.5rem; } .branch-menu { display: flex; gap: 0.5em; align-items: center; } .branch-menu__avatar { width: 1.4rem; aspect-ratio: 1; vertical-align: text-bottom; } .action-divider { display: inline-block; width: 0.1rem; height: 2.2rem; vertical-align: middle; background-color: var(--titlebar-fg); opacity: 0.4; margin: { // left: 0.2rem; right: 0.2rem; } } .button-group { display: flex; flex-direction: row; align-items: stretch; } .button-group:hover, .button-group:focus-within { background-color: var(--color-graph-actionbar-selectedBackground); border-radius: 3px; } .button-group > *:not(:first-child), .button-group > *:not(:first-child) .action-button { display: flex; border-top-left-radius: 0; border-bottom-left-radius: 0; } .button-group > *:not(:first-child) .action-button { padding-left: 0.5rem; padding-right: 0.5rem; height: 100%; } .button-group:hover > *:not(:last-child), .button-group:active > *:not(:last-child), .button-group:focus-within > *:not(:last-child), .button-group:hover > *:not(:last-child) .action-button, .button-group:active > *:not(:last-child) .action-button, .button-group:focus-within > *:not(:last-child) .action-button { border-top-right-radius: 0; border-bottom-right-radius: 0; } .minimap-marker-swatch { display: inline-block; width: 1rem; height: 1rem; border-radius: 2px; transform: scale(1.6); margin-left: 0.3rem; margin-right: 1rem; } .minimap-marker-swatch[data-marker='localBranches'] { background-color: var(--color-graph-minimap-marker-local-branches); } .minimap-marker-swatch[data-marker='pullRequests'] { background-color: var(--color-graph-minimap-marker-pull-requests); } .minimap-marker-swatch[data-marker='remoteBranches'] { background-color: var(--color-graph-minimap-marker-remote-branches); } .minimap-marker-swatch[data-marker='stashes'] { background-color: var(--color-graph-minimap-marker-stashes); } .minimap-marker-swatch[data-marker='tags'] { background-color: var(--color-graph-minimap-marker-tags); } gl-search-box::part(search) { --gl-search-input-background: var(--color-graph-actionbar-background); --gl-search-input-border: var(--sl-input-border-color); } sl-option::part(base) { padding: 0.2rem 0.4rem; } sl-option[aria-selected='true']::part(base), sl-option:not([aria-selected='true']):hover::part(base), sl-option:not([aria-selected='true']):focus::part(base) { background-color: var(--vscode-list-activeSelectionBackground); color: var(--vscode-list-activeSelectionForeground); } sl-option::part(checked-icon) { display: none; } sl-select::part(listbox) { padding-block: 0.2rem 0; width: max-content; } sl-select::part(combobox) { --sl-input-background-color: var(--color-graph-actionbar-background); --sl-input-color: var(--color-foreground); --sl-input-color-hover: var(--color-foreground); padding: 0 0.75rem; color: var(--color-foreground); border-radius: var(--sl-border-radius-small); } sl-select::part(display-input) { field-sizing: content; } sl-select::part(expand-icon) { margin-inline-start: var(--sl-spacing-x-small); } sl-select[open]::part(combobox) { background-color: var(--color-graph-actionbar-background); } sl-select:hover::part(combobox), sl-select:focus::part(combobox) { background-color: var(--color-graph-actionbar-selectedBackground); } `" + "name": "ruleStyles", + "default": "css` hr { border: none; border-top: 1px solid var(--color-foreground--25); } `" } ], "exports": [ { "kind": "js", - "name": "repoHeaderStyles", - "declaration": { - "name": "repoHeaderStyles", - "module": "src/webviews/apps/plus/graph/styles/header.css.ts" - } - }, - { - "kind": "js", - "name": "progressStyles", - "declaration": { - "name": "progressStyles", - "module": "src/webviews/apps/plus/graph/styles/header.css.ts" - } - }, - { - "kind": "js", - "name": "titlebarStyles", + "name": "linkStyles", "declaration": { - "name": "titlebarStyles", - "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + "name": "linkStyles", + "module": "src/webviews/apps/plus/shared/components/vscode.css.ts" } }, { "kind": "js", - "name": "graphHeaderControlStyles", + "name": "ruleStyles", "declaration": { - "name": "graphHeaderControlStyles", - "module": "src/webviews/apps/plus/graph/styles/header.css.ts" + "name": "ruleStyles", + "module": "src/webviews/apps/plus/shared/components/vscode.css.ts" } } ] @@ -26129,6 +31634,11 @@ } ] }, + { + "kind": "field", + "name": "handleLinkKeydown", + "privacy": "private" + }, { "kind": "method", "name": "focus", @@ -26564,6 +32074,404 @@ } ] }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/banner/banner.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "bannerStyles", + "default": "css` :host { /* Banner color custom properties */ --gl-banner-primary-background: var(--vscode-sideBar-background); --gl-banner-secondary-background: var(--vscode-editor-background); --gl-banner-primary-emphasis-background: var(--vscode-button-background); --gl-banner-secondary-emphasis-background: var(--vscode-button-secondaryBackground); --gl-banner-text-color: var(--vscode-foreground); --gl-banner-dim-text-color: var(--vscode-descriptionForeground); --gl-banner-transparency: 0.5; /* Layout properties */ --gl-banner-padding: 1.2rem; --gl-banner-gap: 0.8rem; --gl-banner-border-radius: 0.4rem; /* Button customization - use 8px horizontal padding, keep original vertical padding */ --gl-banner-button-padding: 0.4rem 0.8rem; display: block; margin-block-end: 1.2rem; } .banner { display: flex; flex-direction: column; padding: var(--gl-banner-padding); border-radius: var(--gl-banner-border-radius); position: relative; overflow: hidden; container-type: inline-size; } /* Solid display mode - same as card background */ .banner--solid { background-color: var(--gl-banner-primary-background); border: 1px solid color-mix(in lab, var(--gl-banner-primary-background) 100%, var(--vscode-foreground) 12%); } /* Outline display mode - emphasis color outline with secondary background */ .banner--outline { background-color: var(--gl-banner-secondary-background); border: 2px solid var(--gl-banner-primary-emphasis-background); } /* Gradient display mode - horizontal gradient from primary to secondary emphasis */ .banner--gradient { background: linear-gradient( to right, var(--gl-banner-primary-emphasis-background) 0%, var(--gl-banner-secondary-emphasis-background) 100% ); border: 1px solid color-mix( in lab, var(--gl-banner-primary-emphasis-background) 50%, var(--gl-banner-secondary-emphasis-background) 50% ); } /* Gradient transparent display mode - same gradient but with transparency */ .banner--gradient-transparent { background: linear-gradient( to right, color-mix( in lab, var(--gl-banner-primary-emphasis-background) calc(100% * (1 - var(--gl-banner-transparency))), transparent ) 0%, color-mix( in lab, var(--gl-banner-secondary-emphasis-background) calc(100% * (1 - var(--gl-banner-transparency))), transparent ) 100% ); border: 1px solid color-mix( in lab, color-mix( in lab, var(--gl-banner-primary-emphasis-background) 50%, var(--gl-banner-secondary-emphasis-background) 50% ) calc(100% * (1 - var(--gl-banner-transparency))), transparent ); } /* Gradient purple display mode - matches the auto-composer container styling */ .banner--gradient-purple { border: 1px solid var(--vscode-panel-border); border-radius: 6px; background: linear-gradient(135deg, #a100ff1a 0%, #255ed11a 100%); } .banner--gradient-purple .banner__title { font-size: 1.3rem; color: var(--vscode-foreground); font-weight: normal; } .banner--gradient-purple .banner__body { font-size: 1.2rem; color: var(--vscode-descriptionForeground); line-height: 1.4; } .banner--gradient-purple .banner__body a { color: var(--vscode-textLink-foreground); text-decoration: none; } .banner--gradient-purple .banner__body a:hover { color: var(--vscode-textLink-activeForeground); text-decoration: underline; } .banner__content { display: flex; flex-direction: column; gap: var(--gl-banner-gap); align-items: center; text-align: center; } /* Responsive layout */ .banner--responsive .banner__content { display: flex; flex-direction: column; align-items: stretch; text-align: left; gap: var(--gl-banner-gap); } .banner--responsive .banner__text { display: flex; flex-direction: column; gap: 0.4rem; } .banner--responsive .banner__title, .banner--responsive .banner__body { text-align: left; } /* < 500px: Stack vertically with full-width buttons */ .banner--responsive .banner__buttons { display: flex; flex-direction: column; gap: 0.8rem; margin-top: 0.8rem; width: 100%; } .banner--responsive .banner__button { grid-column: unset; justify-self: unset; width: 100% !important; min-width: 100% !important; max-width: 100% !important; justify-content: center; flex: 1; } /* >= 500px: Three-group horizontal layout */ @container (min-width: 500px) { .banner--responsive .banner__content { flex-direction: row; align-items: center; gap: 1.6rem; } /* Group 1: Text content (left-aligned) */ .banner--responsive .banner__text { flex: 1; min-width: 0; align-self: center; } /* Group 2: Buttons (content-sized) */ .banner--responsive .banner__buttons { display: flex; flex-direction: column; gap: 0.8rem; margin-top: 0; width: auto; flex-shrink: 0; align-self: center; } .banner--responsive .banner__button { width: auto; white-space: nowrap; } /* Group 3: Dismiss button (to the right of buttons) */ .banner--responsive .banner__dismiss { position: static !important; top: auto !important; right: auto !important; align-self: center; flex-shrink: 0; } } .banner__title { font-size: 1.2em; font-weight: bold; color: var(--gl-banner-text-color); margin: 0; text-wrap: pretty; } .banner__body { font-size: 1em; color: var(--gl-banner-text-color); margin: 0; line-height: 1.4; text-wrap: pretty; } .banner__buttons { display: grid; grid-template-columns: 1fr auto 1fr; gap: 0.8rem; margin-top: 0.8rem; align-items: center; width: 100%; } .banner:not(.banner--gradient-purple) .banner__button--primary { grid-column: 2; justify-self: center; white-space: nowrap; --button-background: color-mix(in lab, var(--gl-banner-primary-background) 10%, #fff 20%); --button-foreground: var(--gl-banner-text-color); --button-hover-background: color-mix(in lab, var(--gl-banner-primary-background) 20%, #fff 30%); --button-padding: var(--gl-banner-button-padding); } .banner--gradient-purple .banner__button--primary { grid-column: 2; justify-self: center; white-space: nowrap; --button-padding: var(--gl-banner-button-padding); } .banner__button--secondary { grid-column: 3; justify-self: end; white-space: nowrap; --button-background: transparent; --button-foreground: var(--gl-banner-dim-text-color); --button-hover-background: color-mix(in lab, var(--gl-banner-dim-text-color) 10%, transparent); } /* When only primary button exists, center it across the full width */ .banner__buttons:has(.banner__button--primary):not(:has(.banner__button--secondary)) .banner__button--primary { grid-column: 1 / -1; justify-self: center; } /* Dismiss button */ .banner__dismiss { position: absolute; top: 0.8rem; right: 0.8rem; --button-background: transparent; --button-foreground: var(--gl-banner-dim-text-color); --button-hover-background: color-mix(in lab, var(--gl-banner-dim-text-color) 15%, transparent); --button-padding: 0.4rem; z-index: 1; } /* Responsive layout dismiss button */ .banner--responsive .banner__dismiss { /* < 500px: Upper right corner (default positioning) */ position: absolute; top: 0.8rem; right: 0.8rem; } /* Theme-specific adjustments */ /* Light theme: Brighten gradient colors for better contrast with dark text */ :host-context(.vscode-light), :host-context(.vscode-high-contrast-light) { --gl-banner-primary-emphasis-background: color-mix(in lab, var(--vscode-button-background) 40%, #fff 60%); --gl-banner-secondary-emphasis-background: color-mix( in lab, var(--vscode-button-secondaryBackground) 40%, #fff 60% ); } /* Override text color for high contrast light theme specifically */ :host-context(.vscode-high-contrast-light) { --gl-banner-text-color: #000; } :host-context(.vscode-dark) .banner:not(.banner--gradient-purple) .banner__button--primary, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .banner:not(.banner--gradient-purple) .banner__button--primary { --button-background: color-mix(in lab, var(--gl-banner-primary-background) 10%, #fff 20%); --button-hover-background: color-mix(in lab, var(--gl-banner-primary-background) 20%, #fff 30%); --button-foreground: #fff; } :host-context(.vscode-light) .banner:not(.banner--gradient-purple) .banner__button--primary, :host-context(.vscode-high-contrast-light) .banner:not(.banner--gradient-purple) .banner__button--primary { --button-background: color-mix(in lab, var(--gl-banner-primary-background) 8%, #fff 25%); --button-hover-background: color-mix(in lab, var(--gl-banner-primary-background) 15%, #fff 35%); --button-foreground: #000; } /* Make banner text darker in light themes */ :host-context(.vscode-light) .banner__body, :host-context(.vscode-high-contrast-light) .banner__body { color: color-mix(in lab, var(--gl-banner-text-color) 20%, #000 80%); } /* Strong colors for banner title - pure black/white for maximum contrast */ :host-context(.vscode-light) .banner__title, :host-context(.vscode-high-contrast-light) .banner__title { color: #000 !important; } :host-context(.vscode-dark) .banner__title, :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) .banner__title { color: #fff !important; } /* Responsive adjustments */ @media (max-width: 640px) { .banner__buttons { flex-direction: column; width: 100%; } .banner__button { width: 100%; } } /* More aggressive responsive layout for narrow sidebars */ @media (max-width: 400px) { .banner__buttons { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.8rem; align-items: center; width: 100%; } .banner__button--primary, .banner__button--secondary { grid-column: unset; justify-self: unset; width: 100%; max-width: 200px; } .banner__button--primary { order: 1; } .banner__button--secondary { order: 2; } } /* Support for custom banner buttons layout */ :host([data-banner-buttons-layout='column']) .banner__buttons, .banner__buttons[data-layout='column'] { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.8rem; align-items: center; width: 100%; } :host([data-banner-buttons-layout='column']) .banner__button--primary, :host([data-banner-buttons-layout='column']) .banner__button--secondary, .banner__buttons[data-layout='column'] .banner__button--primary, .banner__buttons[data-layout='column'] .banner__button--secondary { grid-column: unset; justify-self: unset; width: 100%; max-width: 200px; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "bannerStyles", + "declaration": { + "name": "bannerStyles", + "module": "src/webviews/apps/shared/components/banner/banner.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/banner/banner.ts", + "declarations": [ + { + "kind": "variable", + "name": "bannerTagName", + "type": { + "text": "string" + }, + "default": "'gl-banner'" + }, + { + "kind": "class", + "description": "", + "name": "GlBanner", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "display", + "type": { + "text": "BannerDisplay" + }, + "default": "'solid'", + "attribute": "display", + "reflects": true + }, + { + "kind": "field", + "name": "bannerTitle", + "type": { + "text": "string | undefined" + }, + "attribute": "banner-title" + }, + { + "kind": "field", + "name": "body", + "type": { + "text": "string | undefined" + }, + "attribute": "body" + }, + { + "kind": "field", + "name": "primaryButton", + "type": { + "text": "string | undefined" + }, + "attribute": "primary-button" + }, + { + "kind": "field", + "name": "primaryButtonHref", + "type": { + "text": "string | undefined" + }, + "attribute": "primary-button-href" + }, + { + "kind": "field", + "name": "primaryButtonCommand", + "type": { + "text": "string | undefined" + }, + "attribute": "primary-button-command" + }, + { + "kind": "field", + "name": "secondaryButton", + "type": { + "text": "string | undefined" + }, + "attribute": "secondary-button" + }, + { + "kind": "field", + "name": "secondaryButtonHref", + "type": { + "text": "string | undefined" + }, + "attribute": "secondary-button-href" + }, + { + "kind": "field", + "name": "secondaryButtonCommand", + "type": { + "text": "string | undefined" + }, + "attribute": "secondary-button-command" + }, + { + "kind": "field", + "name": "dismissible", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "dismissible" + }, + { + "kind": "field", + "name": "dismissHref", + "type": { + "text": "string | undefined" + }, + "attribute": "dismiss-href" + }, + { + "kind": "field", + "name": "layout", + "type": { + "text": "'default' | 'responsive'" + }, + "default": "'default'", + "attribute": "layout" + }, + { + "kind": "field", + "name": "classNames", + "privacy": "private", + "readonly": true + }, + { + "kind": "method", + "name": "renderDefaultContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderResponsiveContent", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderTitle", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderBody", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderButtons", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderPrimaryButton", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSecondaryButton", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderDismissButton", + "privacy": "private" + }, + { + "kind": "method", + "name": "onPrimaryButtonClick", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onSecondaryButtonClick", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "onDismissClick", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "Event" + } + } + ] + } + ], + "events": [ + { + "name": "gl-banner-primary-click", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-banner-secondary-click", + "type": { + "text": "CustomEvent" + } + }, + { + "name": "gl-banner-dismiss", + "type": { + "text": "CustomEvent" + } + } + ], + "attributes": [ + { + "name": "display", + "type": { + "text": "BannerDisplay" + }, + "default": "'solid'", + "fieldName": "display" + }, + { + "name": "banner-title", + "type": { + "text": "string | undefined" + }, + "fieldName": "bannerTitle" + }, + { + "name": "body", + "type": { + "text": "string | undefined" + }, + "fieldName": "body" + }, + { + "name": "primary-button", + "type": { + "text": "string | undefined" + }, + "fieldName": "primaryButton" + }, + { + "name": "primary-button-href", + "type": { + "text": "string | undefined" + }, + "fieldName": "primaryButtonHref" + }, + { + "name": "primary-button-command", + "type": { + "text": "string | undefined" + }, + "fieldName": "primaryButtonCommand" + }, + { + "name": "secondary-button", + "type": { + "text": "string | undefined" + }, + "fieldName": "secondaryButton" + }, + { + "name": "secondary-button-href", + "type": { + "text": "string | undefined" + }, + "fieldName": "secondaryButtonHref" + }, + { + "name": "secondary-button-command", + "type": { + "text": "string | undefined" + }, + "fieldName": "secondaryButtonCommand" + }, + { + "name": "dismissible", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "dismissible" + }, + { + "name": "dismiss-href", + "type": { + "text": "string | undefined" + }, + "fieldName": "dismissHref" + }, + { + "name": "layout", + "type": { + "text": "'default' | 'responsive'" + }, + "default": "'default'", + "fieldName": "layout" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "bannerTagName", + "declaration": { + "name": "bannerTagName", + "module": "src/webviews/apps/shared/components/banner/banner.ts" + } + }, + { + "kind": "js", + "name": "GlBanner", + "declaration": { + "name": "GlBanner", + "module": "src/webviews/apps/shared/components/banner/banner.ts" + } + }, + { + "kind": "custom-element-definition", + "declaration": { + "name": "GlBanner", + "module": "src/webviews/apps/shared/components/banner/banner.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/banner/index.ts", + "declarations": [], + "exports": [ + { + "kind": "js", + "name": "*", + "declaration": { + "name": "*", + "module": "src/webviews/apps/shared/components/banner/banner" + } + }, + { + "kind": "js", + "name": "bannerStyles", + "declaration": { + "name": "bannerStyles", + "module": "./banner.css" + } + } + ] + }, { "kind": "javascript-module", "path": "src/webviews/apps/shared/components/card/card.css.ts", @@ -28518,6 +34426,94 @@ } ] }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/markdown/markdown.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlMarkdown", + "members": [ + { + "kind": "field", + "name": "markdown", + "type": { + "text": "string" + }, + "privacy": "private", + "default": "''", + "attribute": "markdown" + }, + { + "kind": "field", + "name": "density", + "type": { + "text": "'compact' | 'document'" + }, + "default": "'compact'", + "attribute": "density", + "reflects": true + }, + { + "kind": "method", + "name": "renderMarkdown", + "privacy": "private", + "parameters": [ + { + "name": "markdown", + "type": { + "text": "string" + } + } + ] + } + ], + "attributes": [ + { + "name": "markdown", + "type": { + "text": "string" + }, + "default": "''", + "fieldName": "markdown" + }, + { + "name": "density", + "type": { + "text": "'compact' | 'document'" + }, + "default": "'compact'", + "fieldName": "density" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-markdown", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlMarkdown", + "declaration": { + "name": "GlMarkdown", + "module": "src/webviews/apps/shared/components/markdown/markdown.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-markdown", + "declaration": { + "name": "GlMarkdown", + "module": "src/webviews/apps/shared/components/markdown/markdown.ts" + } + } + ] + }, { "kind": "javascript-module", "path": "src/webviews/apps/shared/components/menu/menu-divider.ts", @@ -28728,70 +34724,110 @@ }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/markdown/markdown.ts", + "path": "src/webviews/apps/shared/components/overlays/dialog.ts", "declarations": [ { "kind": "class", "description": "", - "name": "GlMarkdown", + "name": "GlDialog", "members": [ { "kind": "field", - "name": "markdown", + "name": "open", "type": { - "text": "string" + "text": "boolean" }, - "privacy": "private", - "default": "''", - "attribute": "markdown" + "default": "false", + "attribute": "open", + "reflects": true + }, + { + "kind": "field", + "name": "modal", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "modal", + "reflects": true + }, + { + "kind": "field", + "name": "closedby", + "type": { + "text": "'any' | 'closerequest' | 'none' | undefined" + }, + "attribute": "closedby" + }, + { + "kind": "field", + "name": "dialog", + "type": { + "text": "HTMLDialogElement" + } }, { "kind": "method", - "name": "renderMarkdown", - "privacy": "private", - "parameters": [ - { - "name": "markdown", - "type": { - "text": "string" - } - } - ] + "name": "toggleVisibility", + "privacy": "private" + }, + { + "kind": "method", + "name": "close" + }, + { + "kind": "method", + "name": "show" } ], "attributes": [ { - "name": "markdown", + "name": "open", "type": { - "text": "string" + "text": "boolean" }, - "default": "''", - "fieldName": "markdown" + "default": "false", + "fieldName": "open" + }, + { + "name": "modal", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "modal" + }, + { + "name": "closedby", + "type": { + "text": "'any' | 'closerequest' | 'none' | undefined" + }, + "fieldName": "closedby" } ], "superclass": { "name": "LitElement", "package": "lit" }, - "tagName": "gl-markdown", + "tagName": "gl-dialog", "customElement": true } ], "exports": [ { "kind": "js", - "name": "GlMarkdown", + "name": "GlDialog", "declaration": { - "name": "GlMarkdown", - "module": "src/webviews/apps/shared/components/markdown/markdown.ts" + "name": "GlDialog", + "module": "src/webviews/apps/shared/components/overlays/dialog.ts" } }, { "kind": "custom-element-definition", - "name": "gl-markdown", + "name": "gl-dialog", "declaration": { - "name": "GlMarkdown", - "module": "src/webviews/apps/shared/components/markdown/markdown.ts" + "name": "GlDialog", + "module": "src/webviews/apps/shared/components/overlays/dialog.ts" } } ] @@ -29648,41 +35684,410 @@ "type": { "text": "boolean" }, - "default": "false", - "fieldName": "colorized" + "default": "false", + "fieldName": "colorized" + }, + { + "name": "missingUpstream", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "missingUpstream" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-tracking-pill", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlTrackingPill", + "declaration": { + "name": "GlTrackingPill", + "module": "src/webviews/apps/shared/components/pills/tracking.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-tracking-pill", + "declaration": { + "name": "GlTrackingPill", + "module": "src/webviews/apps/shared/components/pills/tracking.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/radio/radio-group.ts", + "declarations": [ + { + "kind": "variable", + "name": "tagName", + "type": { + "text": "string" + }, + "default": "'gl-radio-group'" + }, + { + "kind": "class", + "description": "", + "name": "RadioGroup", + "members": [ + { + "kind": "field", + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "disabled", + "reflects": true + }, + { + "kind": "field", + "name": "value", + "type": { + "text": "string | undefined" + }, + "attribute": "value" + }, + { + "kind": "method", + "name": "handleValueChange", + "privacy": "private" + }, + { + "kind": "field", + "name": "radioEls", + "type": { + "text": "Radio[]" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "updateRadioElements", + "privacy": "private", + "parameters": [ + { + "name": "updateParentGroup", + "default": "false" + } + ] + }, + { + "kind": "method", + "name": "setValue", + "return": { + "type": { + "text": "void" + } + }, + "parameters": [ + { + "name": "value", + "type": { + "text": "string" + } + } + ] + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "value", + "type": { + "text": "string | undefined" + }, + "fieldName": "value" + } + ], + "superclass": { + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "tagName", + "declaration": { + "name": "tagName", + "module": "src/webviews/apps/shared/components/radio/radio-group.ts" + } + }, + { + "kind": "js", + "name": "RadioGroup", + "declaration": { + "name": "RadioGroup", + "module": "src/webviews/apps/shared/components/radio/radio-group.ts" + } + }, + { + "kind": "custom-element-definition", + "declaration": { + "name": "RadioGroup", + "module": "src/webviews/apps/shared/components/radio/radio-group.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/radio/radio.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "radioStyles", + "default": "css` :host { --checkbox-radius: 50%; --checkbox-foreground: var(--vscode-radio-inactiveForeground); --checkbox-background: var(--vscode-radio-inactiveBackground); --checkbox-border: var(--vscode-radio-inactiveBorder); --checkbox-checked-foreground: var(--vscode-radio-activeForeground); --checkbox-checked-background: var(--vscode-radio-activeBackground); --checkbox-checked-border: var(--vscode-radio-activeBorder); --checkbox-hover-background: var(--vscode-radio-inactiveHoverBackground); } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "radioStyles", + "declaration": { + "name": "radioStyles", + "module": "src/webviews/apps/shared/components/radio/radio.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/shared/components/radio/radio.ts", + "declarations": [ + { + "kind": "variable", + "name": "tagName", + "type": { + "text": "string" + }, + "default": "'gl-radio'" + }, + { + "kind": "class", + "description": "", + "name": "Radio", + "members": [ + { + "kind": "field", + "name": "shadowRootOptions", + "type": { + "text": "ShadowRootInit" + }, + "static": true, + "default": "{ ...GlElement.shadowRootOptions, delegatesFocus: true, }" + }, + { + "kind": "field", + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "disabled", + "reflects": true + }, + { + "kind": "field", + "name": "value", + "type": { + "text": "string | undefined" + }, + "attribute": "value" + }, + { + "kind": "field", + "name": "name", + "type": { + "text": "string | undefined" + }, + "attribute": "name", + "reflects": true + }, + { + "kind": "field", + "name": "checked", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "checked", + "reflects": true + }, + { + "kind": "field", + "name": "_parentGroup", + "type": { + "text": "RadioGroup | undefined" + }, + "privacy": "private", + "default": "undefined" + }, + { + "kind": "field", + "name": "parentGroup", + "type": { + "text": "RadioGroup | undefined" + } + }, + { + "kind": "method", + "name": "handleClick", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderCircle", + "privacy": "private" + }, + { + "kind": "method", + "name": "emit", + "return": { + "type": { + "text": "CustomEventType" + } + }, + "parameters": [ + { + "name": "name", + "type": { + "text": "T" + } + }, + { + "name": "detail", + "type": { + "text": "CustomEventDetailType" + } + }, + { + "name": "options", + "optional": true, + "type": { + "text": "Omit>, 'detail'>" + } + } + ], + "inheritedFrom": { + "name": "GlElement", + "module": "src/webviews/apps/shared/components/element.ts" + } + } + ], + "attributes": [ + { + "name": "disabled", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "disabled" + }, + { + "name": "value", + "type": { + "text": "string | undefined" + }, + "fieldName": "value" + }, + { + "name": "name", + "type": { + "text": "string | undefined" + }, + "fieldName": "name" }, { - "name": "missingUpstream", + "name": "checked", "type": { "text": "boolean" }, "default": "false", - "fieldName": "missingUpstream" + "fieldName": "checked" } ], "superclass": { - "name": "LitElement", - "package": "lit" - }, - "tagName": "gl-tracking-pill", - "customElement": true + "name": "GlElement", + "module": "/src/webviews/apps/shared/components/element" + } } ], "exports": [ { "kind": "js", - "name": "GlTrackingPill", + "name": "tagName", "declaration": { - "name": "GlTrackingPill", - "module": "src/webviews/apps/shared/components/pills/tracking.ts" + "name": "tagName", + "module": "src/webviews/apps/shared/components/radio/radio.ts" + } + }, + { + "kind": "js", + "name": "Radio", + "declaration": { + "name": "Radio", + "module": "src/webviews/apps/shared/components/radio/radio.ts" } }, { "kind": "custom-element-definition", - "name": "gl-tracking-pill", "declaration": { - "name": "GlTrackingPill", - "module": "src/webviews/apps/shared/components/pills/tracking.ts" + "name": "Radio", + "module": "src/webviews/apps/shared/components/radio/radio.ts" } } ] @@ -30221,447 +36626,136 @@ }, { "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/radio/radio-group.ts", + "path": "src/webviews/apps/shared/components/search/search-box.ts", "declarations": [ - { - "kind": "variable", - "name": "tagName", - "type": { - "text": "string" - }, - "default": "'gl-radio-group'" - }, { "kind": "class", "description": "", - "name": "RadioGroup", + "name": "GlSearchBox", "members": [ { "kind": "field", - "name": "disabled", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "disabled", - "reflects": true - }, - { - "kind": "field", - "name": "value", + "name": "searchInput", "type": { - "text": "string | undefined" - }, - "attribute": "value" - }, - { - "kind": "method", - "name": "handleValueChange", - "privacy": "private" + "text": "GlSearchInput" + } }, { "kind": "field", - "name": "radioEls", - "type": { - "text": "Radio[]" - }, - "privacy": "private" - }, - { - "kind": "method", - "name": "updateRadioElements", - "privacy": "private", - "parameters": [ - { - "name": "updateParentGroup", - "default": "false" - } - ] - }, - { - "kind": "method", - "name": "setValue", - "return": { - "type": { - "text": "void" - } - }, - "parameters": [ - { - "name": "value", - "type": { - "text": "string" - } - } - ] - }, - { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ - { - "name": "disabled", + "name": "aiAllowed", "type": { "text": "boolean" }, - "default": "false", - "fieldName": "disabled" + "default": "true", + "attribute": "aiAllowed" }, - { - "name": "value", - "type": { - "text": "string | undefined" - }, - "fieldName": "value" - } - ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } - } - ], - "exports": [ - { - "kind": "js", - "name": "tagName", - "declaration": { - "name": "tagName", - "module": "src/webviews/apps/shared/components/radio/radio-group.ts" - } - }, - { - "kind": "js", - "name": "RadioGroup", - "declaration": { - "name": "RadioGroup", - "module": "src/webviews/apps/shared/components/radio/radio-group.ts" - } - }, - { - "kind": "custom-element-definition", - "declaration": { - "name": "RadioGroup", - "module": "src/webviews/apps/shared/components/radio/radio-group.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/radio/radio.css.ts", - "declarations": [ - { - "kind": "variable", - "name": "radioStyles", - "default": "css` :host { --checkbox-radius: 50%; --checkbox-foreground: var(--vscode-radio-inactiveForeground); --checkbox-background: var(--vscode-radio-inactiveBackground); --checkbox-border: var(--vscode-radio-inactiveBorder); --checkbox-checked-foreground: var(--vscode-radio-activeForeground); --checkbox-checked-background: var(--vscode-radio-activeBackground); --checkbox-checked-border: var(--vscode-radio-activeBorder); --checkbox-hover-background: var(--vscode-radio-inactiveHoverBackground); } `" - } - ], - "exports": [ - { - "kind": "js", - "name": "radioStyles", - "declaration": { - "name": "radioStyles", - "module": "src/webviews/apps/shared/components/radio/radio.css.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/radio/radio.ts", - "declarations": [ - { - "kind": "variable", - "name": "tagName", - "type": { - "text": "string" - }, - "default": "'gl-radio'" - }, - { - "kind": "class", - "description": "", - "name": "Radio", - "members": [ { "kind": "field", - "name": "shadowRootOptions", + "name": "errorMessage", "type": { - "text": "ShadowRootInit" + "text": "string" }, - "static": true, - "default": "{ ...GlElement.shadowRootOptions, delegatesFocus: true, }" + "default": "''", + "attribute": "errorMessage" }, { "kind": "field", - "name": "disabled", + "name": "filter", "type": { "text": "boolean" }, "default": "false", - "attribute": "disabled", - "reflects": true - }, - { - "kind": "field", - "name": "value", - "type": { - "text": "string | undefined" - }, - "attribute": "value" + "attribute": "filter" }, { "kind": "field", - "name": "name", + "name": "matchAll", "type": { - "text": "string | undefined" + "text": "boolean" }, - "attribute": "name", - "reflects": true + "default": "false", + "attribute": "matchAll" }, { "kind": "field", - "name": "checked", + "name": "matchCase", "type": { "text": "boolean" }, "default": "false", - "attribute": "checked", - "reflects": true + "attribute": "matchCase" }, { "kind": "field", - "name": "_parentGroup", + "name": "matchRegex", "type": { - "text": "RadioGroup | undefined" + "text": "boolean" }, - "privacy": "private", - "default": "undefined" + "default": "true", + "attribute": "matchRegex" }, { "kind": "field", - "name": "parentGroup", - "type": { - "text": "RadioGroup | undefined" - } - }, - { - "kind": "method", - "name": "handleClick", - "privacy": "private" - }, - { - "kind": "method", - "name": "renderCircle", - "privacy": "private" - }, - { - "kind": "method", - "name": "emit", - "return": { - "type": { - "text": "CustomEventType" - } - }, - "parameters": [ - { - "name": "name", - "type": { - "text": "T" - } - }, - { - "name": "detail", - "type": { - "text": "CustomEventDetailType" - } - }, - { - "name": "options", - "optional": true, - "type": { - "text": "Omit>, 'detail'>" - } - } - ], - "inheritedFrom": { - "name": "GlElement", - "module": "src/webviews/apps/shared/components/element.ts" - } - } - ], - "attributes": [ - { - "name": "disabled", + "name": "matchWholeWord", "type": { "text": "boolean" }, "default": "false", - "fieldName": "disabled" - }, - { - "name": "value", - "type": { - "text": "string | undefined" - }, - "fieldName": "value" - }, - { - "name": "name", - "type": { - "text": "string | undefined" - }, - "fieldName": "name" + "attribute": "matchWholeWord" }, { - "name": "checked", + "kind": "field", + "name": "more", "type": { "text": "boolean" }, "default": "false", - "fieldName": "checked" - } - ], - "superclass": { - "name": "GlElement", - "module": "/src/webviews/apps/shared/components/element" - } - } - ], - "exports": [ - { - "kind": "js", - "name": "tagName", - "declaration": { - "name": "tagName", - "module": "src/webviews/apps/shared/components/radio/radio.ts" - } - }, - { - "kind": "js", - "name": "Radio", - "declaration": { - "name": "Radio", - "module": "src/webviews/apps/shared/components/radio/radio.ts" - } - }, - { - "kind": "custom-element-definition", - "declaration": { - "name": "Radio", - "module": "src/webviews/apps/shared/components/radio/radio.ts" - } - } - ] - }, - { - "kind": "javascript-module", - "path": "src/webviews/apps/shared/components/search/search-box.ts", - "declarations": [ - { - "kind": "class", - "description": "", - "name": "GlSearchBox", - "members": [ - { - "kind": "field", - "name": "errorMessage", - "type": { - "text": "string" - }, - "default": "''", - "attribute": "errorMessage" - }, - { - "kind": "field", - "name": "_value", - "type": { - "text": "string" - } - }, - { - "kind": "field", - "name": "value", - "attribute": "value" + "attribute": "more" }, { "kind": "field", - "name": "matchAll", + "name": "naturalLanguage", "type": { "text": "boolean" }, "default": "false", - "attribute": "matchAll" + "attribute": "naturalLanguage" }, { "kind": "field", - "name": "matchCase", + "name": "resultsHidden", "type": { "text": "boolean" }, "default": "false", - "attribute": "matchCase" + "attribute": "resultsHidden" }, { "kind": "field", - "name": "matchRegex", + "name": "resultsLabel", "type": { - "text": "boolean" + "text": "string" }, - "default": "true", - "attribute": "matchRegex" + "default": "'result'", + "attribute": "resultsLabel" }, { "kind": "field", - "name": "filter", + "name": "resultsLoaded", "type": { "text": "boolean" }, "default": "false", - "attribute": "filter" + "attribute": "resultsLoaded" }, { "kind": "field", - "name": "total", + "name": "searching", "type": { - "text": "number" + "text": "boolean" }, - "default": "0", - "attribute": "total" + "default": "false", + "attribute": "searching" }, { "kind": "field", @@ -30674,21 +36768,12 @@ }, { "kind": "field", - "name": "more", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "more" - }, - { - "kind": "field", - "name": "searching", + "name": "total", "type": { - "text": "boolean" + "text": "number" }, - "default": "false", - "attribute": "searching" + "default": "0", + "attribute": "total" }, { "kind": "field", @@ -30701,30 +36786,16 @@ }, { "kind": "field", - "name": "resultsHidden", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "resultsHidden" + "name": "value", + "attribute": "value" }, { "kind": "field", - "name": "resultsLabel", + "name": "_value", "type": { "text": "string" }, - "default": "'result'", - "attribute": "resultsLabel" - }, - { - "kind": "field", - "name": "resultsLoaded", - "type": { - "text": "boolean" - }, - "default": "false", - "attribute": "resultsLoaded" + "privacy": "private" }, { "kind": "field", @@ -30732,15 +36803,9 @@ "type": { "text": "boolean" }, + "privacy": "private", "readonly": true }, - { - "kind": "field", - "name": "searchInput", - "type": { - "text": "GlSearchInput" - } - }, { "kind": "field", "name": "_disposable", @@ -30912,6 +36977,14 @@ } ], "attributes": [ + { + "name": "aiAllowed", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "aiAllowed" + }, { "name": "errorMessage", "type": { @@ -30921,8 +36994,12 @@ "fieldName": "errorMessage" }, { - "name": "value", - "fieldName": "value" + "name": "filter", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "filter" }, { "name": "matchAll", @@ -30949,28 +37026,12 @@ "fieldName": "matchRegex" }, { - "name": "filter", + "name": "matchWholeWord", "type": { "text": "boolean" }, "default": "false", - "fieldName": "filter" - }, - { - "name": "total", - "type": { - "text": "number" - }, - "default": "0", - "fieldName": "total" - }, - { - "name": "step", - "type": { - "text": "number" - }, - "default": "0", - "fieldName": "step" + "fieldName": "matchWholeWord" }, { "name": "more", @@ -30978,23 +37039,15 @@ "text": "boolean" }, "default": "false", - "fieldName": "more" - }, - { - "name": "searching", - "type": { - "text": "boolean" - }, - "default": "false", - "fieldName": "searching" + "fieldName": "more" }, { - "name": "valid", + "name": "naturalLanguage", "type": { "text": "boolean" }, "default": "false", - "fieldName": "valid" + "fieldName": "naturalLanguage" }, { "name": "resultsHidden", @@ -31019,6 +37072,42 @@ }, "default": "false", "fieldName": "resultsLoaded" + }, + { + "name": "searching", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "searching" + }, + { + "name": "step", + "type": { + "text": "number" + }, + "default": "0", + "fieldName": "step" + }, + { + "name": "total", + "type": { + "text": "number" + }, + "default": "0", + "fieldName": "total" + }, + { + "name": "valid", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "valid" + }, + { + "name": "value", + "fieldName": "value" } ], "superclass": { @@ -31089,78 +37178,119 @@ }, { "kind": "field", - "name": "errorMessage", + "name": "aiAllowed", "type": { - "text": "string" + "text": "boolean" }, - "default": "''" + "default": "true", + "attribute": "aiAllowed" }, { "kind": "field", - "name": "helpType", + "name": "filter", "type": { - "text": "SearchOperatorsLongForm | undefined" - } + "text": "boolean" + }, + "default": "false", + "attribute": "filter" }, { "kind": "field", - "name": "label", - "privacy": "private", - "readonly": true + "name": "matchAll", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "matchAll" }, { "kind": "field", - "name": "placeholder", - "privacy": "private", - "readonly": true + "name": "matchCase", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "matchCase" }, { "kind": "field", - "name": "_value", + "name": "matchRegex", "type": { - "text": "string" - } + "text": "boolean" + }, + "default": "true", + "attribute": "matchRegex" }, { "kind": "field", - "name": "value", - "attribute": "value" + "name": "matchWholeWord", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "matchWholeWord" }, { "kind": "field", - "name": "filter", + "name": "naturalLanguage", "type": { "text": "boolean" }, "default": "false", - "attribute": "filter" + "attribute": "naturalLanguage" }, { "kind": "field", - "name": "matchAll", + "name": "searching", "type": { "text": "boolean" }, "default": "false", - "attribute": "matchAll" + "attribute": "searching" }, { "kind": "field", - "name": "matchCase", + "name": "value", + "attribute": "value" + }, + { + "kind": "field", + "name": "errorMessage", "type": { - "text": "boolean" + "text": "string" }, - "default": "false", - "attribute": "matchCase" + "privacy": "private", + "default": "''" }, { "kind": "field", - "name": "matchRegex", + "name": "helpType", "type": { - "text": "boolean" + "text": "SearchOperatorsLongForm | undefined" }, - "default": "true", - "attribute": "matchRegex" + "privacy": "private" + }, + { + "kind": "field", + "name": "processedQuery", + "type": { + "text": "string | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_value", + "type": { + "text": "string" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "label", + "privacy": "private", + "readonly": true }, { "kind": "field", @@ -31170,6 +37300,29 @@ }, "readonly": true }, + { + "kind": "field", + "name": "matchWholeWordOverride", + "type": { + "text": "boolean" + }, + "readonly": true + }, + { + "kind": "field", + "name": "placeholder", + "privacy": "private", + "readonly": true + }, + { + "kind": "field", + "name": "showNaturalLanguageHelpText", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "true" + }, { "kind": "method", "name": "focus", @@ -31299,7 +37452,33 @@ }, { "kind": "method", - "name": "handleFilter", + "name": "handleMatchWholeWord", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "handleFilterClick", + "privacy": "private", + "parameters": [ + { + "name": "_e", + "type": { + "text": "Event" + } + } + ] + }, + { + "kind": "method", + "name": "handleNaturalLanguageClick", "privacy": "private", "parameters": [ { @@ -31310,6 +37489,19 @@ } ] }, + { + "kind": "method", + "name": "updateNaturalLanguage", + "privacy": "private", + "parameters": [ + { + "name": "useNaturalLanguage", + "type": { + "text": "boolean" + } + } + ] + }, { "kind": "method", "name": "handleKeyup", @@ -31427,6 +37619,35 @@ } ] }, + { + "kind": "method", + "name": "renderHelpText", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSpecificHelpText", + "privacy": "private", + "parameters": [ + { + "name": "type", + "optional": true, + "type": { + "text": "SearchOperatorsLongForm" + } + } + ] + }, + { + "kind": "method", + "name": "renderSearchByPopover", + "privacy": "private" + }, + { + "kind": "method", + "name": "renderSearchOptions", + "privacy": "private" + }, { "kind": "method", "name": "emit", @@ -31464,8 +37685,12 @@ ], "attributes": [ { - "name": "value", - "fieldName": "value" + "name": "aiAllowed", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "aiAllowed" }, { "name": "filter", @@ -31498,6 +37723,34 @@ }, "default": "true", "fieldName": "matchRegex" + }, + { + "name": "matchWholeWord", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "matchWholeWord" + }, + { + "name": "naturalLanguage", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "naturalLanguage" + }, + { + "name": "searching", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "searching" + }, + { + "name": "value", + "fieldName": "value" } ], "superclass": { @@ -31666,12 +37919,129 @@ "attribute": "guides", "reflects": true }, + { + "kind": "field", + "name": "ariaLabel", + "type": { + "text": "string" + }, + "default": "'Tree'", + "attribute": "aria-label" + }, + { + "kind": "field", + "name": "_lastSelectedPath", + "type": { + "text": "string | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_focusedItemPath", + "type": { + "text": "string | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_focusedItemIndex", + "type": { + "text": "number" + }, + "privacy": "private", + "default": "-1" + }, + { + "kind": "field", + "name": "virtualizerRef", + "type": { + "text": "Ref" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "scrollableRef", + "type": { + "text": "Ref" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_containerHasFocus", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "_actionButtonHasFocus", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "_scrolling", + "type": { + "text": "boolean" + }, + "privacy": "private", + "default": "false" + }, + { + "kind": "field", + "name": "_typeAheadBuffer", + "type": { + "text": "string" + }, + "privacy": "private", + "default": "''" + }, + { + "kind": "field", + "name": "_typeAheadTimer", + "type": { + "text": "number | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "_typeAheadTimeout", + "type": { + "text": "number" + }, + "privacy": "private", + "readonly": true, + "default": "800" + }, + { + "kind": "field", + "name": "_nodeMap", + "privacy": "private", + "default": "new Map()" + }, + { + "kind": "field", + "name": "_pathToIndexMap", + "privacy": "private", + "default": "new Map()" + }, { "kind": "field", "name": "_model", "type": { "text": "TreeModel[] | undefined" - } + }, + "privacy": "private" }, { "kind": "field", @@ -31732,14 +38102,57 @@ }, { "kind": "method", - "name": "renderTree", + "name": "findTreeNode", "privacy": "private", + "return": { + "type": { + "text": "TreeModel | undefined" + } + }, "parameters": [ { - "name": "nodes", - "optional": true, + "name": "path", + "type": { + "text": "string" + } + } + ], + "description": "Find a tree node by path using O(1) map lookup" + }, + { + "kind": "method", + "name": "getItemIndex", + "privacy": "private", + "return": { + "type": { + "text": "number" + } + }, + "parameters": [ + { + "name": "path", + "type": { + "text": "string" + } + } + ], + "description": "Get the index of an item by path using O(1) map lookup" + }, + { + "kind": "method", + "name": "rebuildFlattenedTree", + "privacy": "private", + "description": "Rebuild the flattened tree from the hierarchical model\nThis is called when the tree structure changes (expand/collapse)" + }, + { + "kind": "method", + "name": "onBeforeTreeItemSelected", + "privacy": "private", + "parameters": [ + { + "name": "model", "type": { - "text": "TreeModelFlat[]" + "text": "TreeModelFlat" } } ] @@ -31804,34 +38217,181 @@ "type": { "text": "TreeItemAction" } + }, + { + "name": "dblClick", + "default": "false" + } + ] + }, + { + "kind": "field", + "name": "handleContainerFocus", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleContainerBlur", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleFocusIn", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleFocusOut", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleContextMenu", + "privacy": "private" + }, + { + "kind": "field", + "name": "handleKeydown", + "privacy": "private" + }, + { + "kind": "method", + "name": "getCurrentFocusedIndex", + "privacy": "private", + "return": { + "type": { + "text": "number" + } + } + }, + { + "kind": "field", + "name": "handleContainerKeydown", + "privacy": "private" + }, + { + "kind": "method", + "name": "handleItemActivation", + "privacy": "private", + "parameters": [ + { + "name": "item", + "type": { + "text": "TreeModelFlat" + } } ] }, { "kind": "method", - "name": "onTreeItemActionDblClicked", + "name": "handleBranchToggle", "privacy": "private", + "return": { + "type": { + "text": "boolean" + } + }, "parameters": [ { "name": "e", "type": { - "text": "MouseEvent" + "text": "KeyboardEvent" } }, { - "name": "model", + "name": "item", "type": { "text": "TreeModelFlat" } - }, + } + ] + }, + { + "kind": "method", + "name": "focusItemAtIndex", + "privacy": "private", + "parameters": [ { - "name": "action", + "name": "index", "type": { - "text": "TreeItemAction" + "text": "number" + } + } + ] + }, + { + "kind": "method", + "name": "scrollToItem", + "privacy": "private", + "parameters": [ + { + "name": "index", + "type": { + "text": "number" } } ] }, + { + "kind": "method", + "name": "handleTypeAhead", + "privacy": "private", + "parameters": [ + { + "name": "char", + "type": { + "text": "string" + }, + "description": "The character to add to the search buffer" + } + ], + "description": "Handles type-ahead search functionality" + }, + { + "kind": "method", + "name": "buildPathToIndexMap", + "privacy": "private" + }, + { + "kind": "method", + "name": "findNextMatchingItem", + "privacy": "private", + "return": { + "type": { + "text": "" + } + }, + "parameters": [ + { + "name": "searchText", + "type": { + "text": "string" + }, + "description": "The text to search for" + } + ], + "description": "Finds the next tree item that matches the search buffer" + }, + { + "kind": "method", + "name": "isPrintableCharacter", + "privacy": "private", + "return": { + "type": { + "text": "" + } + }, + "parameters": [ + { + "name": "char", + "type": { + "text": "string" + }, + "description": "The character to check" + } + ], + "description": "Checks if a character is printable (for type-ahead search)" + }, { "kind": "method", "name": "emit", @@ -31874,6 +38434,14 @@ "text": "'none' | 'onHover' | 'always' | undefined" }, "fieldName": "guides" + }, + { + "name": "aria-label", + "type": { + "text": "string" + }, + "default": "'Tree'", + "fieldName": "ariaLabel" } ], "superclass": { @@ -32018,6 +38586,23 @@ "default": "true", "attribute": "showIcon" }, + { + "kind": "field", + "name": "tabIndex", + "type": { + "text": "number" + }, + "default": "-1", + "attribute": "tabIndex" + }, + { + "kind": "field", + "name": "vscodeContext", + "type": { + "text": "string | undefined" + }, + "attribute": "vscode-context" + }, { "kind": "field", "name": "selected", @@ -32032,7 +38617,19 @@ "type": { "text": "boolean" }, - "default": "false" + "default": "false", + "attribute": "focused", + "reflects": true + }, + { + "kind": "field", + "name": "focusedInactive", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "focused-inactive", + "reflects": true }, { "kind": "field", @@ -32163,6 +38760,19 @@ } ] }, + { + "kind": "method", + "name": "onButtonContextMenu", + "privacy": "private", + "parameters": [ + { + "name": "e", + "type": { + "text": "MouseEvent" + } + } + ] + }, { "kind": "method", "name": "onCheckboxClick", @@ -32318,6 +38928,37 @@ }, "default": "true", "fieldName": "showIcon" + }, + { + "name": "tabIndex", + "type": { + "text": "number" + }, + "default": "-1", + "fieldName": "tabIndex" + }, + { + "name": "vscode-context", + "type": { + "text": "string | undefined" + }, + "fieldName": "vscodeContext" + }, + { + "name": "focused", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "focused" + }, + { + "name": "focused-inactive", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "focusedInactive" } ], "superclass": { @@ -32357,7 +38998,7 @@ "type": { "text": "array" }, - "default": "[elementBase, css``]" + "default": "[ elementBase, css` :host { display: block; height: 100%; } `, ]" }, { "kind": "variable", @@ -32365,7 +39006,7 @@ "type": { "text": "array" }, - "default": "[ elementBase, css` :host { --tree-connector-spacing: 0.6rem; --tree-connector-size: var(--gitlens-tree-indent, 1.6rem); box-sizing: border-box; padding-left: var(--gitlens-gutter-width); /* padding-right: var(--gitlens-scrollbar-gutter-width); */ padding-right: 0.5rem; padding-top: 0.1rem; padding-bottom: 0.1rem; line-height: 2.2rem; height: 2.2rem; display: flex; flex-direction: row; align-items: center; justify-content: space-between; font-size: var(--vscode-font-size); color: var(--gitlens-tree-foreground, var(--vscode-foreground)); content-visibility: auto; contain-intrinsic-size: auto 2.2rem; cursor: pointer; } :host(:hover), :host(:focus-within) { content-visibility: visible; } :host([aria-hidden='true']) { display: none; } :host(:hover) { color: var(--vscode-list-hoverForeground); background-color: var(--vscode-list-hoverBackground); } :host([aria-selected='true']) { color: var(--vscode-list-inactiveSelectionForeground); background-color: var(--vscode-list-inactiveSelectionBackground); } /* TODO: these should be :has(.input:focus) instead of :focus-within */ :host(:focus-within) { outline: 1px solid var(--vscode-list-focusOutline); outline-offset: -0.1rem; } :host([aria-selected='true']:focus-within) { color: var(--vscode-list-activeSelectionForeground); background-color: var(--vscode-list-activeSelectionBackground); } .item { appearance: none; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; gap: 0.6rem; width: 100%; padding: 0; font-family: inherit; font-size: inherit; text-decoration: none; color: inherit; background: none; border: none; outline: none; cursor: pointer; min-width: 0; } /* FIXME: remove, this is for debugging .item:focus { outline: 1px solid var(--vscode-list-focusOutline); outline-offset: -0.1rem; } */ .icon { display: inline-block; width: 1.6rem; text-align: center; height: 2.2rem; line-height: 2.2rem; pointer-events: none; vertical-align: text-bottom; } slot[name='icon']::slotted(*) { width: 1.6rem; aspect-ratio: 1; vertical-align: text-bottom; } .node { display: inline-block; width: var(--tree-connector-size); text-align: center; flex: none; height: 2.2rem; line-height: 2.2rem; pointer-events: none; vertical-align: text-bottom; } .node:last-of-type { margin-right: 0.3rem; } .node--connector { position: relative; } .node--connector::before { content: ''; position: absolute; height: 2.2rem; border-left: 1px solid transparent; top: 50%; transform: translate(-1px, -50%); left: 0.8rem; width: 0.1rem; transition: border-color 0.1s linear; opacity: 0.4; } :host-context([guides='always']) .node--connector::before, :host-context([guides='onHover']:focus-within) .node--connector::before, :host-context([guides='onHover']:hover) .node--connector::before { border-color: var(--vscode-tree-indentGuidesStroke); } .branch { display: inline-block; margin-right: 0.6rem; height: 2.2rem; line-height: 2.2rem; vertical-align: text-bottom; } .text { line-height: 1.6rem; overflow: hidden; white-space: nowrap; text-align: left; text-overflow: ellipsis; flex: 1; } .main { display: inline; } .description { display: inline; opacity: 0.7; font-size: 0.9em; margin-left: 0.3rem; pointer-events: none; } .actions { flex: none; user-select: none; color: var(--vscode-icon-foreground); } :host(:focus-within) .actions { color: var(--vscode-list-activeSelectionIconForeground); } :host(:not(:hover):not(:focus-within)) .actions { display: none; } .checkbox { position: relative; display: inline-flex; width: 1.6rem; aspect-ratio: 1 / 1; text-align: center; color: var(--vscode-checkbox-foreground); background: var(--vscode-checkbox-background); border: 1px solid var(--vscode-checkbox-border); border-radius: 0.3rem; // overflow: hidden; margin-right: 0.6rem; } .checkbox:has(:checked) { color: var(--vscode-inputOption-activeForeground); border-color: var(--vscode-inputOption-activeBorder); background-color: var(--vscode-inputOption-activeBackground); } .checkbox:has(:disabled) { opacity: 0.4; } .checkbox__input { position: absolute; top: 0; left: 0; appearance: none; width: 1.4rem; aspect-ratio: 1 / 1; margin: 0; cursor: pointer; border-radius: 0.3rem; } .checkbox__input:disabled { cursor: default; } .checkbox__check { width: 1.6rem; aspect-ratio: 1 / 1; opacity: 0; transition: opacity 0.1s linear; color: var(--vscode-checkbox-foreground); pointer-events: none; } .checkbox__input:checked + .checkbox__check { opacity: 1; } slot[name='decorations'] { display: inline-block; margin-left: 0.4rem; } `, ]" + "default": "[ elementBase, css` :host { --tree-connector-spacing: 0.6rem; --tree-connector-size: var(--gitlens-tree-indent, 1.6rem); box-sizing: border-box; padding-left: var(--gitlens-gutter-width); padding-right: 0.5rem; padding-top: 0.1rem; padding-bottom: 0.1rem; line-height: 2.2rem; height: 2.2rem; display: flex; flex-direction: row; align-items: center; justify-content: space-between; font-size: var(--vscode-font-size); color: var(--gitlens-tree-foreground, var(--vscode-foreground)); cursor: pointer; /* Reduced containment to allow tooltips to escape */ contain: layout; } :host([aria-hidden='true']) { display: none; } :host(:hover) { color: var(--vscode-list-hoverForeground); background-color: var(--vscode-list-hoverBackground); } :host([aria-selected='true']) { color: var(--vscode-list-inactiveSelectionForeground); background-color: var(--vscode-list-inactiveSelectionBackground); } /* Focused state - when the item is the active descendant in the tree */ :host([focused]) { outline: 1px solid var(--vscode-list-focusOutline); outline-offset: -0.1rem; } :host([aria-selected='true'][focused]) { color: var(--vscode-list-activeSelectionForeground); background-color: var(--vscode-list-activeSelectionBackground); } /* Inactive focus state - when the item would be focused but container doesn't have focus */ /* In VS Code, inactive focus shows the selection background without the outline */ :host([focused-inactive]) { color: var(--vscode-list-inactiveSelectionForeground); background-color: var(--vscode-list-inactiveSelectionBackground); } /* TODO: these should be :has(.input:focus) instead of :focus-within */ :host(:focus-within) { outline: 1px solid var(--vscode-list-focusOutline); outline-offset: -0.1rem; } :host([aria-selected='true']:focus-within) { color: var(--vscode-list-activeSelectionForeground); background-color: var(--vscode-list-activeSelectionBackground); } .item { appearance: none; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; gap: 0.6rem; width: 100%; padding: 0; font-family: inherit; font-size: inherit; text-decoration: none; color: inherit; background: none; border: none; outline: none; cursor: pointer; min-width: 0; } .icon { display: inline-block; width: 1.6rem; text-align: center; height: 2.2rem; line-height: 2.2rem; pointer-events: none; vertical-align: text-bottom; } slot[name='icon']::slotted(*) { width: 1.6rem; aspect-ratio: 1; vertical-align: text-bottom; } .node { display: inline-block; width: var(--tree-connector-size); text-align: center; flex: none; height: 2.2rem; line-height: 2.2rem; pointer-events: none; vertical-align: text-bottom; } .node:last-of-type { margin-right: 0.3rem; } .node--connector { position: relative; } .node--connector::before { content: ''; position: absolute; height: 2.2rem; border-left: 1px solid transparent; top: 50%; transform: translate(-1px, -50%); left: 0.8rem; width: 0.1rem; transition: border-color 0.1s linear; opacity: 0.4; } @media (prefers-reduced-motion: reduce) { .node--connector::before { transition: none; } } :host-context([guides='always']) .node--connector::before, :host-context([guides='onHover']:focus-within) .node--connector::before, :host-context([guides='onHover'][focused]) .node--connector::before, :host-context([guides='onHover'][focused-inactive]) .node--connector::before, :host-context([guides='onHover']:hover) .node--connector::before { border-color: var(--vscode-tree-indentGuidesStroke); } .branch { display: inline-block; margin-right: 0.6rem; height: 2.2rem; line-height: 2.2rem; vertical-align: text-bottom; } .text { line-height: 1.8rem; overflow: hidden; white-space: nowrap; text-align: left; text-overflow: ellipsis; flex: 1; } .main { display: inline; } .description { display: inline; opacity: 0.7; font-size: 0.9em; margin-left: 0.3rem; pointer-events: none; } .actions { flex: none; user-select: none; color: var(--vscode-icon-foreground); } :host(:focus-within) .actions, :host([focused]) .actions { color: var(--vscode-list-activeSelectionIconForeground); } :host([focused-inactive]) .actions { color: var(--vscode-list-inactiveSelectionIconForeground, var(--vscode-icon-foreground)); } :host(:not(:hover):not(:focus-within):not([focused]):not([focused-inactive])) .actions { display: none; } .checkbox { position: relative; display: inline-flex; width: 1.6rem; aspect-ratio: 1 / 1; text-align: center; color: var(--vscode-checkbox-foreground); background: var(--vscode-checkbox-background); border: 1px solid var(--vscode-checkbox-border); border-radius: 0.3rem; margin-right: 0.6rem; } .checkbox:has(:checked) { color: var(--vscode-inputOption-activeForeground); border-color: var(--vscode-inputOption-activeBorder); background-color: var(--vscode-inputOption-activeBackground); } .checkbox:has(:disabled) { opacity: 0.4; } .checkbox__input { position: absolute; top: 0; left: 0; appearance: none; width: 1.4rem; aspect-ratio: 1 / 1; margin: 0; cursor: pointer; border-radius: 0.3rem; } .checkbox__input:disabled { cursor: default; } .checkbox__check { width: 1.6rem; aspect-ratio: 1 / 1; opacity: 0; transition: opacity 0.1s linear; color: var(--vscode-checkbox-foreground); pointer-events: none; } .checkbox__input:checked + .checkbox__check { opacity: 1; } slot[name='decorations'] { display: inline-block; margin-left: 0.4rem; } /* High Contrast Mode Support */ @media (forced-colors: active) { :host { forced-color-adjust: none; } :host([focused]) { outline: 2px solid CanvasText; outline-offset: -2px; } :host([aria-selected='true']) { background-color: Highlight; color: HighlightText; } :host([aria-selected='true'][focused]) { outline: 2px solid CanvasText; outline-offset: -2px; } .checkbox { border: 1px solid CanvasText; } .checkbox:has(:checked) { background-color: Highlight; border-color: CanvasText; } .node--connector::before { border-color: CanvasText; opacity: 1; } } `, ]" } ], "exports": [ @@ -32510,6 +39151,409 @@ } ] }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/diff/diff-file.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlDiffFile", + "members": [ + { + "kind": "field", + "name": "filename", + "type": { + "text": "string | undefined" + }, + "attribute": "filename" + }, + { + "kind": "field", + "name": "hunks", + "type": { + "text": "ComposerHunk[] | undefined" + }, + "attribute": "hunks" + }, + { + "kind": "field", + "name": "sideBySide", + "type": { + "text": "boolean" + }, + "default": "false", + "attribute": "side-by-side" + }, + { + "kind": "field", + "name": "defaultExpanded", + "type": { + "text": "boolean" + }, + "default": "true", + "attribute": "default-expanded" + }, + { + "kind": "field", + "name": "targetElement", + "type": { + "text": "HTMLDivElement" + } + }, + { + "kind": "field", + "name": "diffText", + "type": { + "text": "string | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "parsedDiff", + "type": { + "text": "DiffFile[] | undefined" + }, + "privacy": "private" + }, + { + "kind": "field", + "name": "diffFile", + "type": { + "text": "DiffFile | undefined" + }, + "readonly": true + }, + { + "kind": "field", + "name": "diff2htmlUi", + "type": { + "text": "Diff2HtmlUI | undefined" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "renderDiff", + "privacy": "private" + }, + { + "kind": "method", + "name": "processDiff", + "privacy": "private" + } + ], + "attributes": [ + { + "name": "filename", + "type": { + "text": "string | undefined" + }, + "fieldName": "filename" + }, + { + "name": "hunks", + "type": { + "text": "ComposerHunk[] | undefined" + }, + "fieldName": "hunks" + }, + { + "name": "side-by-side", + "type": { + "text": "boolean" + }, + "default": "false", + "fieldName": "sideBySide" + }, + { + "name": "default-expanded", + "type": { + "text": "boolean" + }, + "default": "true", + "fieldName": "defaultExpanded" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-diff-file", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlDiffFile", + "declaration": { + "name": "GlDiffFile", + "module": "src/webviews/apps/plus/composer/components/diff/diff-file.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-diff-file", + "declaration": { + "name": "GlDiffFile", + "module": "src/webviews/apps/plus/composer/components/diff/diff-file.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/diff/diff-templates.compiled.ts", + "declarations": [ + { + "kind": "variable", + "name": "compiledComposerTemplates", + "type": { + "text": "CompiledTemplates" + }, + "default": "{ \"generic-block-header\": new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||\"\");t.b(\"\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");if(t.s(t.f(\"blockHeader\",c,p,1),c,p,0,156,173,\"{{ }}\")){t.rs(c,p,function(c,p,t){t.b(t.t(t.f(\"blockHeader\",c,p,0)));});c.pop();}if(!t.s(t.f(\"blockHeader\",c,p,1),c,p,1,0,0,\"\")){t.b(\" \");};t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"\");return t.fl(); },partials: {}, subs: { }}), \"line-by-line-file-diff\": new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||\"\");t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(t.t(t.f(\"filePath\",c,p,0)));t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(t.t(t.f(\"diffs\",c,p,0)));t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");return t.fl(); },partials: {}, subs: { }}), \"side-by-side-file-diff\": new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||\"\");t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(t.t(t.f(\"filePath\",c,p,0)));t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(t.t(t.d(\"diffs.left\",c,p,0)));t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\" \");t.b(t.t(t.d(\"diffs.right\",c,p,0)));t.b(\"\\n\" + i);t.b(\" \");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");t.b(\"\\n\" + i);t.b(\"
\");return t.fl(); },partials: {}, subs: { }}), \"generic-file-path\": new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||\"\");t.b(\"\");t.b(\"\\n\" + i);t.b(\" \");t.b(t.v(t.f(\"fileDiffName\",c,p,0)));t.b(\"\");t.b(\"\\n\" + i);t.b(t.rp(\"\");t.b(\"\\n\" + i);t.b(\"\");return t.fl(); },partials: {\"
{{#blockHeader}}{{{blockHeader}}}{{/blockHeader}}{{^blockHeader}} {{/blockHeader}}
`" + }, + { + "kind": "variable", + "name": "lineByLineFileTemplate", + "default": "`
{{{filePath}}}
{{{diffs}}}
`" + }, + { + "kind": "variable", + "name": "sideBySideFileTemplate", + "default": "`
{{{filePath}}}
{{{diffs.left}}}
{{{diffs.right}}}
`" + }, + { + "kind": "variable", + "name": "genericFilePathTemplate", + "default": "` {{fileDiffName}} {{>fileTag}} `" + } + ], + "exports": [ + { + "kind": "js", + "name": "blockHeaderTemplate", + "declaration": { + "name": "blockHeaderTemplate", + "module": "src/webviews/apps/plus/composer/components/diff/diff-templates.ts" + } + }, + { + "kind": "js", + "name": "lineByLineFileTemplate", + "declaration": { + "name": "lineByLineFileTemplate", + "module": "src/webviews/apps/plus/composer/components/diff/diff-templates.ts" + } + }, + { + "kind": "js", + "name": "sideBySideFileTemplate", + "declaration": { + "name": "sideBySideFileTemplate", + "module": "src/webviews/apps/plus/composer/components/diff/diff-templates.ts" + } + }, + { + "kind": "js", + "name": "genericFilePathTemplate", + "declaration": { + "name": "genericFilePathTemplate", + "module": "src/webviews/apps/plus/composer/components/diff/diff-templates.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/diff/diff.css.ts", + "declarations": [ + { + "kind": "variable", + "name": "hljsStyles", + "default": "css` .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hljs-comment, .hljs-quote { color: #998; font-style: italic; } .hljs-keyword, .hljs-selector-tag, .hljs-subst { color: #333; font-weight: 700; } .hljs-literal, .hljs-number, .hljs-tag .hljs-attr, .hljs-template-variable, .hljs-variable { color: teal; } .hljs-doctag, .hljs-string { color: #d14; } .hljs-section, .hljs-selector-id, .hljs-title { color: #900; font-weight: 700; } .hljs-subst { font-weight: 400; } .hljs-class .hljs-title, .hljs-type { color: #458; font-weight: 700; } .hljs-attribute, .hljs-name, .hljs-tag { color: navy; font-weight: 400; } .hljs-link, .hljs-regexp { color: #009926; } .hljs-bullet, .hljs-symbol { color: #990073; } .hljs-built_in, .hljs-builtin-name { color: #0086b3; } .hljs-meta { color: #999; font-weight: 700; } .hljs-deletion { background: #fdd; } .hljs-addition { background: #dfd; } .hljs-emphasis { font-style: italic; } .hljs-strong { font-weight: 700; } `" + }, + { + "kind": "variable", + "name": "diff2htmlStyles", + "default": "css` :host { --d2h-intrinsic-base-height: 3.5rem; --d2h-intrinsic-line-count: 50; --d2h-intrinsic-line-height: 1.8rem; --d2h-intrinsic-height: calc( var(--d2h-intrinsic-base-height) + (var(--d2h-intrinsic-line-height) * var(--d2h-intrinsic-line-count)) ); display: block; position: relative; } .d2h-file-wrapper { content-visibility: auto; contain-intrinsic-size: auto var(--d2h-intrinsic-base-height); } .d2h-file-wrapper[open] { contain-intrinsic-height: var(--d2h-intrinsic-height); } .d2h-wrapper { color: var(--d2h-color); text-align: left; } .d2h-file-header { background-color: var(--d2h-file-header-bg-color); border-bottom: 1px solid var(--d2h-file-header-border-color); display: flex; font-family: var(--vscode-font-family); height: 35px; padding: 4px 5px; } .d2h-file-header.d2h-sticky-header { position: sticky; top: 0; z-index: 1; } .d2h-file-stats { display: flex; font-size: 14px; margin-left: auto; } .d2h-lines-added { border: 1px solid var(--d2h-ins-border-color); border-radius: 5px 0 0 5px; color: var(--d2h-ins-label-color); padding: 2px; text-align: right; vertical-align: middle; } .d2h-lines-deleted { border: 1px solid var(--d2h-del-border-color); border-radius: 0 5px 5px 0; color: var(--d2h-del-label-color); margin-left: 1px; padding: 2px; text-align: left; vertical-align: middle; } .d2h-file-name-wrapper { display: flex; -webkit-box-align: center; -ms-flex-align: center; align-items: center; font-size: 1.4rem; width: 100%; } .d2h-file-name { overflow-x: hidden; text-overflow: ellipsis; white-space: nowrap; } .d2h-file-wrapper { border: 1px solid var(--d2h-border-color); border-radius: 3px; margin-bottom: 1em; } .d2h-file-collapse { -webkit-box-pack: end; -ms-flex-pack: end; cursor: pointer; display: none; font-size: 12px; justify-content: flex-end; -webkit-box-align: center; -ms-flex-align: center; align-items: center; border: 1px solid var(--d2h-border-color); border-radius: 3px; padding: 4px 8px; } .d2h-file-collapse.d2h-selected { background-color: var(--d2h-selected-color); } .d2h-file-collapse-input { margin: 0 4px 0 0; } .d2h-diff-table { border-collapse: collapse; font-family: var(--vscode-editor-font-family); font-size: var(--editor-font-size); width: 100%; } .d2h-files-diff { display: flex; width: 100%; } .d2h-file-diff { overflow-y: hidden; } .d2h-file-diff.d2h-d-none, .d2h-files-diff.d2h-d-none { display: none; } .d2h-file-side-diff { display: inline-block; overflow-x: scroll; overflow-y: hidden; width: 50%; } .d2h-code-line { padding: 0 8em; /* width: calc(100% - 16em); */ width: 100%; } .d2h-code-line, .d2h-code-side-line { display: inline-block; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; white-space: nowrap; } .d2h-code-side-line { padding: 0 4.5em; width: calc(100% - 9em); } .d2h-code-line-ctn { background: none; display: inline-block; padding: 0; word-wrap: normal; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; vertical-align: middle; white-space: pre; width: 100%; } .d2h-code-line del, .d2h-code-side-line del { background-color: var(--d2h-del-highlight-bg-color); } .d2h-code-line del, .d2h-code-line ins, .d2h-code-side-line del, .d2h-code-side-line ins { border-radius: 0.2em; display: inline-block; margin-top: -1px; -webkit-text-decoration: none; text-decoration: none; } .d2h-code-line ins, .d2h-code-side-line ins { background-color: var(--d2h-ins-highlight-bg-color); text-align: left; } .d2h-code-line-prefix { background: none; display: inline; padding: 0; word-wrap: normal; white-space: pre; } .line-num1 { float: left; } .line-num1, .line-num2 { -webkit-box-sizing: border-box; box-sizing: border-box; overflow: hidden; padding: 0 0.5em; text-overflow: ellipsis; width: 3.5em; } .line-num2 { float: right; } .d2h-code-linenumber { background-color: var(--d2h-bg-color); border-style: solid; border-color: transparent var(--d2h-line-border-color); border-width: 1px; -webkit-box-sizing: border-box; box-sizing: border-box; color: var(--d2h-dim-color); cursor: pointer; display: inline-block; position: absolute; text-align: right; width: 7.5em; } .d2h-code-linenumber:after { content: '\\\\200b'; } .d2h-code-linenumber.d2h-ins { border-color: transparent var(--d2h-ins-border-color); } .d2h-code-linenumber.d2h-del { border-color: transparent var(--d2h-del-border-color); } .d2h-code-side-linenumber { background-color: var(--d2h-bg-color); border: solid var(--d2h-line-border-color); border-width: 0 1px; -webkit-box-sizing: border-box; box-sizing: border-box; color: var(--d2h-dim-color); cursor: pointer; display: inline-block; overflow: hidden; padding: 0 0.5em; position: absolute; text-align: right; text-overflow: ellipsis; width: 4em; } .d2h-code-side-linenumber:after { content: '\\\\200b'; } .d2h-code-side-emptyplaceholder, .d2h-emptyplaceholder { background-color: var(--d2h-empty-placeholder-bg-color); border-color: var(--d2h-empty-placeholder-border-color); } .d2h-code-line-prefix, .d2h-code-linenumber, .d2h-code-side-linenumber, .d2h-emptyplaceholder { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .d2h-code-linenumber, .d2h-code-side-linenumber { direction: rtl; } .d2h-del { background-color: var(--d2h-del-bg-color); border-color: var(--d2h-del-border-color); } .d2h-ins { background-color: var(--d2h-ins-bg-color); border-color: var(--d2h-ins-border-color); } .d2h-info { background-color: var(--d2h-info-bg-color); border-color: var(--d2h-info-border-color); color: var(--d2h-dim-color); } .d2h-file-diff .d2h-del.d2h-change { background-color: var(--d2h-change-del-color); } .d2h-file-diff .d2h-ins.d2h-change { background-color: var(--d2h-change-ins-color); } .d2h-file-list-wrapper { margin-bottom: 10px; } .d2h-file-list-wrapper a { -webkit-text-decoration: none; text-decoration: none; } .d2h-file-list-wrapper a, .d2h-file-list-wrapper a:visited { color: var(--d2h-moved-label-color); } .d2h-file-list-header { text-align: left; } .d2h-file-list-title { font-weight: 700; } .d2h-file-list-line { display: flex; text-align: left; } .d2h-file-list { display: block; list-style: none; margin: 0; padding: 0; } .d2h-file-list > li { border-bottom: 1px solid var(--d2h-border-color); margin: 0; padding: 5px 10px; } .d2h-file-list > li:last-child { border-bottom: none; } .d2h-file-switch { cursor: pointer; display: none; font-size: 10px; } .d2h-icon { margin-right: 10px; vertical-align: middle; fill: currentColor; } .d2h-deleted { color: var(--d2h-del-label-color); } .d2h-added { color: var(--d2h-ins-label-color); } .d2h-changed { color: var(--d2h-change-label-color); } .d2h-moved { color: var(--d2h-moved-label-color); } .d2h-tag { background-color: var(--d2h-bg-color); display: flex; font-size: 10px; margin-left: 6px; padding: 0px 3px; border-radius: 2px; } .d2h-deleted-tag { border: 1px solid var(--d2h-del-label-color); } .d2h-added-tag { border: 1px solid var(--d2h-ins-label-color); } .d2h-changed-tag { border: 1px solid var(--d2h-change-label-color); } .d2h-moved-tag { border: 1px solid var(--d2h-moved-label-color); } :host-context(.vscode-high-contrast) .d2h-ins .d2h-code-line { border: 1px dashed var(--d2h-ins-border-color); line-height: calc(var(--d2h-intrinsic-line-height) - 0.2rem); } :host-context(.vscode-high-contrast) .d2h-del .d2h-code-line { border: 1px dashed var(--d2h-del-border-color); line-height: calc(var(--d2h-intrinsic-line-height) - 0.2rem); } `" + }, + { + "kind": "variable", + "name": "diffStyles", + "default": "css` td { padding-block: 0; line-height: var(--d2h-intrinsic-line-height); } .d2h-file-wrapper { margin-block-end: 0; } tr:has(.d2h-code-linenumber) { position: relative; } .d2h-file-header { align-items: center; gap: 0.4rem; cursor: pointer; } .d2h-file-wrapper:not([open]) .d2h-file-header, .d2h-file-header:has(.d2h-file-collapse.d2h-selected) { border-bottom-color: transparent; } .d2h-code-linenumber { background-color: color-mix(in srgb, var(--d2h-bg-color) 100%, transparent 12%) !important; } .d2h-file-wrapper:not([open]) .file-icon--open, .d2h-file-wrapper[open] .file-icon--closed { display: none; } `" + } + ], + "exports": [ + { + "kind": "js", + "name": "hljsStyles", + "declaration": { + "name": "hljsStyles", + "module": "src/webviews/apps/plus/composer/components/diff/diff.css.ts" + } + }, + { + "kind": "js", + "name": "diff2htmlStyles", + "declaration": { + "name": "diff2htmlStyles", + "module": "src/webviews/apps/plus/composer/components/diff/diff.css.ts" + } + }, + { + "kind": "js", + "name": "diffStyles", + "declaration": { + "name": "diffStyles", + "module": "src/webviews/apps/plus/composer/components/diff/diff.css.ts" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "src/webviews/apps/plus/composer/components/diff/diff.ts", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "GlDiffHunk", + "members": [ + { + "kind": "field", + "name": "diffHeader", + "type": { + "text": "string" + }, + "default": "''", + "attribute": "diff-header" + }, + { + "kind": "field", + "name": "hunkHeader", + "type": { + "text": "string" + }, + "default": "''", + "attribute": "hunk-header" + }, + { + "kind": "field", + "name": "hunkContent", + "type": { + "text": "string" + }, + "default": "''", + "attribute": "hunk-content" + }, + { + "kind": "field", + "name": "targetElement", + "type": { + "text": "HTMLDivElement" + } + }, + { + "kind": "field", + "name": "isDarkMode", + "readonly": true + }, + { + "kind": "field", + "name": "rawTemplates", + "readonly": true + }, + { + "kind": "field", + "name": "diff2htmlUi", + "type": { + "text": "Diff2HtmlUI | undefined" + }, + "privacy": "private" + }, + { + "kind": "method", + "name": "renderDiff", + "privacy": "private" + } + ], + "attributes": [ + { + "name": "diff-header", + "type": { + "text": "string" + }, + "default": "''", + "fieldName": "diffHeader" + }, + { + "name": "hunk-header", + "type": { + "text": "string" + }, + "default": "''", + "fieldName": "hunkHeader" + }, + { + "name": "hunk-content", + "type": { + "text": "string" + }, + "default": "''", + "fieldName": "hunkContent" + } + ], + "superclass": { + "name": "LitElement", + "package": "lit" + }, + "tagName": "gl-diff-hunk", + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "GlDiffHunk", + "declaration": { + "name": "GlDiffHunk", + "module": "src/webviews/apps/plus/composer/components/diff/diff.ts" + } + }, + { + "kind": "custom-element-definition", + "name": "gl-diff-hunk", + "declaration": { + "name": "GlDiffHunk", + "module": "src/webviews/apps/plus/composer/components/diff/diff.ts" + } + } + ] + }, { "kind": "javascript-module", "path": "src/webviews/apps/shared/components/styles/lit/a11y.css.ts", @@ -32592,6 +39636,11 @@ "name": "elementBase", "default": "css` :host { box-sizing: border-box; } :host *, :host *::before, :host *::after { box-sizing: inherit; } [hidden] { display: none !important; } `" }, + { + "kind": "variable", + "name": "boxSizingBase", + "default": "css` * { box-sizing: border-box; } `" + }, { "kind": "variable", "name": "linkBase", @@ -32617,6 +39666,14 @@ "module": "src/webviews/apps/shared/components/styles/lit/base.css.ts" } }, + { + "kind": "js", + "name": "boxSizingBase", + "declaration": { + "name": "boxSizingBase", + "module": "src/webviews/apps/shared/components/styles/lit/base.css.ts" + } + }, { "kind": "js", "name": "linkBase", From 58a0a85271125aa46d3bf41147f6bf952f38ca62 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 27 Oct 2025 02:00:34 -0400 Subject: [PATCH 78/83] Moves composer utils to common folder structure Removes custom config for composer utils --- eslint.config.mjs | 2 -- src/webviews/apps/plus/composer/components/app.ts | 2 +- .../apps/plus/composer/components/commits-panel.ts | 2 +- .../apps/plus/composer/components/details-panel.ts | 2 +- src/webviews/apps/tsconfig.json | 2 -- src/webviews/plus/composer/composerWebview.ts | 4 ++-- .../composer/{utils.ts => utils/composer.utils.ts} | 12 ++++++------ 7 files changed, 11 insertions(+), 15 deletions(-) rename src/webviews/plus/composer/{utils.ts => utils/composer.utils.ts} (97%) diff --git a/eslint.config.mjs b/eslint.config.mjs index ab189f29a1752..eb5eb15ca0f51 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -31,7 +31,6 @@ const filePatterns = { webviewsShared: [ // Keep in sync with `src/webviews/apps/tsconfig.json` 'src/webviews/ipc.ts', - 'src/webviews/plus/composer/utils.ts', 'src/webviews/**/protocol.ts', 'src/**/models/**/*.ts', 'src/**/utils/**/*.ts', @@ -41,7 +40,6 @@ const filePatterns = { 'src/constants.*.ts', 'src/env/browser/**/*', 'src/features.ts', - 'src/git/parsers/diffParser.ts', 'src/system/**/*.ts', '**/webview/**/*', ], diff --git a/src/webviews/apps/plus/composer/components/app.ts b/src/webviews/apps/plus/composer/components/app.ts index 8b4628c9a5d37..cb1bf236f650b 100644 --- a/src/webviews/apps/plus/composer/components/app.ts +++ b/src/webviews/apps/plus/composer/components/app.ts @@ -27,7 +27,7 @@ import { OpenOnboardingCommand, ReloadComposerCommand, } from '../../../../plus/composer/protocol'; -import { updateHunkAssignments } from '../../../../plus/composer/utils'; +import { updateHunkAssignments } from '../../../../plus/composer/utils/composer.utils'; import type { RepoButtonGroupClickEvent } from '../../../shared/components/repo-button-group'; import { focusableBaseStyles } from '../../../shared/components/styles/lit/a11y.css'; import { boxSizingBase } from '../../../shared/components/styles/lit/base.css'; diff --git a/src/webviews/apps/plus/composer/components/commits-panel.ts b/src/webviews/apps/plus/composer/components/commits-panel.ts index ae59b06f6b621..ef554f209800c 100644 --- a/src/webviews/apps/plus/composer/components/commits-panel.ts +++ b/src/webviews/apps/plus/composer/components/commits-panel.ts @@ -11,7 +11,7 @@ import { getFileCountForCommit, getUnassignedHunks, getUniqueFileNames, -} from '../../../../plus/composer/utils'; +} from '../../../../plus/composer/utils/composer.utils'; import { focusableBaseStyles } from '../../../shared/components/styles/lit/a11y.css'; import { boxSizingBase, inlineCode, scrollableBase } from '../../../shared/components/styles/lit/base.css'; import { ruleStyles } from '../../shared/components/vscode.css'; diff --git a/src/webviews/apps/plus/composer/components/details-panel.ts b/src/webviews/apps/plus/composer/components/details-panel.ts index 0e202950c20eb..9853d89669350 100644 --- a/src/webviews/apps/plus/composer/components/details-panel.ts +++ b/src/webviews/apps/plus/composer/components/details-panel.ts @@ -10,7 +10,7 @@ import { getUnassignedHunks, getUniqueFileNames, groupHunksByFile, -} from '../../../../plus/composer/utils'; +} from '../../../../plus/composer/utils/composer.utils'; import { focusableBaseStyles } from '../../../shared/components/styles/lit/a11y.css'; import { boxSizingBase, scrollableBase } from '../../../shared/components/styles/lit/base.css'; import type { CommitMessage } from './commit-message'; diff --git a/src/webviews/apps/tsconfig.json b/src/webviews/apps/tsconfig.json index 70032ab64d9e9..8e8975fe8f58e 100644 --- a/src/webviews/apps/tsconfig.json +++ b/src/webviews/apps/tsconfig.json @@ -13,7 +13,6 @@ "include": [ "**/*", "../ipc.ts", - "../plus/composer/utils.ts", "../**/protocol.ts", "../../**/models/**/*.ts", "../../**/utils/**/*.ts", @@ -23,7 +22,6 @@ "../../constants.*.ts", "../../env/browser/**/*", "../../features.ts", - "../../git/parsers/diffParser.ts", "../../system/**/*.ts", "../../**/webview/**/*" ], diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index d8713aabe73c4..40ade32b28edd 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -79,7 +79,7 @@ import { ReloadComposerCommand, } from './protocol'; import type { ComposerWebviewShowingArgs } from './registration'; -import type { WorkingTreeDiffs } from './utils'; +import type { WorkingTreeDiffs } from './utils/composer.utils'; import { convertToComposerDiffInfo, createCombinedDiffForCommit, @@ -88,7 +88,7 @@ import { getWorkingTreeDiffs, validateResultingDiff, validateSafetyState, -} from './utils'; +} from './utils/composer.utils'; export class ComposerWebviewProvider implements WebviewProvider { private readonly _disposable: Disposable; diff --git a/src/webviews/plus/composer/utils.ts b/src/webviews/plus/composer/utils/composer.utils.ts similarity index 97% rename from src/webviews/plus/composer/utils.ts rename to src/webviews/plus/composer/utils/composer.utils.ts index c73ba0386397e..c79198d0bbfeb 100644 --- a/src/webviews/plus/composer/utils.ts +++ b/src/webviews/plus/composer/utils/composer.utils.ts @@ -1,10 +1,10 @@ import { sha256 } from '@env/crypto'; -import type { GitDiff, ParsedGitDiff } from '../../../git/models/diff'; -import type { Repository } from '../../../git/models/repository'; -import { uncommitted, uncommittedStaged } from '../../../git/models/revision'; -import { parseGitDiff } from '../../../git/parsers/diffParser'; -import { getSettledValue } from '../../../system/promise'; -import type { ComposerCommit, ComposerHunk, ComposerSafetyState } from './protocol'; +import type { GitDiff, ParsedGitDiff } from '../../../../git/models/diff'; +import type { Repository } from '../../../../git/models/repository'; +import { uncommitted, uncommittedStaged } from '../../../../git/models/revision'; +import { parseGitDiff } from '../../../../git/parsers/diffParser'; +import { getSettledValue } from '../../../../system/promise'; +import type { ComposerCommit, ComposerHunk, ComposerSafetyState } from '../protocol'; export function getHunksForCommit(commit: ComposerCommit, hunks: ComposerHunk[]): ComposerHunk[] { return hunks.filter(hunk => commit.hunkIndices.includes(hunk.index)); From 4f9d6483dd995e7c96b3ef97918d192f85f7a29d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 27 Oct 2025 02:55:14 -0400 Subject: [PATCH 79/83] Updates dependencies (eslint-lite) - Should fix CI issues --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 68da74e0c8432..275ec536d2992 100644 --- a/package.json +++ b/package.json @@ -25980,7 +25980,7 @@ }, "devDependencies": { "@custom-elements-manifest/analyzer": "0.10.10", - "@eamodio/eslint-lite-webpack-plugin": "0.3.3", + "@eamodio/eslint-lite-webpack-plugin": "0.3.4", "@eslint/compat": "1.4.0", "@eslint/js": "9.37.0", "@playwright/test": "1.56.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4e0c1260c4ae..6724dc4901f78 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,8 +131,8 @@ importers: specifier: 0.10.10 version: 0.10.10 '@eamodio/eslint-lite-webpack-plugin': - specifier: 0.3.3 - version: 0.3.3(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1) + specifier: 0.3.4 + version: 0.3.4(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1) '@eslint/compat': specifier: 1.4.0 version: 1.4.0(eslint@9.37.0(jiti@2.4.0)) @@ -428,8 +428,8 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} - '@eamodio/eslint-lite-webpack-plugin@0.3.3': - resolution: {integrity: sha512-cXBm16OFztEv3ngaGopLLo15qUJaLs3h+qiKzUEV5cQzGj/A9kY0mGkAwA4CKIrEkC+L4ZPN5ji+W2JipF7n1Q==} + '@eamodio/eslint-lite-webpack-plugin@0.3.4': + resolution: {integrity: sha512-rz0HMmv1HzEHY4iSepH1JeKLUGTZdKWof/V3pVDmq5UZY7r4lGSqwyVveNqGbSwX9PrSjHXHtHdjmbMmufHr5g==} engines: {node: '>= 22.12.0', pnpm: '>= 10.0.0'} peerDependencies: eslint: ^9.23.0 @@ -6546,7 +6546,7 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} - '@eamodio/eslint-lite-webpack-plugin@0.3.3(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1)': + '@eamodio/eslint-lite-webpack-plugin@0.3.4(eslint@9.37.0(jiti@2.4.0))(webpack@5.102.1)': dependencies: eslint: 9.37.0(jiti@2.4.0) minimatch: 10.0.3 From 511362abc969231c01c45f07ae75f86fdb750bfb Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 29 Oct 2025 00:15:03 -0400 Subject: [PATCH 80/83] Improves webview type safety & adds custom editors --- src/system/webview.ts | 6 +- .../apps/commitDetails/stateProvider.ts | 2 +- src/webviews/apps/home/stateProvider.ts | 2 +- .../apps/plus/composer/stateProvider.ts | 2 +- src/webviews/apps/plus/graph/context.ts | 27 +++++++ src/webviews/apps/plus/graph/gate.ts | 2 +- src/webviews/apps/plus/graph/graph-app.ts | 2 +- src/webviews/apps/plus/graph/graph-header.ts | 2 +- .../plus/graph/graph-wrapper/graph-wrapper.ts | 2 +- .../apps/plus/graph/sidebar/sidebar.ts | 2 +- src/webviews/apps/plus/graph/stateProvider.ts | 78 ++++++++----------- .../apps/plus/timeline/stateProvider.ts | 2 +- src/webviews/apps/shared/stateProviderBase.ts | 8 +- src/webviews/commitDetails/protocol.ts | 2 +- src/webviews/home/protocol.ts | 2 +- src/webviews/plus/composer/protocol.ts | 4 +- src/webviews/plus/graph/protocol.ts | 2 +- src/webviews/plus/patchDetails/protocol.ts | 2 +- src/webviews/plus/timeline/protocol.ts | 2 +- src/webviews/protocol.ts | 11 +-- src/webviews/rebase/protocol.ts | 3 +- src/webviews/settings/protocol.ts | 2 +- src/webviews/webviewController.ts | 2 +- src/webviews/webviewProvider.ts | 2 +- 24 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 src/webviews/apps/plus/graph/context.ts diff --git a/src/system/webview.ts b/src/system/webview.ts index 4be34e3cdcf9a..a27c46b868a9b 100644 --- a/src/system/webview.ts +++ b/src/system/webview.ts @@ -1,9 +1,9 @@ import type { PlusCommands, WebviewCommands, WebviewViewCommands } from '../constants.commands'; -import type { WebviewIds, WebviewViewIds } from '../constants.views'; +import type { CustomEditorIds, WebviewIds, WebviewViewIds } from '../constants.views'; export function createWebviewCommandLink( command: WebviewCommands | WebviewViewCommands | PlusCommands, - webviewId: WebviewIds | WebviewViewIds, + webviewId: WebviewIds | WebviewViewIds | CustomEditorIds, webviewInstanceId: string | undefined, args?: T, ): string { @@ -13,7 +13,7 @@ export function createWebviewCommandLink( } export interface WebviewContext { - webview: WebviewIds | WebviewViewIds; + webview: WebviewIds | WebviewViewIds | CustomEditorIds; webviewInstance: string | undefined; } diff --git a/src/webviews/apps/commitDetails/stateProvider.ts b/src/webviews/apps/commitDetails/stateProvider.ts index 075a73b343f08..f1ddbe4767308 100644 --- a/src/webviews/apps/commitDetails/stateProvider.ts +++ b/src/webviews/apps/commitDetails/stateProvider.ts @@ -18,7 +18,7 @@ import { stateContext } from './context'; type State = IpcSerialized<_State>; -export class CommitDetailsStateProvider extends StateProviderBase { +export class CommitDetailsStateProvider extends StateProviderBase { protected override get deferBootstrap(): boolean { return true; } diff --git a/src/webviews/apps/home/stateProvider.ts b/src/webviews/apps/home/stateProvider.ts index a5d5118fe6c1b..aede1b40c19c9 100644 --- a/src/webviews/apps/home/stateProvider.ts +++ b/src/webviews/apps/home/stateProvider.ts @@ -16,7 +16,7 @@ import type { ReactiveElementHost } from '../shared/appHost'; import { StateProviderBase } from '../shared/stateProviderBase'; import { stateContext } from './context'; -export class HomeStateProvider extends StateProviderBase { +export class HomeStateProvider extends StateProviderBase { protected override createContextProvider(state: State): ContextProvider { return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } diff --git a/src/webviews/apps/plus/composer/stateProvider.ts b/src/webviews/apps/plus/composer/stateProvider.ts index ca12fd10815cc..3987934815c57 100644 --- a/src/webviews/apps/plus/composer/stateProvider.ts +++ b/src/webviews/apps/plus/composer/stateProvider.ts @@ -24,7 +24,7 @@ import type { ReactiveElementHost } from '../../shared/appHost'; import { StateProviderBase } from '../../shared/stateProviderBase'; import { stateContext } from './context'; -export class ComposerStateProvider extends StateProviderBase { +export class ComposerStateProvider extends StateProviderBase { protected override createContextProvider(state: State): ContextProvider { return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } diff --git a/src/webviews/apps/plus/graph/context.ts b/src/webviews/apps/plus/graph/context.ts new file mode 100644 index 0000000000000..3d2085984c2bc --- /dev/null +++ b/src/webviews/apps/plus/graph/context.ts @@ -0,0 +1,27 @@ +import { createContext } from '@lit/context'; +import type { SearchQuery } from '../../../../constants.search'; +import type { + GraphSearchResults, + GraphSearchResultsError, + GraphSelectedRows, + State, +} from '../../../plus/graph/protocol'; + +export interface AppState extends State { + state: State; + activeDay: number | undefined; + activeRow: string | undefined; + filter: SearchQuery; + isBusy: boolean; + loading: boolean; + mcpBannerCollapsed?: boolean | undefined; + searching: boolean; + searchResultsHidden: boolean; + searchResultsResponse: GraphSearchResults | GraphSearchResultsError | undefined; + searchResults: GraphSearchResults | undefined; + searchResultsError: GraphSearchResultsError | undefined; + selectedRows: GraphSelectedRows | undefined; + visibleDays: { top: number; bottom: number } | undefined; +} + +export const graphStateContext = createContext('graph-state-context'); diff --git a/src/webviews/apps/plus/graph/gate.ts b/src/webviews/apps/plus/graph/gate.ts index c4e50e13eb5d3..842fecd779a9d 100644 --- a/src/webviews/apps/plus/graph/gate.ts +++ b/src/webviews/apps/plus/graph/gate.ts @@ -6,7 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { createWebviewCommandLink } from '../../../../system/webview'; import { GlElement } from '../../shared/components/element'; import { linkStyles } from '../shared/components/vscode.css'; -import { graphStateContext } from './stateProvider'; +import { graphStateContext } from './context'; import '../../shared/components/feature-badge'; import '../../shared/components/feature-gate'; diff --git a/src/webviews/apps/plus/graph/graph-app.ts b/src/webviews/apps/plus/graph/graph-app.ts index bbdbdc2f853d2..8bb6ad6a9da4a 100644 --- a/src/webviews/apps/plus/graph/graph-app.ts +++ b/src/webviews/apps/plus/graph/graph-app.ts @@ -13,11 +13,11 @@ import { ipcContext } from '../../shared/contexts/ipc'; import type { TelemetryContext } from '../../shared/contexts/telemetry'; import { telemetryContext } from '../../shared/contexts/telemetry'; import { emitTelemetrySentEvent } from '../../shared/telemetry'; +import { graphStateContext } from './context'; import type { GlGraphWrapper } from './graph-wrapper/graph-wrapper'; import type { GlGraphHover } from './hover/graphHover'; import type { GraphMinimapDaySelectedEventDetail } from './minimap/minimap'; import type { GlGraphMinimapContainer } from './minimap/minimap-container'; -import { graphStateContext } from './stateProvider'; import './gate'; import './graph-header'; import './graph-wrapper/graph-wrapper'; diff --git a/src/webviews/apps/plus/graph/graph-header.ts b/src/webviews/apps/plus/graph/graph-header.ts index b03f6b1e67ba3..196ed8a3b8dcb 100644 --- a/src/webviews/apps/plus/graph/graph-header.ts +++ b/src/webviews/apps/plus/graph/graph-header.ts @@ -48,7 +48,7 @@ import type { TelemetryContext } from '../../shared/contexts/telemetry'; import { telemetryContext } from '../../shared/contexts/telemetry'; import { emitTelemetrySentEvent } from '../../shared/telemetry'; import { ruleStyles } from '../shared/components/vscode.css'; -import { graphStateContext } from './stateProvider'; +import { graphStateContext } from './context'; import { actionButton, linkBase } from './styles/graph.css'; import { graphHeaderControlStyles, progressStyles, repoHeaderStyles, titlebarStyles } from './styles/header.css'; import '@shoelace-style/shoelace/dist/components/option/option.js'; diff --git a/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts b/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts index e4c868dce1a25..af8240ec83b8d 100644 --- a/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts +++ b/src/webviews/apps/plus/graph/graph-wrapper/graph-wrapper.ts @@ -26,7 +26,7 @@ import { telemetryContext } from '../../../shared/contexts/telemetry'; import type { Disposable } from '../../../shared/events'; import type { ThemeChangeEvent } from '../../../shared/theme'; import { onDidChangeTheme } from '../../../shared/theme'; -import { graphStateContext } from '../stateProvider'; +import { graphStateContext } from '../context'; import type { GlGraph } from './gl-graph'; import type { GraphWrapperTheming } from './gl-graph.react'; import './gl-graph'; diff --git a/src/webviews/apps/plus/graph/sidebar/sidebar.ts b/src/webviews/apps/plus/graph/sidebar/sidebar.ts index 51379dd775f44..20e4559370320 100644 --- a/src/webviews/apps/plus/graph/sidebar/sidebar.ts +++ b/src/webviews/apps/plus/graph/sidebar/sidebar.ts @@ -9,7 +9,7 @@ import { ipcContext } from '../../../shared/contexts/ipc'; import type { Disposable } from '../../../shared/events'; import type { HostIpc } from '../../../shared/ipc'; import { emitTelemetrySentEvent } from '../../../shared/telemetry'; -import { graphStateContext } from '../stateProvider'; +import { graphStateContext } from '../context'; import '../../../shared/components/code-icon'; import '../../../shared/components/overlays/tooltip'; diff --git a/src/webviews/apps/plus/graph/stateProvider.ts b/src/webviews/apps/plus/graph/stateProvider.ts index b57c88621a1e2..e6a6abb2b6b69 100644 --- a/src/webviews/apps/plus/graph/stateProvider.ts +++ b/src/webviews/apps/plus/graph/stateProvider.ts @@ -1,13 +1,7 @@ -import { ContextProvider, createContext } from '@lit/context'; -import type { SearchQuery } from '../../../../constants.search'; +import { ContextProvider } from '@lit/context'; import { debounce } from '../../../../system/function/debounce'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; -import type { - GraphSearchResults, - GraphSearchResultsError, - GraphSelectedRows, - State, -} from '../../../plus/graph/protocol'; +import type { GraphSearchResults, GraphSearchResultsError, State } from '../../../plus/graph/protocol'; import { DidChangeAvatarsNotification, DidChangeBranchStateNotification, @@ -36,18 +30,14 @@ import { signalObjectState, signalState } from '../../shared/components/signal-u import type { LoggerContext } from '../../shared/contexts/logger'; import type { HostIpc } from '../../shared/ipc'; import { StateProviderBase } from '../../shared/stateProviderBase'; +import type { AppState } from './context'; +import { graphStateContext } from './context'; const BaseWebviewStateKeys = [ 'timestamp', 'webviewId', 'webviewInstanceId', -] as const satisfies readonly (keyof WebviewState)[] as readonly string[]; - -interface AppState { - activeDay?: number; - activeRow?: string; - visibleDays?: { top: number; bottom: number }; -} +] as const satisfies readonly (keyof WebviewState)[] as readonly string[]; function getSearchResultModel(searchResults: State['searchResults']): { results: undefined | GraphSearchResults; @@ -65,24 +55,13 @@ function getSearchResultModel(searchResults: State['searchResults']): { return { results: results, resultsError: resultsError }; } -export const graphStateContext = createContext('graph-state-context'); - -export class GraphStateProvider extends StateProviderBase { +export class GraphStateProvider extends StateProviderBase { // App state members moved from GraphAppState @signalState() - accessor activeDay: number | undefined; + accessor activeDay: AppState['activeDay']; @signalState() - accessor activeRow: string | undefined = undefined; - - @signalState(false) - accessor loading = false; - - @signalState(false) - accessor searching = false; - - @signalObjectState() - accessor visibleDays: AppState['visibleDays']; + accessor activeRow: AppState['activeRow']; @signalObjectState( { query: '' }, @@ -92,10 +71,20 @@ export class GraphStateProvider extends StateProviderBase(undefined, { afterChange: (target, value) => { @@ -104,16 +93,19 @@ export class GraphStateProvider extends StateProviderBase { +export class TimelineStateProvider extends StateProviderBase { protected override createContextProvider(state: State): ContextProvider { return new ContextProvider(this.host, { context: stateContext, initialValue: state }); } diff --git a/src/webviews/apps/shared/stateProviderBase.ts b/src/webviews/apps/shared/stateProviderBase.ts index 7332e6e679a47..c2eb06197bd0c 100644 --- a/src/webviews/apps/shared/stateProviderBase.ts +++ b/src/webviews/apps/shared/stateProviderBase.ts @@ -1,5 +1,6 @@ import type { Context, ContextProvider, ContextType } from '@lit/context'; import { fromBase64ToString } from '@env/base64'; +import type { CustomEditorIds, WebviewIds, WebviewViewIds } from '../../../constants.views'; import { isPromise } from '../../../system/promise'; import type { IpcMessage, WebviewState } from '../../protocol'; import { WebviewReadyRequest } from '../../protocol'; @@ -16,8 +17,11 @@ import type { HostIpc } from './ipc'; * - Sync: Uses bootstrap state from HTML * - Async: Requests full state from extension after connection */ -export abstract class StateProviderBase> - implements Disposable +export abstract class StateProviderBase< + ID extends WebviewIds | WebviewViewIds | CustomEditorIds, + State extends WebviewState, + TContext extends Context, +> implements Disposable { protected readonly disposable: Disposable; protected readonly provider: ContextProvider; diff --git a/src/webviews/commitDetails/protocol.ts b/src/webviews/commitDetails/protocol.ts index f13e3e26aeaf6..c1147feea6466 100644 --- a/src/webviews/commitDetails/protocol.ts +++ b/src/webviews/commitDetails/protocol.ts @@ -92,7 +92,7 @@ export interface DraftState { inReview: boolean; } -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.views.commitDetails' | 'gitlens.views.graphDetails'> { mode: Mode; pinned: boolean; diff --git a/src/webviews/home/protocol.ts b/src/webviews/home/protocol.ts index 14cced16e3489..6323628262fec 100644 --- a/src/webviews/home/protocol.ts +++ b/src/webviews/home/protocol.ts @@ -21,7 +21,7 @@ import { IpcCommand, IpcNotification, IpcRequest } from '../protocol'; export const scope: IpcScope = 'home'; -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.views.home'> { discovering: boolean; repositories: DidChangeRepositoriesParams; webroot?: string; diff --git a/src/webviews/plus/composer/protocol.ts b/src/webviews/plus/composer/protocol.ts index 23f5d7254b207..e4ca4a31b5a01 100644 --- a/src/webviews/plus/composer/protocol.ts +++ b/src/webviews/plus/composer/protocol.ts @@ -60,7 +60,7 @@ export interface ComposerSafetyState { // timestamp: number; } -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.composer'> { // data model hunks: ComposerHunk[]; @@ -111,7 +111,7 @@ export interface State extends WebviewState { }; } -export const initialState: Omit = { +export const initialState: Omit> = { hunks: [], commits: [], baseCommit: null, diff --git a/src/webviews/plus/graph/protocol.ts b/src/webviews/plus/graph/protocol.ts index f198814570120..2c3007f60c72d 100644 --- a/src/webviews/plus/graph/protocol.ts +++ b/src/webviews/plus/graph/protocol.ts @@ -91,7 +91,7 @@ export type GraphMinimapMarkerTypes = export const supportedRefMetadataTypes: GraphRefMetadataType[] = ['upstream', 'pullRequest', 'issue']; -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.graph' | 'gitlens.views.graph'> { windowFocused?: boolean; webroot?: string; repositories?: GraphRepository[]; diff --git a/src/webviews/plus/patchDetails/protocol.ts b/src/webviews/plus/patchDetails/protocol.ts index 8eebeb2c57b5e..b11d3feb79816 100644 --- a/src/webviews/plus/patchDetails/protocol.ts +++ b/src/webviews/plus/patchDetails/protocol.ts @@ -151,7 +151,7 @@ export interface CreatePatchState { userSelections?: DraftUserSelection[]; } -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.patchDetails' | 'gitlens.views.patchDetails'> { mode: Mode; preferences: Preferences; diff --git a/src/webviews/plus/timeline/protocol.ts b/src/webviews/plus/timeline/protocol.ts index 9e0136a84fcbc..57bc16e6d075c 100644 --- a/src/webviews/plus/timeline/protocol.ts +++ b/src/webviews/plus/timeline/protocol.ts @@ -8,7 +8,7 @@ import { IpcCommand, IpcNotification, IpcRequest } from '../../protocol'; export const scope: IpcScope = 'timeline'; -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.timeline' | 'gitlens.views.timeline'> { dataset?: Promise; config: { showAllBranches: boolean; diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts index 59769f377e05d..e910aea12b7ff 100644 --- a/src/webviews/protocol.ts +++ b/src/webviews/protocol.ts @@ -74,13 +74,14 @@ export class IpcNotification extends IpcCall {} // COMMANDS & REQUESTS +export interface WebviewReadyParams { + bootstrap?: boolean; +} + export interface WebviewReadyResponse { state?: unknown | Promise; } -export const WebviewReadyRequest = new IpcRequest<{ bootstrap?: boolean }, WebviewReadyResponse>( - 'core', - 'webview/ready', -); +export const WebviewReadyRequest = new IpcRequest('core', 'webview/ready'); export interface WebviewFocusChangedParams { focused: boolean; @@ -190,7 +191,7 @@ export function assertsConfigKeyValue( // Noop } -export interface WebviewState { +export interface WebviewState { webviewId: Id; webviewInstanceId: string | undefined; timestamp: number; diff --git a/src/webviews/rebase/protocol.ts b/src/webviews/rebase/protocol.ts index 70826f4c2664b..93c2fcdac04ee 100644 --- a/src/webviews/rebase/protocol.ts +++ b/src/webviews/rebase/protocol.ts @@ -1,10 +1,9 @@ -import type { CustomEditorIds } from '../../constants.views'; import type { IpcScope, WebviewState } from '../protocol'; import { IpcCommand, IpcNotification } from '../protocol'; export const scope: IpcScope = 'rebase'; -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.rebase'> { branch: string; onto: { sha: string; commit?: Commit } | undefined; diff --git a/src/webviews/settings/protocol.ts b/src/webviews/settings/protocol.ts index 865c903756abd..926321b1e669c 100644 --- a/src/webviews/settings/protocol.ts +++ b/src/webviews/settings/protocol.ts @@ -5,7 +5,7 @@ import { IpcNotification, IpcRequest } from '../protocol'; export const scope: IpcScope = 'settings'; -export interface State extends WebviewState { +export interface State extends WebviewState<'gitlens.settings'> { version: string; config: Config; customSettings?: Record; diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 4e2194081190a..494007b26fc4e 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -419,7 +419,7 @@ export class WebviewController< }); } - get baseWebviewState(): WebviewState { + get baseWebviewState(): WebviewState { return { webviewId: this.id, webviewInstanceId: this.instanceId, diff --git a/src/webviews/webviewProvider.ts b/src/webviews/webviewProvider.ts index 5312b0c8b1fcf..a1327f689d66f 100644 --- a/src/webviews/webviewProvider.ts +++ b/src/webviews/webviewProvider.ts @@ -69,7 +69,7 @@ export interface WebviewHost { readonly ready: boolean; readonly viewColumn: ViewColumn | undefined; readonly visible: boolean; - readonly baseWebviewState: WebviewState; + readonly baseWebviewState: WebviewState; readonly cspNonce: string; getWebRoot(): string; From c8eb3b715223c2ab85753c484c416f8b68516b87 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 29 Oct 2025 00:22:27 -0400 Subject: [PATCH 81/83] Removes unused function --- src/webviews/webviewController.ts | 34 ------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 494007b26fc4e..751b60a98b645 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -944,37 +944,3 @@ export function setContextKeys( ): void { void setContext(`${contextKeyPrefix}:visible`, true); } - -export function updatePendingContext( - current: Context, - pending: Partial | undefined, - update: Partial, - force: boolean = false, -): [changed: boolean, pending: Partial | undefined] { - let changed = false; - for (const [key, value] of Object.entries(update)) { - const currentValue = (current as unknown as Record)[key]; - if ( - !force && - (currentValue instanceof Uri || value instanceof Uri) && - (currentValue as any)?.toString() === value?.toString() - ) { - continue; - } - - if (!force && currentValue === value) { - if ((value !== undefined || key in current) && (pending == null || !(key in pending))) { - continue; - } - } - - if (pending == null) { - pending = {}; - } - - (pending as Record)[key] = value; - changed = true; - } - - return [changed, pending]; -} From 3dbdc7d8a70fa9fa42b0e4a2e7a8318fdb9504ab Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 29 Oct 2025 19:24:29 -0400 Subject: [PATCH 82/83] Improves sequentialize decorator w/ deduplication Adds unit tests for decorators --- .../decorators/__tests__/decorators.test.ts | 791 ++++++++++++++++++ src/system/decorators/gate.ts | 4 +- src/system/decorators/sequentialize.ts | 116 +++ src/system/decorators/serialize.ts | 37 - src/webviews/webviewController.ts | 2 +- 5 files changed, 910 insertions(+), 40 deletions(-) create mode 100644 src/system/decorators/__tests__/decorators.test.ts create mode 100644 src/system/decorators/sequentialize.ts delete mode 100644 src/system/decorators/serialize.ts diff --git a/src/system/decorators/__tests__/decorators.test.ts b/src/system/decorators/__tests__/decorators.test.ts new file mode 100644 index 0000000000000..7dac2551f5ec1 --- /dev/null +++ b/src/system/decorators/__tests__/decorators.test.ts @@ -0,0 +1,791 @@ +import * as assert from 'assert'; +import { gate } from '../gate'; +import { memoize } from '../memoize'; +import { sequentialize } from '../sequentialize'; + +suite('Decorator Test Suite', () => { + suite('sequentialize', () => { + test('should execute calls sequentially', async () => { + const executionOrder: number[] = []; + let counter = 0; + + class TestClass { + @sequentialize() + async method(delay: number): Promise { + const id = ++counter; + executionOrder.push(id); + await new Promise(resolve => setTimeout(resolve, delay)); + return id; + } + } + + const instance = new TestClass(); + + // Start three calls with different delays + const p1 = instance.method(50); // Should execute first + const p2 = instance.method(10); // Should execute second (even though faster) + const p3 = instance.method(5); // Should execute third + + const results = await Promise.all([p1, p2, p3]); + + // All should complete + assert.deepStrictEqual(results, [1, 2, 3]); + // Execution order should be sequential + assert.deepStrictEqual(executionOrder, [1, 2, 3]); + }); + + test('should deduplicate consecutive calls with same arguments', async () => { + let executionCount = 0; + const counterMap = new Map(); + + class TestClass { + @sequentialize() + async method(value: string): Promise { + executionCount++; + let counter = counterMap.get(value) || 0; + const id = ++counter; + counterMap.set(value, counter); + await new Promise(resolve => setTimeout(resolve, 10)); + return `${value}=${id}`; + } + } + + const instance = new TestClass(); + + const p1 = instance.method('msg1'); // Call 1 starts immediately + const p2 = instance.method('msg1'); // Call 2 chains and becomes waiting + const p3 = instance.method('msg1'); // Call 3 deduplicates with Call 2 (consecutive, same args) + const p4 = instance.method('msg2'); // Call 4 chains, doesn't deduplicate (different args) + const p5 = instance.method('msg1'); // Call 5 chains, doesn't deduplicate (not consecutive) + + const [r1, r2, r3, r4, r5] = await Promise.all([p1, p2, p3, p4, p5]); + + // Total executions: 4 (p1, p2 shared by calls 2&3, p4, p5) + assert.strictEqual(executionCount, 4); + + assert.strictEqual(r1, `msg1=1`); + // Calls 2 and 3 should share the same result + assert.strictEqual(r2, `msg1=2`); + assert.strictEqual(r3, `msg1=2`); + assert.strictEqual(r4, `msg2=1`); + assert.strictEqual(r5, `msg1=3`); + }); + + test('should not deduplicate non-consecutive calls', async () => { + let executionCount = 0; + const counterMap = new Map(); + + class TestClass { + @sequentialize() + async method(value: string): Promise { + executionCount++; + let counter = counterMap.get(value) || 0; + const id = ++counter; + counterMap.set(value, counter); + await new Promise(resolve => setTimeout(resolve, 10)); + return `${value}=${id}`; + } + } + + const instance = new TestClass(); + + const p1 = instance.method('msg1'); // Call 1 starts immediately + const p2 = instance.method('msg1'); // Call 2 chains and becomes waiting + const p3 = instance.method('msg2'); // Call 3 chains, doesn't deduplicate (different args) + const p4 = instance.method('msg1'); // Call 4 chains, doesn't deduplicate (not consecutive) + + const [r1, r2, r3, r4] = await Promise.all([p1, p2, p3, p4]); + + // Should execute 4 times (no deduplication) + assert.strictEqual(executionCount, 4); + + assert.strictEqual(r1, `msg1=1`); + assert.strictEqual(r2, `msg1=2`); + assert.strictEqual(r3, `msg2=1`); + assert.strictEqual(r4, `msg1=3`); + }); + + test('should work with custom resolver', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize({ getDedupingKey: (obj: { id: number }) => obj.id.toString() }) + async method(obj: { id: number; data: string }): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return `${obj.id}=${executionCount}`; + } + } + + const instance = new TestClass(); + + const p1 = instance.method({ id: 1, data: 'a' }); // Call 1 starts immediately + const p2 = instance.method({ id: 1, data: 'b' }); // Call 2 chains and becomes waiting + const p3 = instance.method({ id: 1, data: 'c' }); // Call 3 deduplicates with Call 2 (consecutive, same resolved args) + const p4 = instance.method({ id: 2, data: 'a' }); // Call 4 chains, doesn't deduplicate (not consecutive) + const p5 = instance.method({ id: 2, data: 'd' }); // Call 5 deduplicates with Call 4 (consecutive, same resolved args) + + const [r1, r2, r3, r4, r5] = await Promise.all([p1, p2, p3, p4, p5]); + + // Should execute 3 times (p1, p2 shared by calls 2&3, p4, p5 shared by calls 4&5) + assert.strictEqual(executionCount, 3); + + assert.strictEqual(r1, `1=1`); + assert.strictEqual(r2, `1=2`); + assert.strictEqual(r3, `1=2`); + assert.strictEqual(r4, `2=3`); + assert.strictEqual(r5, `2=3`); + }); + + test('should handle errors correctly', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize() + async method(shouldFail: boolean): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + if (shouldFail) { + throw new Error('Test error'); + } + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method(true); // Will fail + const p2 = instance.method(false); // Should still execute after p1 fails + + await assert.rejects(p1, /Test error/); + const result = await p2; + + assert.strictEqual(executionCount, 2); + assert.strictEqual(result, 2); + }); + + test('should clean up state after all calls complete', async () => { + class TestClass { + @sequentialize() + async method(value: string): Promise { + await new Promise(resolve => setTimeout(resolve, 10)); + return value; + } + } + + const instance = new TestClass(); + const stateKey = '$sequentialize$method'; + + // Initially no state + assert.strictEqual((instance as any)[stateKey], undefined); + + const p1 = instance.method('test'); + // State should exist while call is pending + assert.notStrictEqual((instance as any)[stateKey], undefined); + + await p1; + // State should be cleaned up after completion + assert.strictEqual((instance as any)[stateKey], undefined); + }); + + test('should handle empty arguments', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize() + async method(): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method(); + const p2 = instance.method(); // Should chain and become waiting + const p3 = instance.method(); // Should dedupe with p2 + + const [r1, r2, r3] = await Promise.all([p1, p2, p3]); + + // Should execute 2 times (p1, then p2 shared by calls 2&3) + assert.strictEqual(executionCount, 2); + assert.strictEqual(r1, 1); + assert.strictEqual(r2, 2); + assert.strictEqual(r3, 2); + }); + + test('should handle error in deduplicated waiting call', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize() + async method(shouldFail: boolean): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + if (shouldFail) { + throw new Error('Test error'); + } + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method(false); // Succeeds + const p2 = instance.method(true); // Becomes waiting, will fail + const p3 = instance.method(true); // Dedupes with p2, should also fail + + await p1; // Wait for first to complete + + // Both p2 and p3 should reject with the same error + await assert.rejects(p2, /Test error/); + await assert.rejects(p3, /Test error/); + + // Should execute 2 times (p1, then p2 shared by p2&p3) + assert.strictEqual(executionCount, 2); + }); + + test('should handle null and undefined arguments', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize() + async method(value: string | null | undefined): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method(null); // Execution 1 (runs immediately) + const p2 = instance.method(null); // Execution 2 (chains, becomes waiting) + const p3 = instance.method(undefined); // Dedupes with p2 (null and undefined both resolve to '') + const p4 = instance.method('test'); // Execution 3 (different arg) + + const [r1, r2, r3, r4] = await Promise.all([p1, p2, p3, p4]); + + // Should execute 3 times (p1, p2 shared by p2&p3, p4) + assert.strictEqual(executionCount, 3); + + assert.strictEqual(r1, 1); + assert.strictEqual(r2, 2); + assert.strictEqual(r3, 2); + assert.strictEqual(r4, 3); + }); + + test('should support parallel queues with getQueueKey', async () => { + let executionCount = 0; + const executionOrder: string[] = []; + + class TestClass { + @sequentialize({ + getQueueKey: (msg: { channel: string; id: string }) => msg.channel, + getDedupingKey: (msg: { channel: string; id: string }) => msg.id, + }) + async method(msg: { channel: string; id: string }): Promise { + const count = ++executionCount; + executionOrder.push(`${msg.channel}:${msg.id}:start`); + await new Promise(resolve => setTimeout(resolve, 10)); + executionOrder.push(`${msg.channel}:${msg.id}:end`); + return count; + } + } + + const instance = new TestClass(); + + // Queue A: 3 calls + const p1 = instance.method({ channel: 'A', id: '1' }); // Queue A, runs immediately + const p2 = instance.method({ channel: 'A', id: '1' }); // Queue A, chains, becomes waiting + const p3 = instance.method({ channel: 'A', id: '1' }); // Queue A, dedupes with p2 + + // Queue B: 2 calls (runs in parallel with Queue A) + const p4 = instance.method({ channel: 'B', id: '1' }); // Queue B, runs immediately + const p5 = instance.method({ channel: 'B', id: '2' }); // Queue B, chains (different id) + + // Queue A: 1 more call + const p6 = instance.method({ channel: 'A', id: '2' }); // Queue A, chains (different id) + + const results = await Promise.all([p1, p2, p3, p4, p5, p6]); + + // Should execute 5 times total (p1, p2 shared by p2&p3, p4, p5, p6) + assert.strictEqual(executionCount, 5); + + // p2 and p3 should share the same result (deduplicated) + assert.strictEqual(results[1], results[2]); + + // Verify execution order shows parallel execution + // Both queues should start before either finishes (parallel execution) + const aStartIndex = executionOrder.indexOf('A:1:start'); + const bStartIndex = executionOrder.indexOf('B:1:start'); + const aEndIndex = executionOrder.indexOf('A:1:end'); + assert.ok( + aStartIndex >= 0 && bStartIndex >= 0 && aEndIndex >= 0, + `Missing expected execution markers in: ${executionOrder.join(', ')}`, + ); + assert.ok( + bStartIndex < aEndIndex, + `Expected B to start before A ends (parallel), but order was: ${executionOrder.join(', ')}`, + ); + + // Verify sequential execution within each queue + const a1Start = executionOrder.indexOf('A:1:start'); + const a1End = executionOrder.indexOf('A:1:end'); + const a2Start = executionOrder.indexOf('A:2:start'); + assert.ok( + a1Start < a1End && a1End < a2Start, + `Expected A:1 to complete before A:2 starts (sequential in queue), but order was: ${executionOrder.join(', ')}`, + ); + + const b1Start = executionOrder.indexOf('B:1:start'); + const b1End = executionOrder.indexOf('B:1:end'); + const b2Start = executionOrder.indexOf('B:2:start'); + assert.ok( + b1Start < b1End && b1End < b2Start, + `Expected B:1 to complete before B:2 starts (sequential in queue), but order was: ${executionOrder.join(', ')}`, + ); + }); + + test('sequentialize should work with multiple instances', async () => { + let executionCount = 0; + + class TestClass { + @sequentialize() + async method(value: string): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance1 = new TestClass(); + const instance2 = new TestClass(); + + // Calls on different instances should not interfere + const p1 = instance1.method('test'); + const p2 = instance2.method('test'); + const p3 = instance1.method('test'); + + await Promise.all([p1, p2, p3]); + + // Should execute 3 times (instance1: 2 sequential, instance2: 1) + assert.strictEqual(executionCount, 3); + }); + }); + + suite('gate', () => { + test('should deduplicate concurrent calls with same arguments', async () => { + let executionCount = 0; + + class TestClass { + @gate() + async method(value: string): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 50)); + return executionCount; + } + } + + const instance = new TestClass(); + + // All three calls happen concurrently with same args + const p1 = instance.method('test'); + const p2 = instance.method('test'); + const p3 = instance.method('test'); + + const results = await Promise.all([p1, p2, p3]); + + // Should only execute once + assert.strictEqual(executionCount, 1); + // All should get the same result + assert.strictEqual(results[0], 1); + assert.strictEqual(results[1], 1); + assert.strictEqual(results[2], 1); + }); + + test('should not deduplicate calls with different arguments', async () => { + let executionCount = 0; + + class TestClass { + @gate() + async method(value: string): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method('a'); + const p2 = instance.method('b'); + const p3 = instance.method('c'); + + await Promise.all([p1, p2, p3]); + + // Should execute three times (different args) + assert.strictEqual(executionCount, 3); + }); + + test('should allow new calls after promise resolves', async () => { + let executionCount = 0; + + class TestClass { + @gate() + async method(value: string): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = await instance.method('test'); + const result2 = await instance.method('test'); + + // Should execute twice (sequential, not concurrent) + assert.strictEqual(executionCount, 2); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 2); + }); + + test('should work with custom resolver', async () => { + let executionCount = 0; + const executionOrder: string[] = []; + + class TestClass { + @gate((obj: { id: number }) => obj.id.toString()) + async method(obj: { id: number; data: string }): Promise { + const count = ++executionCount; + executionOrder.push(`${obj.id}:start`); + await new Promise(resolve => setTimeout(resolve, 10)); + executionOrder.push(`${obj.id}:end`); + return count; + } + } + + const instance = new TestClass(); + + // Start all three calls at the same time + const p1 = instance.method({ id: 1, data: 'a' }); + const p2 = instance.method({ id: 1, data: 'b' }); // Same id, should dedupe + const p3 = instance.method({ id: 2, data: 'a' }); // Different id, runs in parallel + + const results = await Promise.all([p1, p2, p3]); + + // Should execute twice (p1&p2 share, p3 runs in parallel) + assert.strictEqual(executionCount, 2); + assert.strictEqual(results[0], results[1]); // p1 and p2 share result + assert.notStrictEqual(results[0], results[2]); // p3 has different result + + // Verify parallel execution: both should start before either finishes + const id1Start = executionOrder.indexOf('1:start'); + const id2Start = executionOrder.indexOf('2:start'); + const id1End = executionOrder.indexOf('1:end'); + assert.ok( + id1Start >= 0 && id2Start >= 0 && id1End >= 0, + `Missing expected execution markers in: ${executionOrder.join(', ')}`, + ); + assert.ok( + id2Start < id1End, + `Expected id:2 to start before id:1 ends (parallel), but order was: ${executionOrder.join(', ')}`, + ); + }); + + test('should handle non-promise return values', () => { + let executionCount = 0; + + class TestClass { + @gate() + method(value: string): number { + executionCount++; + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = instance.method('test'); + const result2 = instance.method('test'); + + // Non-promise values should not be gated + assert.strictEqual(executionCount, 2); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 2); + }); + + test('should handle errors in gated calls', async () => { + let executionCount = 0; + + class TestClass { + @gate() + async method(shouldFail: boolean): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + if (shouldFail) { + throw new Error('Test error'); + } + return executionCount; + } + } + + const instance = new TestClass(); + + const p1 = instance.method(true); + const p2 = instance.method(true); // Should share the same error + + await assert.rejects(p1, /Test error/); + await assert.rejects(p2, /Test error/); + + // Should only execute once (both share the same promise) + assert.strictEqual(executionCount, 1); + + // After error, new calls should work + const result = await instance.method(false); + assert.strictEqual(result, 2); + }); + + test('gate should work with multiple instances', async () => { + let executionCount = 0; + + class TestClass { + @gate() + async method(value: string): Promise { + const count = ++executionCount; + await new Promise(resolve => setTimeout(resolve, 50)); + return count; + } + } + + const instance1 = new TestClass(); + const instance2 = new TestClass(); + + // Concurrent calls on different instances should not deduplicate + const start = Date.now(); + const p1 = instance1.method('test'); + const p2 = instance2.method('test'); + const p3 = instance1.method('test'); // Should dedupe with p1 + + const results = await Promise.all([p1, p2, p3]); + const totalTime = Date.now() - start; + + // Should execute 2 times (instance1: 1, instance2: 1) + assert.strictEqual(executionCount, 2); + assert.strictEqual(results[0], results[2]); // p1 and p3 share result + assert.notStrictEqual(results[0], results[1]); // p1 and p2 different + // Should run in parallel (total time should be ~50ms, not ~100ms) + assert.ok(totalTime < 80, `Expected parallel execution (~50ms), but took ${totalTime}ms`); + }); + }); + + suite('memoize', () => { + test('should cache results for same arguments', () => { + let executionCount = 0; + + class TestClass { + @memoize() + method(value: string): number { + executionCount++; + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = instance.method('test'); + const result2 = instance.method('test'); + const result3 = instance.method('test'); + + // Should only execute once + assert.strictEqual(executionCount, 1); + // All results should be the same + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 1); + assert.strictEqual(result3, 1); + }); + + test('should not cache results for different arguments', () => { + let executionCount = 0; + + class TestClass { + @memoize() + method(value: string): number { + executionCount++; + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = instance.method('a'); + const result2 = instance.method('b'); + const result3 = instance.method('c'); + + // Should execute three times + assert.strictEqual(executionCount, 3); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 2); + assert.strictEqual(result3, 3); + }); + + test('should work with custom resolver', () => { + let executionCount = 0; + + class TestClass { + @memoize((obj: { id: number }) => obj.id.toString()) + method(obj: { id: number; data: string }): number { + executionCount++; + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = instance.method({ id: 1, data: 'a' }); + const result2 = instance.method({ id: 1, data: 'b' }); // Same id, should use cache + const result3 = instance.method({ id: 2, data: 'a' }); // Different id, new execution + + // Should execute twice + assert.strictEqual(executionCount, 2); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 1); // Cached + assert.strictEqual(result3, 2); + }); + + test('should cache per instance', () => { + let executionCount = 0; + + class TestClass { + @memoize() + method(value: string): number { + executionCount++; + return executionCount; + } + } + + const instance1 = new TestClass(); + const instance2 = new TestClass(); + + const result1 = instance1.method('test'); + const result2 = instance2.method('test'); + const result3 = instance1.method('test'); // Should use cache from instance1 + + // Should execute twice (once per instance) + assert.strictEqual(executionCount, 2); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 2); + assert.strictEqual(result3, 1); // Cached from instance1 + }); + + test('should work with getters', () => { + let executionCount = 0; + + class TestClass { + @memoize() + get value(): number { + executionCount++; + return executionCount; + } + } + + const instance = new TestClass(); + + const result1 = instance.value; + const result2 = instance.value; + const result3 = instance.value; + + // Should only execute once + assert.strictEqual(executionCount, 1); + assert.strictEqual(result1, 1); + assert.strictEqual(result2, 1); + assert.strictEqual(result3, 1); + }); + + test('should cache complex return values', () => { + let executionCount = 0; + + class TestClass { + @memoize() + method(value: string): { count: number; value: string } { + executionCount++; + return { count: executionCount, value: value }; + } + } + + const instance = new TestClass(); + + const result1 = instance.method('test'); + const result2 = instance.method('test'); + + // Should only execute once + assert.strictEqual(executionCount, 1); + // Should return the exact same object reference + assert.strictEqual(result1, result2); + assert.strictEqual(result1.count, 1); + }); + + test('should work with async functions', async () => { + let executionCount = 0; + + class TestClass { + @memoize() + async method(value: string): Promise { + executionCount++; + await new Promise(resolve => setTimeout(resolve, 10)); + return executionCount; + } + } + + const instance = new TestClass(); + + // First call creates and caches the promise + const p1 = instance.method('test'); + // Second call should return the same cached promise + const p2 = instance.method('test'); + + // Should be the same promise reference + assert.strictEqual(p1, p2); + + const results = await Promise.all([p1, p2]); + + // Should only execute once + assert.strictEqual(executionCount, 1); + assert.strictEqual(results[0], 1); + assert.strictEqual(results[1], 1); + }); + + test('should NOT cache errors', () => { + let executionCount = 0; + + class TestClass { + @memoize() + method(shouldFail: boolean): number { + executionCount++; + if (shouldFail) { + throw new Error('Test error'); + } + return executionCount; + } + } + + const instance = new TestClass(); + + // First call throws + assert.throws(() => instance.method(true), /Test error/); + assert.strictEqual(executionCount, 1); + + // Second call with same args should execute again (error not cached) + assert.throws(() => instance.method(true), /Test error/); + assert.strictEqual(executionCount, 2); + + // Successful call should cache + const result1 = instance.method(false); + const result2 = instance.method(false); + assert.strictEqual(executionCount, 3); // Only one more execution + assert.strictEqual(result1, result2); + }); + }); +}); diff --git a/src/system/decorators/gate.ts b/src/system/decorators/gate.ts index 1a80d729dc0d2..5158391230040 100644 --- a/src/system/decorators/gate.ts +++ b/src/system/decorators/gate.ts @@ -4,7 +4,7 @@ import { Logger } from '../logger'; import { isPromise } from '../promise'; import { resolveProp } from './resolver'; -export function gate any>(resolver?: (...args: Parameters) => string) { +export function gate any>(getGroupingKey?: (...args: Parameters) => string) { return (_target: any, key: string, descriptor: PropertyDescriptor): void => { // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type let fn: Function | undefined; @@ -18,7 +18,7 @@ export function gate any>(resolver?: (...args: Parame const gateKey = `$gate$${key}`; descriptor.value = function (this: any, ...args: any[]) { - const prop = resolveProp(gateKey, resolver, ...(args as Parameters)); + const prop = resolveProp(gateKey, getGroupingKey, ...(args as Parameters)); if (!Object.prototype.hasOwnProperty.call(this, prop)) { Object.defineProperty(this, prop, { configurable: false, diff --git a/src/system/decorators/sequentialize.ts b/src/system/decorators/sequentialize.ts new file mode 100644 index 0000000000000..ff02fd12899dc --- /dev/null +++ b/src/system/decorators/sequentialize.ts @@ -0,0 +1,116 @@ +import { defaultResolver } from '@env/resolver'; + +interface SequentializeState { + promise: Promise; + waiting?: { + key: string; + promise: Promise; + }; +} + +interface SequentializeOptions any> { + /** + * Optional function to resolve arguments into a deduplication key. + * Consecutive duplicate calls (same deduplication key) that haven't started yet are deduplicated and share the same result. + * If omitted, uses the default resolver which deduplicates based on argument values. + */ + getDedupingKey?: (...args: Parameters) => string; + + /** + * Optional function to resolve arguments into a queue key. + * Calls with the same queue key execute sequentially in that queue. + * Calls with different queue keys execute in parallel (different queues). + * If omitted, all calls share a single queue. + */ + getQueueKey?: (...args: Parameters) => string; +} + +/** + * Method decorator that ensures all calls to the decorated async method are executed sequentially. + * If the method is called multiple times before a previous invocation completes, subsequent calls are queued and executed one after another. + * + * Consecutive duplicate calls (same arguments) that haven't started yet are deduplicated and share the same result. + * + * @param options Optional options object: + * - getQueueKey: Groups calls into parallel queues + * - getDedupingKey: Deduplicates consecutive calls within each queue + * - If omitted: Uses default resolver for deduplication, single queue for all calls + */ +export function sequentialize any>( + options?: SequentializeOptions, +): (target: any, key: string, descriptor: PropertyDescriptor) => void { + const getQueueKey = options?.getQueueKey; + const getDedupingKey = options?.getDedupingKey; + + return (_target: any, key: string, descriptor: PropertyDescriptor) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + let fn: Function | undefined; + if (typeof descriptor.value === 'function') { + fn = descriptor.value; + } else if (typeof descriptor.get === 'function') { + fn = descriptor.get; + } + if (fn === undefined) throw new Error('Not supported'); + + const serializeKey = `$sequentialize$${key}`; + + descriptor.value = function (this: any, ...args: any[]) { + // Compute queue key (if getQueueKey provided, otherwise use default queue) + const queueKey = getQueueKey?.(...(args as Parameters)) ?? ''; + const prop = queueKey ? `${serializeKey}$${queueKey}` : serializeKey; + + if (!Object.prototype.hasOwnProperty.call(this, prop)) { + Object.defineProperty(this, prop, { + configurable: false, + enumerable: false, + writable: true, + value: undefined, + }); + } + + const state: SequentializeState | undefined = this[prop]; + // eslint-disable-next-line no-return-await, @typescript-eslint/no-unsafe-return + const run = async () => await fn.apply(this, args); + + // Compute the dedupe key once + const dedupeKey = getDedupingKey?.(...(args as Parameters)) ?? defaultResolver(...(args as any)); + + // If there's a waiting call, check if we can deduplicate with it and return the same promise as the waiting call + if (state?.waiting != null && state.waiting.key === dedupeKey) return state.waiting.promise; + + // Chain this call after the current promise (or start fresh if no state) + let promise: Promise; + if (state == null) { + // No existing state, start fresh and don't set waiting (it starts immediately) + promise = run(); + this[prop] = { promise: promise }; + } else { + // Chain after existing promise with a single handler for both success and error + const clearWaitingAndRun = () => { + // Clear waiting status when this call starts running + const s = this[prop]; + if (s?.waiting?.promise === promise) { + s.waiting = undefined; + } + return run(); + }; + + promise = state.promise.then(clearWaitingAndRun, clearWaitingAndRun); + + // Update state with this call as the new waiting call + state.promise = promise; + state.waiting = { key: dedupeKey, promise: promise }; + } + + // Cleanup when done + void promise.finally(() => { + const s = this[prop]; + if (s?.promise === promise && s.waiting == null) { + this[prop] = undefined; + } + }); + + return promise; + }; + }; +} diff --git a/src/system/decorators/serialize.ts b/src/system/decorators/serialize.ts deleted file mode 100644 index 0b35bd3006d90..0000000000000 --- a/src/system/decorators/serialize.ts +++ /dev/null @@ -1,37 +0,0 @@ -export function sequentialize(): (target: any, key: string, descriptor: PropertyDescriptor) => void { - return (_target: any, key: string, descriptor: PropertyDescriptor) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - let fn: Function | undefined; - if (typeof descriptor.value === 'function') { - fn = descriptor.value; - } else if (typeof descriptor.get === 'function') { - fn = descriptor.get; - } - if (fn === undefined) throw new Error('Not supported'); - - const serializeKey = `$sequentialize$${key}`; - - descriptor.value = function (this: any, ...args: any[]) { - if (!Object.prototype.hasOwnProperty.call(this, serializeKey)) { - Object.defineProperty(this, serializeKey, { - configurable: false, - enumerable: false, - writable: true, - value: undefined, - }); - } - - let promise: Promise | undefined = this[serializeKey]; - // eslint-disable-next-line no-return-await, @typescript-eslint/no-unsafe-return - const run = async () => await fn.apply(this, args); - if (promise == null) { - promise = run(); - } else { - promise = promise.then(run, run); - } - - this[serializeKey] = promise; - return promise; - }; - }; -} diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 751b60a98b645..af82bb01db3fb 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -21,7 +21,7 @@ import { setContext } from '../system/-webview/context'; import { getViewFocusCommand } from '../system/-webview/vscode/views'; import { getScopedCounter } from '../system/counter'; import { debug, logName } from '../system/decorators/log'; -import { sequentialize } from '../system/decorators/serialize'; +import { sequentialize } from '../system/decorators/sequentialize'; import { serializeIpcData } from '../system/ipcSerialize'; import { getLoggableName, Logger } from '../system/logger'; import { getLogScope, getNewLogScope, setLogScopeExit } from '../system/logger.scope'; From 85ea29c9459a87f206641e7ecaba07e113b3d71f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 30 Oct 2025 00:14:51 -0400 Subject: [PATCH 83/83] Refactors Git ops into dedicated sub-providers - Moves checkout, cherry-pick, fetch, push, pull, rebase, reset to ops sub-provider - Moves paused operation management to pausedOps sub-provider --- src/commands/generateRebase.ts | 4 +- src/commands/ghpr/openOrCreateWorktree.ts | 2 +- src/commands/git/cherry-pick.ts | 6 +- src/commands/git/reset.ts | 2 +- src/env/node/git/localGitProvider.ts | 218 +------- src/env/node/git/sub-providers/branches.ts | 2 +- src/env/node/git/sub-providers/commits.ts | 61 +-- src/env/node/git/sub-providers/operations.ts | 275 ++++++++++ src/env/node/git/sub-providers/patch.ts | 4 +- .../git/sub-providers/pausedOperations.ts | 516 ++++++++++++++++++ src/env/node/git/sub-providers/status.ts | 499 +---------------- src/git/actions/commit.ts | 2 +- src/git/actions/pausedOperation.ts | 4 +- src/git/errors.ts | 147 ++--- src/git/gitProvider.ts | 89 +-- src/git/gitRepositoryService.ts | 55 +- src/git/models/repository.ts | 10 +- src/views/nodes/branchNode.ts | 2 +- src/views/nodes/fileRevisionAsCommitNode.ts | 2 +- src/views/nodes/repositoryNode.ts | 2 +- .../commitDetails/commitDetailsWebview.ts | 2 +- src/webviews/home/homeWebview.ts | 8 +- src/webviews/plus/composer/composerWebview.ts | 2 +- src/webviews/plus/graph/graphWebview.ts | 6 +- 24 files changed, 985 insertions(+), 935 deletions(-) create mode 100644 src/env/node/git/sub-providers/operations.ts create mode 100644 src/env/node/git/sub-providers/pausedOperations.ts diff --git a/src/commands/generateRebase.ts b/src/commands/generateRebase.ts index 67361230bc2a8..36fd998a08732 100644 --- a/src/commands/generateRebase.ts +++ b/src/commands/generateRebase.ts @@ -249,7 +249,7 @@ export class UndoGenerateRebaseCommand extends GlCommandBase { } // Reset hard to the previous HEAD - await svc.reset(args.previousHeadRef.ref, { hard: true }); + await svc.ops?.reset(args.previousHeadRef.ref, { hard: true }); // Apply the generated stash try { @@ -351,7 +351,7 @@ export async function generateRebase( } // reset the current branch to the new shas - await svc.reset(shas[shas.length - 1], { hard: true }); + await svc.ops?.reset(shas[shas.length - 1], { hard: true }); // Capture the new HEAD after reset generatedHeadRef = createReference(shas[shas.length - 1], svc.path, { refType: 'revision' }); diff --git a/src/commands/ghpr/openOrCreateWorktree.ts b/src/commands/ghpr/openOrCreateWorktree.ts index 60b7f97c70c7d..6ab1ee29c660f 100644 --- a/src/commands/ghpr/openOrCreateWorktree.ts +++ b/src/commands/ghpr/openOrCreateWorktree.ts @@ -93,7 +93,7 @@ export class OpenOrCreateWorktreeCommand extends GlCommandBase { if (remote != null) { remoteName = remote.name; // Ensure we have the latest from the remote - await repo.git.fetch({ remote: remote.name }); + await repo.git.ops?.fetch({ remote: remote.name }); } else { remoteName = remoteOwner; addRemote = { name: remoteOwner, url: remoteUrl }; diff --git a/src/commands/git/cherry-pick.ts b/src/commands/git/cherry-pick.ts index 2a52bbeedde1a..9580d7c358026 100644 --- a/src/commands/git/cherry-pick.ts +++ b/src/commands/git/cherry-pick.ts @@ -90,7 +90,7 @@ export class CherryPickGitCommand extends QuickCommand { private async execute(state: CherryPickStepState>) { try { - await state.repo.git.commits.cherryPick?.( + await state.repo.git.ops?.cherryPick?.( state.references.map(c => c.ref), { edit: state.flags.includes('--edit'), @@ -102,10 +102,10 @@ export class CherryPickGitCommand extends QuickCommand { if (ex instanceof CherryPickError && ex.reason === CherryPickErrorReason.EmptyCommit) { let pausedOperation: GitPausedOperationStatus | undefined; try { - pausedOperation = await state.repo.git.status.getPausedOperationStatus?.(); + pausedOperation = await state.repo.git.pausedOps?.getPausedOperationStatus?.(); pausedOperation ??= await state.repo .waitForRepoChange(500) - .then(() => state.repo.git.status.getPausedOperationStatus?.()); + .then(() => state.repo.git.pausedOps?.getPausedOperationStatus?.()); } catch {} const pausedAt = pausedOperation diff --git a/src/commands/git/reset.ts b/src/commands/git/reset.ts index c38c98db240a6..55f26f549e836 100644 --- a/src/commands/git/reset.ts +++ b/src/commands/git/reset.ts @@ -73,7 +73,7 @@ export class ResetGitCommand extends QuickCommand { private async execute(state: ResetStepState) { try { - await state.repo.git.reset( + await state.repo.git.ops?.reset( state.reference.ref, state.flags.includes('--hard') ? { hard: true } diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 060293c01f974..4871ed8359e6c 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -12,14 +12,7 @@ import type { Container } from '../../../container'; import type { Features } from '../../../features'; import { GitCache } from '../../../git/cache'; import { GitErrorHandling } from '../../../git/commandOptions'; -import { - BlameIgnoreRevsFileBadRevisionError, - BlameIgnoreRevsFileError, - FetchError, - PullError, - PushError, - PushErrorReason, -} from '../../../git/errors'; +import { BlameIgnoreRevsFileBadRevisionError, BlameIgnoreRevsFileError } from '../../../git/errors'; import type { GitProvider, GitProviderDescriptor, @@ -37,7 +30,6 @@ import type { GitBlame, GitBlameAuthor, GitBlameLine } from '../../../git/models import type { GitCommit } from '../../../git/models/commit'; import type { GitLineDiff, ParsedGitDiffHunks } from '../../../git/models/diff'; import type { GitLog } from '../../../git/models/log'; -import type { GitBranchReference, GitReference } from '../../../git/models/reference'; import type { GitRemote } from '../../../git/models/remote'; import { RemoteResourceType } from '../../../git/models/remoteResource'; import type { RepositoryChangeEvent } from '../../../git/models/repository'; @@ -45,8 +37,6 @@ import { Repository, RepositoryChange, RepositoryChangeComparisonMode } from '.. import { deletedOrMissing } from '../../../git/models/revision'; import { parseGitBlame } from '../../../git/parsers/blameParser'; import { parseGitFileDiff } from '../../../git/parsers/diffParser'; -import { getBranchNameAndRemote, getBranchTrackingWithoutRemote } from '../../../git/utils/branch.utils'; -import { isBranchReference } from '../../../git/utils/reference.utils'; import { getVisibilityCacheKey } from '../../../git/utils/remote.utils'; import { isUncommitted, isUncommittedStaged, shortenRevision } from '../../../git/utils/revision.utils'; import { @@ -74,7 +64,7 @@ import { equalsIgnoreCase, getDurationMilliseconds } from '../../../system/strin import { compare, fromString } from '../../../system/version'; import type { CachedBlame, CachedDiff, TrackedGitDocument } from '../../../trackers/trackedDocument'; import { GitDocumentState } from '../../../trackers/trackedDocument'; -import type { Git, PushForceOptions } from './git'; +import type { Git } from './git'; import type { GitLocation } from './locator'; import { findGitPath, InvalidGitConfigError, UnableToFindGitError } from './locator'; import { fsExists } from './shell'; @@ -84,7 +74,9 @@ import { ConfigGitSubProvider } from './sub-providers/config'; import { ContributorsGitSubProvider } from './sub-providers/contributors'; import { DiffGitSubProvider, findPathStatusChanged } from './sub-providers/diff'; import { GraphGitSubProvider } from './sub-providers/graph'; +import { OperationsGitSubProvider } from './sub-providers/operations'; import { PatchGitSubProvider } from './sub-providers/patch'; +import { PausedOperationsGitSubProvider } from './sub-providers/pausedOperations'; import { RefsGitSubProvider } from './sub-providers/refs'; import { RemotesGitSubProvider } from './sub-providers/remotes'; import { RevisionGitSubProvider } from './sub-providers/revision'; @@ -977,31 +969,6 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - @log() - async checkout( - repoPath: string, - ref: string, - options?: { createBranch?: string } | { path?: string }, - ): Promise { - const scope = getLogScope(); - - try { - await this.git.checkout(repoPath, ref, options); - this.container.events.fire('git:cache:reset', { repoPath: repoPath, types: ['branches', 'status'] }); - } catch (ex) { - const msg: string = ex?.toString() ?? ''; - if (/overwritten by checkout/i.test(msg)) { - void showGenericErrorMessage( - `Unable to checkout '${ref}'. Please commit or stash your changes before switching branches`, - ); - return; - } - - Logger.error(ex, scope); - void showGenericErrorMessage(`Unable to checkout '${ref}'`); - } - } - @log() async clone(url: string, parentPath: string): Promise { const scope = getLogScope(); @@ -1038,158 +1005,6 @@ export class LocalGitProvider implements GitProvider, Disposable { return [...paths.values()]; } - @gate() - @log() - async fetch( - repoPath: string, - options?: { all?: boolean; branch?: GitBranchReference; prune?: boolean; pull?: boolean; remote?: string }, - ): Promise { - const scope = getLogScope(); - - const { branch, ...opts } = options ?? {}; - try { - if (isBranchReference(branch)) { - const [branchName, remoteName] = getBranchNameAndRemote(branch); - if (remoteName == null) return undefined; - - await this.git.fetch(repoPath, { - branch: branchName, - remote: remoteName, - upstream: getBranchTrackingWithoutRemote(branch)!, - pull: options?.pull, - }); - } else { - await this.git.fetch(repoPath, opts); - } - - this.container.events.fire('git:cache:reset', { repoPath: repoPath }); - } catch (ex) { - Logger.error(ex, scope); - if (!FetchError.is(ex)) throw ex; - - void window.showErrorMessage(ex.message); - } - } - - @gate() - @log() - async push( - repoPath: string, - options?: { reference?: GitReference; force?: boolean; publish?: { remote: string } }, - ): Promise { - const scope = getLogScope(); - - let branchName: string; - let remoteName: string | undefined; - let upstreamName: string | undefined; - let setUpstream: - | { - branch: string; - remote: string; - remoteBranch: string; - } - | undefined; - - if (isBranchReference(options?.reference)) { - if (options.publish != null) { - branchName = options.reference.name; - remoteName = options.publish.remote; - } else { - [branchName, remoteName] = getBranchNameAndRemote(options.reference); - } - upstreamName = getBranchTrackingWithoutRemote(options.reference); - } else { - const branch = await this.branches.getBranch(repoPath); - if (branch == null) return; - - branchName = - options?.reference != null - ? `${options.reference.ref}:${ - options?.publish != null ? 'refs/heads/' : '' - }${branch.getNameWithoutRemote()}` - : branch.name; - remoteName = branch.getRemoteName() ?? options?.publish?.remote; - upstreamName = options?.reference == null && options?.publish != null ? branch.name : undefined; - - // Git can't setup upstream tracking when publishing a new branch to a specific commit, so we'll need to do it after the push - if (options?.publish?.remote != null && options?.reference != null) { - setUpstream = { - branch: branch.getNameWithoutRemote(), - remote: remoteName!, - remoteBranch: branch.getNameWithoutRemote(), - }; - } - } - - if (options?.publish == null && remoteName == null && upstreamName == null) { - debugger; - throw new PushError(PushErrorReason.Other); - } - - let forceOpts: PushForceOptions | undefined; - if (options?.force) { - const withLease = configuration.getCore('git.useForcePushWithLease') ?? true; - if (withLease) { - forceOpts = { - withLease: withLease, - ifIncludes: configuration.getCore('git.useForcePushIfIncludes') ?? true, - }; - } else { - forceOpts = { - withLease: withLease, - }; - } - } - - try { - await this.git.push(repoPath, { - branch: branchName, - remote: remoteName, - upstream: upstreamName, - force: forceOpts, - publish: options?.publish != null, - }); - - // Since Git can't setup upstream tracking when publishing a new branch to a specific commit, do it now - if (setUpstream != null) { - await this.git.exec( - { cwd: repoPath }, - 'branch', - '--set-upstream-to', - `${setUpstream.remote}/${setUpstream.remoteBranch}`, - setUpstream.branch, - ); - } - - this.container.events.fire('git:cache:reset', { repoPath: repoPath }); - } catch (ex) { - Logger.error(ex, scope); - if (!PushError.is(ex)) throw ex; - - void window.showErrorMessage(ex.message); - } - } - - @gate() - @log() - async pull(repoPath: string, options?: { rebase?: boolean; tags?: boolean }): Promise { - const scope = getLogScope(); - - try { - await this.git.pull(repoPath, { - rebase: options?.rebase, - tags: options?.tags, - }); - - this.container.events.fire('git:cache:reset', { repoPath: repoPath }); - } catch (ex) { - Logger.error(ex, scope); - if (!PullError.is(ex)) throw ex; - - void window.showErrorMessage(ex.message); - } - } - private readonly toCanonicalMap = new Map(); private readonly fromCanonicalMap = new Map(); protected readonly unsafePaths = new Set(); @@ -2065,11 +1880,6 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - @log() - async reset(repoPath: string, ref: string, options?: { hard?: boolean } | { soft?: boolean }): Promise { - await this.git.reset(repoPath, [], { ...options, ref: ref }); - } - @log({ args: { 2: false } }) async runGitCommandViaTerminal( repoPath: string, @@ -2118,11 +1928,31 @@ export class LocalGitProvider implements GitProvider, Disposable { return (this._graph ??= new GraphGitSubProvider(this.container, this.git, this._cache, this)); } + private _operations: OperationsGitSubProvider | undefined; + get ops(): OperationsGitSubProvider { + return (this._operations ??= new OperationsGitSubProvider( + this.container, + this.git, + this._cache, + this as unknown as LocalGitProviderInternal, + )); + } + private _patch: PatchGitSubProvider | undefined; get patch(): PatchGitSubProvider | undefined { return (this._patch ??= new PatchGitSubProvider(this.container, this.git, this)); } + private _pausedOperations: PausedOperationsGitSubProvider | undefined; + get pausedOps(): PausedOperationsGitSubProvider { + return (this._pausedOperations ??= new PausedOperationsGitSubProvider( + this.container, + this.git, + this._cache, + this as unknown as LocalGitProviderInternal, + )); + } + private _refs: RefsGitSubProvider | undefined; get refs(): RefsGitSubProvider { return (this._refs ??= new RefsGitSubProvider(this.container, this.git, this._cache, this)); diff --git a/src/env/node/git/sub-providers/branches.ts b/src/env/node/git/sub-providers/branches.ts index 8a74fa0c0086e..3e46c3785050b 100644 --- a/src/env/node/git/sub-providers/branches.ts +++ b/src/env/node/git/sub-providers/branches.ts @@ -88,7 +88,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider { const [pausedOpStatusResult, committerDateResult, defaultWorktreePathResult] = await Promise.allSettled([ isDetachedHead(ref.name) - ? this.provider.status?.getPausedOperationStatus(repoPath, cancellation) + ? this.provider.pausedOps.getPausedOperationStatus(repoPath, cancellation) : undefined, this.git .exec( diff --git a/src/env/node/git/sub-providers/commits.ts b/src/env/node/git/sub-providers/commits.ts index b569965d8eb21..e248bb578ada2 100644 --- a/src/env/node/git/sub-providers/commits.ts +++ b/src/env/node/git/sub-providers/commits.ts @@ -6,7 +6,6 @@ import { CancellationError, isCancellationError } from '../../../../errors'; import type { GitCache } from '../../../../git/cache'; import type { GitCommandOptions } from '../../../../git/commandOptions'; import { GitErrorHandling } from '../../../../git/commandOptions'; -import { CherryPickError, CherryPickErrorReason } from '../../../../git/errors'; import type { GitCommitsSubProvider, GitLogForPathOptions, @@ -37,7 +36,6 @@ import type { } from '../../../../git/parsers/logParser'; import { getCommitsLogParser, - getShaAndDatesLogParser, getShaAndFilesAndStatsLogParser, getShaLogParser, } from '../../../../git/parsers/logParser'; @@ -58,7 +56,7 @@ import { maybeStopWatch } from '../../../../system/stopwatch'; import type { CachedLog, TrackedGitDocument } from '../../../../trackers/trackedDocument'; import { GitDocumentState } from '../../../../trackers/trackedDocument'; import type { Git, GitResult } from '../git'; -import { gitConfigsLog, gitConfigsLogWithFiles, GitErrors } from '../git'; +import { gitConfigsLog, gitConfigsLogWithFiles } from '../git'; import type { LocalGitProviderInternal } from '../localGitProvider'; import { convertStashesToStdin } from './stash'; @@ -77,63 +75,6 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider { return configuration.get('advanced.caching.enabled'); } - @log() - async cherryPick( - repoPath: string, - revs: string[], - options?: { edit?: boolean; noCommit?: boolean }, - ): Promise { - const args = ['cherry-pick']; - if (options?.edit) { - args.push('-e'); - } - if (options?.noCommit) { - args.push('-n'); - } - - if (revs.length > 1) { - const parser = getShaAndDatesLogParser(); - // Ensure the revs are in reverse committer date order - const result = await this.git.exec( - { cwd: repoPath, stdin: join(revs, '\n') }, - 'log', - '--no-walk', - '--stdin', - ...parser.arguments, - '--', - ); - const commits = [...parser.parse(result.stdout)].sort( - (c1, c2) => - Number(c1.committerDate) - Number(c2.committerDate) || - Number(c1.authorDate) - Number(c2.authorDate), - ); - revs = commits.map(c => c.sha); - } - - args.push(...revs); - - try { - await this.git.exec({ cwd: repoPath, errors: GitErrorHandling.Throw }, ...args); - } catch (ex) { - const msg: string = ex?.toString() ?? ''; - - let reason: CherryPickErrorReason = CherryPickErrorReason.Other; - if ( - GitErrors.changesWouldBeOverwritten.test(msg) || - GitErrors.changesWouldBeOverwritten.test(ex.stderr ?? '') - ) { - reason = CherryPickErrorReason.AbortedWouldOverwrite; - } else if (GitErrors.conflict.test(msg) || GitErrors.conflict.test(ex.stdout ?? '')) { - reason = CherryPickErrorReason.Conflicts; - } else if (GitErrors.emptyPreviousCherryPick.test(msg)) { - reason = CherryPickErrorReason.EmptyCommit; - } - - debugger; - throw new CherryPickError(reason, ex, revs); - } - } - @log() async getCommit(repoPath: string, rev: string, cancellation?: CancellationToken): Promise { if (isUncommitted(rev, true)) { diff --git a/src/env/node/git/sub-providers/operations.ts b/src/env/node/git/sub-providers/operations.ts new file mode 100644 index 0000000000000..259b423620c37 --- /dev/null +++ b/src/env/node/git/sub-providers/operations.ts @@ -0,0 +1,275 @@ +import { window } from 'vscode'; +import type { Container } from '../../../../container'; +import type { GitCache } from '../../../../git/cache'; +import { GitErrorHandling } from '../../../../git/commandOptions'; +import { + CherryPickError, + CherryPickErrorReason, + FetchError, + PullError, + PushError, + PushErrorReason, +} from '../../../../git/errors'; +import type { GitOperationsSubProvider } from '../../../../git/gitProvider'; +import type { GitBranchReference, GitReference } from '../../../../git/models/reference'; +import { getShaAndDatesLogParser } from '../../../../git/parsers/logParser'; +import { getBranchNameAndRemote, getBranchTrackingWithoutRemote } from '../../../../git/utils/branch.utils'; +import { isBranchReference } from '../../../../git/utils/reference.utils'; +import { showGenericErrorMessage } from '../../../../messages'; +import { configuration } from '../../../../system/-webview/configuration'; +import { log } from '../../../../system/decorators/log'; +import { sequentialize } from '../../../../system/decorators/sequentialize'; +import { join } from '../../../../system/iterable'; +import { Logger } from '../../../../system/logger'; +import { getLogScope } from '../../../../system/logger.scope'; +import type { Git, PushForceOptions } from '../git'; +import { GitErrors } from '../git'; +import type { LocalGitProviderInternal } from '../localGitProvider'; + +export class OperationsGitSubProvider implements GitOperationsSubProvider { + constructor( + private readonly container: Container, + private readonly git: Git, + private readonly cache: GitCache, + private readonly provider: LocalGitProviderInternal, + ) {} + + @log() + async checkout( + repoPath: string, + ref: string, + options?: { createBranch?: string } | { path?: string }, + ): Promise { + const scope = getLogScope(); + + try { + await this.git.checkout(repoPath, ref, options); + this.container.events.fire('git:cache:reset', { repoPath: repoPath, types: ['branches', 'status'] }); + } catch (ex) { + const msg: string = ex?.toString() ?? ''; + if (/overwritten by checkout/i.test(msg)) { + void showGenericErrorMessage( + `Unable to checkout '${ref}'. Please commit or stash your changes before switching branches`, + ); + return; + } + + Logger.error(ex, scope); + void showGenericErrorMessage(`Unable to checkout '${ref}'`); + } + } + + @log() + async cherryPick( + repoPath: string, + revs: string[], + options?: { edit?: boolean; noCommit?: boolean }, + ): Promise { + const args = ['cherry-pick']; + if (options?.edit) { + args.push('-e'); + } + if (options?.noCommit) { + args.push('-n'); + } + + if (revs.length > 1) { + const parser = getShaAndDatesLogParser(); + // Ensure the revs are in reverse committer date order + const result = await this.git.exec( + { cwd: repoPath, stdin: join(revs, '\n') }, + 'log', + '--no-walk', + '--stdin', + ...parser.arguments, + '--', + ); + const commits = [...parser.parse(result.stdout)].sort( + (c1, c2) => + Number(c1.committerDate) - Number(c2.committerDate) || + Number(c1.authorDate) - Number(c2.authorDate), + ); + revs = commits.map(c => c.sha); + } + + args.push(...revs); + + try { + await this.git.exec({ cwd: repoPath, errors: GitErrorHandling.Throw }, ...args); + } catch (ex) { + const msg: string = ex?.toString() ?? ''; + + let reason: CherryPickErrorReason = CherryPickErrorReason.Other; + if ( + GitErrors.changesWouldBeOverwritten.test(msg) || + GitErrors.changesWouldBeOverwritten.test(ex.stderr ?? '') + ) { + reason = CherryPickErrorReason.AbortedWouldOverwrite; + } else if (GitErrors.conflict.test(msg) || GitErrors.conflict.test(ex.stdout ?? '')) { + reason = CherryPickErrorReason.Conflicts; + } else if (GitErrors.emptyPreviousCherryPick.test(msg)) { + reason = CherryPickErrorReason.EmptyCommit; + } + + debugger; + throw new CherryPickError(reason, ex, revs); + } + } + + @sequentialize({ getQueueKey: rp => rp }) + @log() + async fetch( + repoPath: string, + options?: { all?: boolean; branch?: GitBranchReference; prune?: boolean; pull?: boolean; remote?: string }, + ): Promise { + const scope = getLogScope(); + + const { branch, ...opts } = options ?? {}; + try { + if (isBranchReference(branch)) { + const [branchName, remoteName] = getBranchNameAndRemote(branch); + if (remoteName == null) return undefined; + + await this.git.fetch(repoPath, { + branch: branchName, + remote: remoteName, + upstream: getBranchTrackingWithoutRemote(branch)!, + pull: options?.pull, + }); + } else { + await this.git.fetch(repoPath, opts); + } + + this.container.events.fire('git:cache:reset', { repoPath: repoPath }); + } catch (ex) { + Logger.error(ex, scope); + if (!FetchError.is(ex)) throw ex; + + void window.showErrorMessage(ex.message); + } + } + + @sequentialize({ getQueueKey: rp => rp }) + @log() + async pull(repoPath: string, options?: { rebase?: boolean; tags?: boolean }): Promise { + const scope = getLogScope(); + + try { + await this.git.pull(repoPath, { + rebase: options?.rebase, + tags: options?.tags, + }); + + this.container.events.fire('git:cache:reset', { repoPath: repoPath }); + } catch (ex) { + Logger.error(ex, scope); + if (!PullError.is(ex)) throw ex; + + void window.showErrorMessage(ex.message); + } + } + + @sequentialize({ getQueueKey: rp => rp }) + @log() + async push( + repoPath: string, + options?: { reference?: GitReference; force?: boolean; publish?: { remote: string } }, + ): Promise { + const scope = getLogScope(); + + let branchName: string; + let remoteName: string | undefined; + let upstreamName: string | undefined; + let setUpstream: + | { + branch: string; + remote: string; + remoteBranch: string; + } + | undefined; + + if (isBranchReference(options?.reference)) { + if (options.publish != null) { + branchName = options.reference.name; + remoteName = options.publish.remote; + } else { + [branchName, remoteName] = getBranchNameAndRemote(options.reference); + } + upstreamName = getBranchTrackingWithoutRemote(options.reference); + } else { + const branch = await this.provider.branches.getBranch(repoPath); + if (branch == null) return; + + branchName = + options?.reference != null + ? `${options.reference.ref}:${ + options?.publish != null ? 'refs/heads/' : '' + }${branch.getNameWithoutRemote()}` + : branch.name; + remoteName = branch.getRemoteName() ?? options?.publish?.remote; + upstreamName = options?.reference == null && options?.publish != null ? branch.name : undefined; + + // Git can't setup upstream tracking when publishing a new branch to a specific commit, so we'll need to do it after the push + if (options?.publish?.remote != null && options?.reference != null) { + setUpstream = { + branch: branch.getNameWithoutRemote(), + remote: remoteName!, + remoteBranch: branch.getNameWithoutRemote(), + }; + } + } + + if (options?.publish == null && remoteName == null && upstreamName == null) { + debugger; + throw new PushError(PushErrorReason.Other); + } + + let forceOpts: PushForceOptions | undefined; + if (options?.force) { + const withLease = configuration.getCore('git.useForcePushWithLease') ?? true; + if (withLease) { + forceOpts = { + withLease: withLease, + ifIncludes: configuration.getCore('git.useForcePushIfIncludes') ?? true, + }; + } else { + forceOpts = { + withLease: withLease, + }; + } + } + + try { + await this.git.push(repoPath, { + branch: branchName, + remote: remoteName, + upstream: upstreamName, + force: forceOpts, + publish: options?.publish != null, + }); + + // Since Git can't setup upstream tracking when publishing a new branch to a specific commit, do it now + if (setUpstream != null) { + await this.git.exec( + { cwd: repoPath }, + 'branch', + '--set-upstream-to', + `${setUpstream.remote}/${setUpstream.remoteBranch}`, + setUpstream.branch, + ); + } + + this.container.events.fire('git:cache:reset', { repoPath: repoPath }); + } catch (ex) { + Logger.error(ex, scope); + if (!PushError.is(ex)) throw ex; + + void window.showErrorMessage(ex.message); + } + } + + @log() + async reset(repoPath: string, ref: string, options?: { hard?: boolean } | { soft?: boolean }): Promise { + await this.git.reset(repoPath, [], { ...options, ref: ref }); + } +} diff --git a/src/env/node/git/sub-providers/patch.ts b/src/env/node/git/sub-providers/patch.ts index 4578a05af6acc..f8e062d2a6fe2 100644 --- a/src/env/node/git/sub-providers/patch.ts +++ b/src/env/node/git/sub-providers/patch.ts @@ -122,14 +122,14 @@ export class PatchGitSubProvider implements GitPatchSubProvider { if (options?.branchName != null && currentBranch?.name !== options.branchName) { const checkoutRef = shouldCreate ? (currentBranch?.ref ?? 'HEAD') : options.branchName; - await this.provider.checkout(targetPath, checkoutRef, { + await this.provider.ops.checkout(targetPath, checkoutRef, { createBranch: shouldCreate ? options.branchName : undefined, }); } // Apply the patch using a cherry pick without committing try { - await this.provider.commits.cherryPick(targetPath, [rev], { noCommit: true }); + await this.provider.ops.cherryPick(targetPath, [rev], { noCommit: true }); } catch (ex) { Logger.error(ex, scope); if (ex instanceof CherryPickError) { diff --git a/src/env/node/git/sub-providers/pausedOperations.ts b/src/env/node/git/sub-providers/pausedOperations.ts new file mode 100644 index 0000000000000..909026b85433a --- /dev/null +++ b/src/env/node/git/sub-providers/pausedOperations.ts @@ -0,0 +1,516 @@ +import { readdir } from 'fs'; +import type { CancellationToken } from 'vscode'; +import type { Container } from '../../../../container'; +import { CancellationError } from '../../../../errors'; +import type { GitCache } from '../../../../git/cache'; +import { GitErrorHandling } from '../../../../git/commandOptions'; +import { + PausedOperationAbortError, + PausedOperationAbortErrorReason, + PausedOperationContinueError, + PausedOperationContinueErrorReason, +} from '../../../../git/errors'; +import type { GitPausedOperationsSubProvider } from '../../../../git/gitProvider'; +import type { + GitCherryPickStatus, + GitMergeStatus, + GitPausedOperationStatus, + GitRebaseStatus, + GitRevertStatus, +} from '../../../../git/models/pausedOperationStatus'; +import type { GitBranchReference, GitTagReference } from '../../../../git/models/reference'; +import { createReference } from '../../../../git/utils/reference.utils'; +import { gate } from '../../../../system/decorators/gate'; +import { log } from '../../../../system/decorators/log'; +import { Logger } from '../../../../system/logger'; +import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; +import { getSettledValue } from '../../../../system/promise'; +import type { Git } from '../git'; +import { GitErrors } from '../git'; +import type { LocalGitProviderInternal } from '../localGitProvider'; + +type Operation = 'cherry-pick' | 'merge' | 'rebase-apply' | 'rebase-merge' | 'revert'; + +const orderedOperations: Operation[] = ['rebase-apply', 'rebase-merge', 'merge', 'cherry-pick', 'revert']; + +export class PausedOperationsGitSubProvider implements GitPausedOperationsSubProvider { + constructor( + private readonly container: Container, + private readonly git: Git, + private readonly cache: GitCache, + private readonly provider: LocalGitProviderInternal, + ) {} + + @log() + async getPausedOperationStatus( + repoPath: string, + cancellation?: CancellationToken, + ): Promise { + const scope = getLogScope(); + + const status = this.cache.pausedOperationStatus?.getOrCreate(repoPath, async _cancellable => { + const gitDir = await this.provider.config.getGitDir(repoPath); + + const operations = await new Promise>((resolve, _) => { + readdir(gitDir.uri.fsPath, { withFileTypes: true }, (err, entries) => { + const operations = new Set(); + if (err != null) { + resolve(operations); + return; + } + + if (entries.length === 0) { + resolve(operations); + return; + } + + let entry; + for (entry of entries) { + if (entry.isFile()) { + switch (entry.name) { + case 'CHERRY_PICK_HEAD': + operations.add('cherry-pick'); + break; + case 'MERGE_HEAD': + operations.add('merge'); + break; + case 'REVERT_HEAD': + operations.add('revert'); + break; + } + } else if (entry.isDirectory()) { + switch (entry.name) { + case 'rebase-apply': + operations.add('rebase-apply'); + break; + case 'rebase-merge': + operations.add('rebase-merge'); + break; + } + } + } + + resolve(operations); + }); + }); + + if (!operations.size) return undefined; + if (cancellation?.isCancellationRequested) throw new CancellationError(); + + const sortedOperations = [...operations].sort( + (a, b) => orderedOperations.indexOf(a) - orderedOperations.indexOf(b), + ); + Logger.log(`Detected paused operations: ${sortedOperations.join(', ')}`); + + const operation = sortedOperations[0]; + switch (operation) { + case 'cherry-pick': { + const result = await this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'rev-parse', + '--quiet', + '--verify', + 'CHERRY_PICK_HEAD', + ); + if (result.cancelled || cancellation?.isCancellationRequested) { + throw new CancellationError(); + } + + const cherryPickHead = result.stdout.trim(); + if (!cherryPickHead) { + setLogScopeExit(scope, 'No CHERRY_PICK_HEAD found'); + return undefined; + } + + const current = (await this.provider.branches.getCurrentBranchReference(repoPath, cancellation))!; + + return { + type: 'cherry-pick', + repoPath: repoPath, + // TODO: Validate that these are correct + HEAD: createReference(cherryPickHead, repoPath, { refType: 'revision' }), + current: current, + incoming: createReference(cherryPickHead, repoPath, { refType: 'revision' }), + } satisfies GitCherryPickStatus; + } + case 'merge': { + const result = await this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'rev-parse', + '--quiet', + '--verify', + 'MERGE_HEAD', + ); + if (result.cancelled || cancellation?.isCancellationRequested) { + throw new CancellationError(); + } + + const mergeHead = result.stdout.trim(); + if (!mergeHead) { + setLogScopeExit(scope, 'No MERGE_HEAD found'); + return undefined; + } + + const [branchResult, mergeBaseResult, possibleSourceBranchesResult] = await Promise.allSettled([ + this.provider.branches.getCurrentBranchReference(repoPath, cancellation), + this.provider.refs.getMergeBase(repoPath, 'MERGE_HEAD', 'HEAD', undefined, cancellation), + this.provider.branches.getBranchesWithCommits( + repoPath, + ['MERGE_HEAD'], + undefined, + { all: true, mode: 'pointsAt' }, + cancellation, + ), + ]); + + if (cancellation?.isCancellationRequested) throw new CancellationError(); + + const current = getSettledValue(branchResult)!; + const mergeBase = getSettledValue(mergeBaseResult); + const possibleSourceBranches = getSettledValue(possibleSourceBranchesResult); + + return { + type: 'merge', + repoPath: repoPath, + mergeBase: mergeBase, + HEAD: createReference(mergeHead, repoPath, { refType: 'revision' }), + current: current, + incoming: + possibleSourceBranches?.length === 1 + ? createReference(possibleSourceBranches[0], repoPath, { + refType: 'branch', + name: possibleSourceBranches[0], + remote: false, + }) + : createReference(mergeHead, repoPath, { refType: 'revision' }), + } satisfies GitMergeStatus; + } + case 'revert': { + const result = await this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'rev-parse', + '--quiet', + '--verify', + 'REVERT_HEAD', + ); + if (result.cancelled || cancellation?.isCancellationRequested) { + throw new CancellationError(); + } + + const revertHead = result.stdout.trim(); + if (!revertHead) { + setLogScopeExit(scope, 'No REVERT_HEAD found'); + return undefined; + } + + const current = (await this.provider.branches.getCurrentBranchReference(repoPath, cancellation))!; + + return { + type: 'revert', + repoPath: repoPath, + HEAD: createReference(revertHead, repoPath, { refType: 'revision' }), + current: current, + incoming: createReference(revertHead, repoPath, { refType: 'revision' }), + } satisfies GitRevertStatus; + } + case 'rebase-apply': + case 'rebase-merge': { + let branch = await this.git.readDotGitFile(gitDir, [operation, 'head-name']); + if (!branch) { + setLogScopeExit(scope, `No '${operation}/head-name' found`); + return undefined; + } + + const [ + rebaseHeadResult, + origHeadResult, + ontoResult, + stepsNumberResult, + stepsTotalResult, + stepsMessageResult, + ] = await Promise.allSettled([ + this.git.exec( + { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, + 'rev-parse', + '--quiet', + '--verify', + 'REBASE_HEAD', + ), + this.git.readDotGitFile(gitDir, [operation, 'orig-head']), + this.git.readDotGitFile(gitDir, [operation, 'onto']), + this.git.readDotGitFile(gitDir, [operation, 'msgnum'], { numeric: true }), + this.git.readDotGitFile(gitDir, [operation, 'end'], { numeric: true }), + this.git + .readDotGitFile(gitDir, [operation, 'message'], { throw: true }) + .catch(() => this.git.readDotGitFile(gitDir, [operation, 'message-squashed'])), + ]); + + if (cancellation?.isCancellationRequested) throw new CancellationError(); + + const origHead = getSettledValue(origHeadResult); + const onto = getSettledValue(ontoResult); + if (origHead == null || onto == null) { + setLogScopeExit(scope, `Neither '${operation}/orig-head' nor '${operation}/onto' found`); + return undefined; + } + + const rebaseHead = getSettledValue(rebaseHeadResult)?.stdout.trim(); + + if (branch.startsWith('refs/heads/')) { + branch = branch.substring(11).trim(); + } + + const [mergeBaseResult, branchTipsResult, tagTipsResult] = await Promise.allSettled([ + rebaseHead != null + ? this.provider.refs.getMergeBase(repoPath, rebaseHead, 'HEAD', undefined, cancellation) + : this.provider.refs.getMergeBase(repoPath, onto, origHead, undefined, cancellation), + this.provider.branches.getBranchesWithCommits( + repoPath, + [onto], + undefined, + { + all: true, + mode: 'pointsAt', + }, + cancellation, + ), + this.provider.tags.getTagsWithCommit(repoPath, onto, { mode: 'pointsAt' }, cancellation), + ]); + + if (cancellation?.isCancellationRequested) throw new CancellationError(); + + const mergeBase = getSettledValue(mergeBaseResult); + const branchTips = getSettledValue(branchTipsResult); + const tagTips = getSettledValue(tagTipsResult); + + let ontoRef: GitBranchReference | GitTagReference | undefined; + if (branchTips != null) { + for (const ref of branchTips) { + if (ref.startsWith('(no branch, rebasing')) continue; + + ontoRef = createReference(ref, repoPath, { + refType: 'branch', + name: ref, + remote: false, + }); + break; + } + } + if (ontoRef == null && tagTips != null) { + for (const ref of tagTips) { + if (ref.startsWith('(no branch, rebasing')) continue; + + ontoRef = createReference(ref, repoPath, { + refType: 'tag', + name: ref, + }); + break; + } + } + + return { + type: 'rebase', + repoPath: repoPath, + mergeBase: mergeBase, + HEAD: createReference(rebaseHead ?? origHead, repoPath, { refType: 'revision' }), + onto: createReference(onto, repoPath, { refType: 'revision' }), + current: ontoRef, + incoming: createReference(branch, repoPath, { + refType: 'branch', + name: branch, + remote: false, + }), + steps: { + current: { + number: getSettledValue(stepsNumberResult) ?? 0, + commit: + rebaseHead != null + ? createReference(rebaseHead, repoPath, { + refType: 'revision', + message: getSettledValue(stepsMessageResult), + }) + : undefined, + }, + total: getSettledValue(stepsTotalResult) ?? 0, + }, + } satisfies GitRebaseStatus; + } + } + }); + + return status; + } + + @gate((rp, o) => `${rp ?? ''}:${o?.quit ?? false}`) + @log() + async abortPausedOperation(repoPath: string, options?: { quit?: boolean }): Promise { + const status = await this.getPausedOperationStatus(repoPath); + if (status == null) return; + + try { + switch (status.type) { + case 'cherry-pick': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'cherry-pick', + options?.quit ? '--quit' : '--abort', + ); + break; + + case 'merge': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'merge', + options?.quit ? '--quit' : '--abort', + ); + break; + + case 'rebase': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'rebase', + options?.quit ? '--quit' : '--abort', + ); + break; + + case 'revert': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'revert', + options?.quit ? '--quit' : '--abort', + ); + break; + } + } catch (ex) { + debugger; + Logger.error(ex); + const msg: string = ex?.toString() ?? ''; + if (GitErrors.noPausedOperation.test(msg)) { + throw new PausedOperationAbortError( + PausedOperationAbortErrorReason.NothingToAbort, + status.type, + `Cannot abort as there is no ${status.type} operation in progress`, + ex, + ); + } + + throw new PausedOperationAbortError(undefined, status.type, `Cannot abort ${status.type}; ${msg}`, ex); + } + } + + @gate((rp, o) => `${rp ?? ''}:${o?.skip ?? false}`) + @log() + async continuePausedOperation(repoPath: string, options?: { skip?: boolean }): Promise { + const status = await this.getPausedOperationStatus(repoPath); + if (status == null) return; + + try { + switch (status.type) { + case 'cherry-pick': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'cherry-pick', + options?.skip ? '--skip' : '--continue', + ); + break; + + case 'merge': + if (options?.skip) throw new Error('Skipping a merge is not supported'); + await this.git.exec({ cwd: repoPath, errors: GitErrorHandling.Throw }, 'merge', '--continue'); + break; + + case 'rebase': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'rebase', + options?.skip ? '--skip' : '--continue', + ); + break; + + case 'revert': + await this.git.exec( + { cwd: repoPath, errors: GitErrorHandling.Throw }, + 'revert', + options?.skip ? '--skip' : '--abort', + ); + break; + } + } catch (ex) { + debugger; + Logger.error(ex); + + const msg: string = ex?.toString() ?? ''; + if (GitErrors.emptyPreviousCherryPick.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.EmptyCommit, + status, + `Cannot continue ${status.type} as the previous cherry-pick is empty`, + ex, + ); + } + + if (GitErrors.noPausedOperation.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.NothingToContinue, + status, + `Cannot ${options?.skip ? 'skip' : 'continue'} as there is no ${status.type} operation in progress`, + ex, + ); + } + + if (GitErrors.uncommittedChanges.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.UncommittedChanges, + status, + `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are uncommitted changes`, + ex, + ); + } + + if (GitErrors.unmergedFiles.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.UnmergedFiles, + status, + `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unmerged files`, + ex, + ); + } + + if (GitErrors.unresolvedConflicts.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.UnresolvedConflicts, + status, + `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unresolved conflicts`, + ex, + ); + } + + if (GitErrors.unstagedChanges.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.UnstagedChanges, + status, + `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unstaged changes`, + ex, + ); + } + + if (GitErrors.changesWouldBeOverwritten.test(msg)) { + throw new PausedOperationContinueError( + PausedOperationContinueErrorReason.WouldOverwrite, + status, + `Cannot ${ + options?.skip ? 'skip' : `continue ${status.type}` + } as local changes would be overwritten`, + ex, + ); + } + + throw new PausedOperationContinueError( + undefined, + status, + `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`}; ${msg}`, + ex, + ); + } + } +} diff --git a/src/env/node/git/sub-providers/status.ts b/src/env/node/git/sub-providers/status.ts index 158e699185d7d..074455a30c620 100644 --- a/src/env/node/git/sub-providers/status.ts +++ b/src/env/node/git/sub-providers/status.ts @@ -1,32 +1,16 @@ -import { readdir } from 'fs'; import type { CancellationToken, Uri } from 'vscode'; import type { Container } from '../../../../container'; -import { CancellationError, isCancellationError } from '../../../../errors'; +import { isCancellationError } from '../../../../errors'; import type { GitCache } from '../../../../git/cache'; import { GitErrorHandling } from '../../../../git/commandOptions'; -import { - PausedOperationAbortError, - PausedOperationAbortErrorReason, - PausedOperationContinueError, - PausedOperationContinueErrorReason, -} from '../../../../git/errors'; import type { GitStatusSubProvider, GitWorkingChangesState } from '../../../../git/gitProvider'; import type { GitConflictFile } from '../../../../git/models'; import type { GitFile } from '../../../../git/models/file'; import { GitFileWorkingTreeStatus } from '../../../../git/models/fileStatus'; -import type { - GitCherryPickStatus, - GitMergeStatus, - GitPausedOperationStatus, - GitRebaseStatus, - GitRevertStatus, -} from '../../../../git/models/pausedOperationStatus'; -import type { GitBranchReference, GitTagReference } from '../../../../git/models/reference'; import { GitStatus } from '../../../../git/models/status'; import type { GitStatusFile } from '../../../../git/models/statusFile'; import { parseGitConflictFiles } from '../../../../git/parsers/indexParser'; import { parseGitStatus } from '../../../../git/parsers/statusParser'; -import { createReference } from '../../../../git/utils/reference.utils'; import { configuration } from '../../../../system/-webview/configuration'; import { splitPath } from '../../../../system/-webview/path'; import { gate } from '../../../../system/decorators/gate'; @@ -34,16 +18,10 @@ import { log } from '../../../../system/decorators/log'; import { Logger } from '../../../../system/logger'; import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; import { stripFolderGlob } from '../../../../system/path'; -import { getSettledValue } from '../../../../system/promise'; import { iterateByDelimiter } from '../../../../system/string'; import type { Git } from '../git'; -import { GitErrors } from '../git'; import type { LocalGitProvider } from '../localGitProvider'; -type Operation = 'cherry-pick' | 'merge' | 'rebase-apply' | 'rebase-merge' | 'revert'; - -const orderedOperations: Operation[] = ['rebase-apply', 'rebase-merge', 'merge', 'cherry-pick', 'revert']; - export class StatusGitSubProvider implements GitStatusSubProvider { constructor( private readonly container: Container, @@ -52,479 +30,6 @@ export class StatusGitSubProvider implements GitStatusSubProvider { private readonly provider: LocalGitProvider, ) {} - @log() - async getPausedOperationStatus( - repoPath: string, - cancellation?: CancellationToken, - ): Promise { - const scope = getLogScope(); - - const status = this.cache.pausedOperationStatus?.getOrCreate(repoPath, async _cancellable => { - const gitDir = await this.provider.config.getGitDir(repoPath); - - const operations = await new Promise>((resolve, _) => { - readdir(gitDir.uri.fsPath, { withFileTypes: true }, (err, entries) => { - const operations = new Set(); - if (err != null) { - resolve(operations); - return; - } - - if (entries.length === 0) { - resolve(operations); - return; - } - - let entry; - for (entry of entries) { - if (entry.isFile()) { - switch (entry.name) { - case 'CHERRY_PICK_HEAD': - operations.add('cherry-pick'); - break; - case 'MERGE_HEAD': - operations.add('merge'); - break; - case 'REVERT_HEAD': - operations.add('revert'); - break; - } - } else if (entry.isDirectory()) { - switch (entry.name) { - case 'rebase-apply': - operations.add('rebase-apply'); - break; - case 'rebase-merge': - operations.add('rebase-merge'); - break; - } - } - } - - resolve(operations); - }); - }); - - if (!operations.size) return undefined; - if (cancellation?.isCancellationRequested) throw new CancellationError(); - - const sortedOperations = [...operations].sort( - (a, b) => orderedOperations.indexOf(a) - orderedOperations.indexOf(b), - ); - Logger.log(`Detected paused operations: ${sortedOperations.join(', ')}`); - - const operation = sortedOperations[0]; - switch (operation) { - case 'cherry-pick': { - const result = await this.git.exec( - { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, - 'rev-parse', - '--quiet', - '--verify', - 'CHERRY_PICK_HEAD', - ); - if (result.cancelled || cancellation?.isCancellationRequested) { - throw new CancellationError(); - } - - const cherryPickHead = result.stdout.trim(); - if (!cherryPickHead) { - setLogScopeExit(scope, 'No CHERRY_PICK_HEAD found'); - return undefined; - } - - const current = (await this.provider.branches.getCurrentBranchReference(repoPath, cancellation))!; - - return { - type: 'cherry-pick', - repoPath: repoPath, - // TODO: Validate that these are correct - HEAD: createReference(cherryPickHead, repoPath, { refType: 'revision' }), - current: current, - incoming: createReference(cherryPickHead, repoPath, { refType: 'revision' }), - } satisfies GitCherryPickStatus; - } - case 'merge': { - const result = await this.git.exec( - { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, - 'rev-parse', - '--quiet', - '--verify', - 'MERGE_HEAD', - ); - if (result.cancelled || cancellation?.isCancellationRequested) { - throw new CancellationError(); - } - - const mergeHead = result.stdout.trim(); - if (!mergeHead) { - setLogScopeExit(scope, 'No MERGE_HEAD found'); - return undefined; - } - - const [branchResult, mergeBaseResult, possibleSourceBranchesResult] = await Promise.allSettled([ - this.provider.branches.getCurrentBranchReference(repoPath, cancellation), - this.provider.refs.getMergeBase(repoPath, 'MERGE_HEAD', 'HEAD', undefined, cancellation), - this.provider.branches.getBranchesWithCommits( - repoPath, - ['MERGE_HEAD'], - undefined, - { all: true, mode: 'pointsAt' }, - cancellation, - ), - ]); - - if (cancellation?.isCancellationRequested) throw new CancellationError(); - - const current = getSettledValue(branchResult)!; - const mergeBase = getSettledValue(mergeBaseResult); - const possibleSourceBranches = getSettledValue(possibleSourceBranchesResult); - - return { - type: 'merge', - repoPath: repoPath, - mergeBase: mergeBase, - HEAD: createReference(mergeHead, repoPath, { refType: 'revision' }), - current: current, - incoming: - possibleSourceBranches?.length === 1 - ? createReference(possibleSourceBranches[0], repoPath, { - refType: 'branch', - name: possibleSourceBranches[0], - remote: false, - }) - : createReference(mergeHead, repoPath, { refType: 'revision' }), - } satisfies GitMergeStatus; - } - case 'revert': { - const result = await this.git.exec( - { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, - 'rev-parse', - '--quiet', - '--verify', - 'REVERT_HEAD', - ); - if (result.cancelled || cancellation?.isCancellationRequested) { - throw new CancellationError(); - } - - const revertHead = result.stdout.trim(); - if (!revertHead) { - setLogScopeExit(scope, 'No REVERT_HEAD found'); - return undefined; - } - - const current = (await this.provider.branches.getCurrentBranchReference(repoPath, cancellation))!; - - return { - type: 'revert', - repoPath: repoPath, - HEAD: createReference(revertHead, repoPath, { refType: 'revision' }), - current: current, - incoming: createReference(revertHead, repoPath, { refType: 'revision' }), - } satisfies GitRevertStatus; - } - case 'rebase-apply': - case 'rebase-merge': { - let branch = await this.git.readDotGitFile(gitDir, [operation, 'head-name']); - if (!branch) { - setLogScopeExit(scope, `No '${operation}/head-name' found`); - return undefined; - } - - const [ - rebaseHeadResult, - origHeadResult, - ontoResult, - stepsNumberResult, - stepsTotalResult, - stepsMessageResult, - ] = await Promise.allSettled([ - this.git.exec( - { cwd: repoPath, cancellation: cancellation, errors: GitErrorHandling.Ignore }, - 'rev-parse', - '--quiet', - '--verify', - 'REBASE_HEAD', - ), - this.git.readDotGitFile(gitDir, [operation, 'orig-head']), - this.git.readDotGitFile(gitDir, [operation, 'onto']), - this.git.readDotGitFile(gitDir, [operation, 'msgnum'], { numeric: true }), - this.git.readDotGitFile(gitDir, [operation, 'end'], { numeric: true }), - this.git - .readDotGitFile(gitDir, [operation, 'message'], { throw: true }) - .catch(() => this.git.readDotGitFile(gitDir, [operation, 'message-squashed'])), - ]); - - if (cancellation?.isCancellationRequested) throw new CancellationError(); - - const origHead = getSettledValue(origHeadResult); - const onto = getSettledValue(ontoResult); - if (origHead == null || onto == null) { - setLogScopeExit(scope, `Neither '${operation}/orig-head' nor '${operation}/onto' found`); - return undefined; - } - - const rebaseHead = getSettledValue(rebaseHeadResult)?.stdout.trim(); - - if (branch.startsWith('refs/heads/')) { - branch = branch.substring(11).trim(); - } - - const [mergeBaseResult, branchTipsResult, tagTipsResult] = await Promise.allSettled([ - rebaseHead != null - ? this.provider.refs.getMergeBase(repoPath, rebaseHead, 'HEAD', undefined, cancellation) - : this.provider.refs.getMergeBase(repoPath, onto, origHead, undefined, cancellation), - this.provider.branches.getBranchesWithCommits( - repoPath, - [onto], - undefined, - { - all: true, - mode: 'pointsAt', - }, - cancellation, - ), - this.provider.tags.getTagsWithCommit(repoPath, onto, { mode: 'pointsAt' }, cancellation), - ]); - - if (cancellation?.isCancellationRequested) throw new CancellationError(); - - const mergeBase = getSettledValue(mergeBaseResult); - const branchTips = getSettledValue(branchTipsResult); - const tagTips = getSettledValue(tagTipsResult); - - let ontoRef: GitBranchReference | GitTagReference | undefined; - if (branchTips != null) { - for (const ref of branchTips) { - if (ref.startsWith('(no branch, rebasing')) continue; - - ontoRef = createReference(ref, repoPath, { - refType: 'branch', - name: ref, - remote: false, - }); - break; - } - } - if (ontoRef == null && tagTips != null) { - for (const ref of tagTips) { - if (ref.startsWith('(no branch, rebasing')) continue; - - ontoRef = createReference(ref, repoPath, { - refType: 'tag', - name: ref, - }); - break; - } - } - - return { - type: 'rebase', - repoPath: repoPath, - mergeBase: mergeBase, - HEAD: createReference(rebaseHead ?? origHead, repoPath, { refType: 'revision' }), - onto: createReference(onto, repoPath, { refType: 'revision' }), - current: ontoRef, - incoming: createReference(branch, repoPath, { - refType: 'branch', - name: branch, - remote: false, - }), - steps: { - current: { - number: getSettledValue(stepsNumberResult) ?? 0, - commit: - rebaseHead != null - ? createReference(rebaseHead, repoPath, { - refType: 'revision', - message: getSettledValue(stepsMessageResult), - }) - : undefined, - }, - total: getSettledValue(stepsTotalResult) ?? 0, - }, - } satisfies GitRebaseStatus; - } - } - }); - - return status; - } - - @gate((rp, o) => `${rp ?? ''}:${o?.quit ?? false}`) - @log() - async abortPausedOperation(repoPath: string, options?: { quit?: boolean }): Promise { - const status = await this.getPausedOperationStatus(repoPath); - if (status == null) return; - - try { - switch (status.type) { - case 'cherry-pick': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'cherry-pick', - options?.quit ? '--quit' : '--abort', - ); - break; - - case 'merge': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'merge', - options?.quit ? '--quit' : '--abort', - ); - break; - - case 'rebase': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'rebase', - options?.quit ? '--quit' : '--abort', - ); - break; - - case 'revert': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'revert', - options?.quit ? '--quit' : '--abort', - ); - break; - } - } catch (ex) { - debugger; - Logger.error(ex); - const msg: string = ex?.toString() ?? ''; - if (GitErrors.noPausedOperation.test(msg)) { - throw new PausedOperationAbortError( - PausedOperationAbortErrorReason.NothingToAbort, - status.type, - `Cannot abort as there is no ${status.type} operation in progress`, - ex, - ); - } - - throw new PausedOperationAbortError(undefined, status.type, `Cannot abort ${status.type}; ${msg}`, ex); - } - } - - @gate((rp, o) => `${rp ?? ''}:${o?.skip ?? false}`) - @log() - async continuePausedOperation(repoPath: string, options?: { skip?: boolean }): Promise { - const status = await this.getPausedOperationStatus(repoPath); - if (status == null) return; - - try { - switch (status.type) { - case 'cherry-pick': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'cherry-pick', - options?.skip ? '--skip' : '--continue', - ); - break; - - case 'merge': - if (options?.skip) throw new Error('Skipping a merge is not supported'); - await this.git.exec({ cwd: repoPath, errors: GitErrorHandling.Throw }, 'merge', '--continue'); - break; - - case 'rebase': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'rebase', - options?.skip ? '--skip' : '--continue', - ); - break; - - case 'revert': - await this.git.exec( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'revert', - options?.skip ? '--skip' : '--abort', - ); - break; - } - } catch (ex) { - debugger; - Logger.error(ex); - - const msg: string = ex?.toString() ?? ''; - if (GitErrors.emptyPreviousCherryPick.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.EmptyCommit, - status, - `Cannot continue ${status.type} as the previous cherry-pick is empty`, - ex, - ); - } - - if (GitErrors.noPausedOperation.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.NothingToContinue, - status, - `Cannot ${options?.skip ? 'skip' : 'continue'} as there is no ${status.type} operation in progress`, - ex, - ); - } - - if (GitErrors.uncommittedChanges.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.UncommittedChanges, - status, - `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are uncommitted changes`, - ex, - ); - } - - if (GitErrors.unmergedFiles.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.UnmergedFiles, - status, - `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unmerged files`, - ex, - ); - } - - if (GitErrors.unresolvedConflicts.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.UnresolvedConflicts, - status, - `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unresolved conflicts`, - ex, - ); - } - - if (GitErrors.unstagedChanges.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.UnstagedChanges, - status, - `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`} as there are unstaged changes`, - ex, - ); - } - - if (GitErrors.changesWouldBeOverwritten.test(msg)) { - throw new PausedOperationContinueError( - PausedOperationContinueErrorReason.WouldOverwrite, - status, - `Cannot ${ - options?.skip ? 'skip' : `continue ${status.type}` - } as local changes would be overwritten`, - ex, - ); - } - - throw new PausedOperationContinueError( - undefined, - status, - `Cannot ${options?.skip ? 'skip' : `continue ${status.type}`}; ${msg}`, - ex, - ); - } - } - @gate(rp => rp ?? '') @log() async getStatus(repoPath: string | undefined, cancellation?: CancellationToken): Promise { @@ -541,7 +46,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider { const status = parseGitStatus(this.container, result.stdout, repoPath, porcelainVersion); if (status?.detached) { - const pausedOpStatus = await this.getPausedOperationStatus(repoPath, cancellation); + const pausedOpStatus = await this.provider.pausedOps.getPausedOperationStatus?.(repoPath, cancellation); if (pausedOpStatus?.type === 'rebase') { return new GitStatus( this.container, diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index 67ce99ce49b79..9236e0cf2933d 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -691,7 +691,7 @@ export async function restoreFile( } } - await Container.instance.git.getRepositoryService(revision.repoPath).checkout(rev, { path: path }); + await Container.instance.git.getRepositoryService(revision.repoPath).ops?.checkout(rev, { path: path }); } export function revealCommit(commit: GitRevisionReference, options?: RevealOptions): Promise { diff --git a/src/git/actions/pausedOperation.ts b/src/git/actions/pausedOperation.ts index be7441585b524..2f1ae724c4be9 100644 --- a/src/git/actions/pausedOperation.ts +++ b/src/git/actions/pausedOperation.ts @@ -7,7 +7,7 @@ import { getReferenceLabel } from '../utils/reference.utils'; export async function abortPausedOperation(svc: GitRepositoryService, options?: { quit?: boolean }): Promise { try { - return await svc.status.abortPausedOperation?.(options); + return await svc.pausedOps?.abortPausedOperation?.(options); } catch (ex) { void window.showErrorMessage(ex.message); } @@ -23,7 +23,7 @@ export async function skipPausedOperation(svc: GitRepositoryService): Promise { try { - return await svc.status.continuePausedOperation?.(skip ? { skip: true } : undefined); + return await svc.pausedOps?.continuePausedOperation?.(skip ? { skip: true } : undefined); } catch (ex) { if ( ex instanceof PausedOperationContinueError && diff --git a/src/git/errors.ts b/src/git/errors.ts index 8de1659b39d06..65b0f25df0d23 100644 --- a/src/git/errors.ts +++ b/src/git/errors.ts @@ -372,41 +372,52 @@ export class CherryPickError extends Error { return ex instanceof CherryPickError && (reason == null || ex.reason === reason); } + private static buildErrorMessage(reason?: CherryPickErrorReason, revs?: string[]): string { + const baseMessage = `Unable to cherry-pick${ + revs?.length ? (revs.length === 1 ? ` commit '${revs[0]}'` : ` ${pluralize('commit', revs.length)}`) : '' + }`; + + switch (reason) { + case CherryPickErrorReason.AbortedWouldOverwrite: + return `${baseMessage} as some local changes would be overwritten.`; + case CherryPickErrorReason.Conflicts: + return `${baseMessage} due to conflicts.`; + default: + return baseMessage; + } + } + readonly original?: Error; readonly reason: CherryPickErrorReason | undefined; + private _revs?: string[]; + get revs(): string[] | undefined { + return this._revs; + } constructor(reason?: CherryPickErrorReason, original?: Error, revs?: string[]); constructor(message?: string, original?: Error); constructor(messageOrReason: string | CherryPickErrorReason | undefined, original?: Error, revs?: string[]) { let message; - const baseMessage = `Unable to cherry-pick${ - revs?.length ? (revs.length === 1 ? ` commit '${revs[0]}'` : ` ${pluralize('commit', revs.length)}`) : '' - }`; let reason: CherryPickErrorReason | undefined; - if (messageOrReason == null) { - message = baseMessage; - } else if (typeof messageOrReason === 'string') { - message = messageOrReason; - reason = undefined; - } else { + if (messageOrReason == null || typeof messageOrReason !== 'string') { reason = messageOrReason; - switch (reason) { - case CherryPickErrorReason.AbortedWouldOverwrite: - message = `${baseMessage} as some local changes would be overwritten.`; - break; - case CherryPickErrorReason.Conflicts: - message = `${baseMessage} due to conflicts.`; - break; - default: - message = baseMessage; - } + message = CherryPickError.buildErrorMessage(reason, revs); + } else { + message = messageOrReason; } super(message); this.original = original; this.reason = reason; + this._revs = revs; Error.captureStackTrace?.(this, CherryPickError); } + + update(changes: { revs?: string[] }): this { + this._revs = changes.revs === null ? undefined : (changes.revs ?? this._revs); + this.message = CherryPickError.buildErrorMessage(this.reason, this._revs); + return this; + } } export class WorkspaceUntrustedError extends Error { @@ -515,6 +526,27 @@ export class BranchError extends Error { return ex instanceof BranchError && (reason == null || ex.reason === reason); } + private static buildErrorMessage(reason?: BranchErrorReason, branch?: string, action?: string): string { + let baseMessage: string; + if (action != null) { + baseMessage = `Unable to ${action} branch ${branch ? `'${branch}'` : ''}`; + } else { + baseMessage = `Unable to perform action ${branch ? `with branch '${branch}'` : 'on branch'}`; + } + switch (reason) { + case BranchErrorReason.BranchAlreadyExists: + return `${baseMessage} because it already exists`; + case BranchErrorReason.BranchNotFullyMerged: + return `${baseMessage} because it is not fully merged`; + case BranchErrorReason.NoRemoteReference: + return `${baseMessage} because the remote reference does not exist`; + case BranchErrorReason.InvalidBranchName: + return `${baseMessage} because the branch name is invalid`; + default: + return baseMessage; + } + } + readonly original?: Error; readonly reason: BranchErrorReason | undefined; private _branch?: string; @@ -536,8 +568,8 @@ export class BranchError extends Error { ) { let message; let reason: BranchErrorReason | undefined; - if (typeof messageOrReason !== 'string') { - reason = messageOrReason as BranchErrorReason; + if (messageOrReason == null || typeof messageOrReason !== 'string') { + reason = messageOrReason; message = BranchError.buildErrorMessage(reason, branch, action); } else { message = messageOrReason; @@ -551,27 +583,6 @@ export class BranchError extends Error { Error.captureStackTrace?.(this, BranchError); } - private static buildErrorMessage(reason?: BranchErrorReason, branch?: string, action?: string): string { - let baseMessage: string; - if (action != null) { - baseMessage = `Unable to ${action} branch ${branch ? `'${branch}'` : ''}`; - } else { - baseMessage = `Unable to perform action ${branch ? `with branch '${branch}'` : 'on branch'}`; - } - switch (reason) { - case BranchErrorReason.BranchAlreadyExists: - return `${baseMessage} because it already exists`; - case BranchErrorReason.BranchNotFullyMerged: - return `${baseMessage} because it is not fully merged`; - case BranchErrorReason.NoRemoteReference: - return `${baseMessage} because the remote reference does not exist`; - case BranchErrorReason.InvalidBranchName: - return `${baseMessage} because the branch name is invalid`; - default: - return baseMessage; - } - } - update(changes: { branch?: string; action?: string }): this { this._branch = changes.branch === null ? undefined : (changes.branch ?? this._branch); this._action = changes.action === null ? undefined : (changes.action ?? this._action); @@ -594,6 +605,30 @@ export class TagError extends Error { return ex instanceof TagError && (reason == null || ex.reason === reason); } + private static buildErrorMessage(reason?: TagErrorReason, tag?: string, action?: string): string { + let baseMessage: string; + if (action != null) { + baseMessage = `Unable to ${action} tag ${tag ? `'${tag}'` : ''}`; + } else { + baseMessage = `Unable to perform action${tag ? ` with tag '${tag}'` : 'on tag'}`; + } + + switch (reason) { + case TagErrorReason.TagAlreadyExists: + return `${baseMessage} because it already exists`; + case TagErrorReason.TagNotFound: + return `${baseMessage} because it does not exist`; + case TagErrorReason.InvalidTagName: + return `${baseMessage} because the tag name is invalid`; + case TagErrorReason.PermissionDenied: + return `${baseMessage} because you don't have permission to push to this remote repository.`; + case TagErrorReason.RemoteRejected: + return `${baseMessage} because the remote repository rejected the push.`; + default: + return baseMessage; + } + } + readonly original?: Error; readonly reason: TagErrorReason | undefined; private _tag?: string; @@ -610,8 +645,8 @@ export class TagError extends Error { constructor(messageOrReason: string | TagErrorReason | undefined, original?: Error, tag?: string, action?: string) { let message; let reason: TagErrorReason | undefined; - if (typeof messageOrReason !== 'string') { - reason = messageOrReason as TagErrorReason; + if (messageOrReason == null || typeof messageOrReason !== 'string') { + reason = messageOrReason; message = TagError.buildErrorMessage(reason, tag, action); } else { message = messageOrReason; @@ -625,30 +660,6 @@ export class TagError extends Error { Error.captureStackTrace?.(this, TagError); } - private static buildErrorMessage(reason?: TagErrorReason, tag?: string, action?: string): string { - let baseMessage: string; - if (action != null) { - baseMessage = `Unable to ${action} tag ${tag ? `'${tag}'` : ''}`; - } else { - baseMessage = `Unable to perform action${tag ? ` with tag '${tag}'` : 'on tag'}`; - } - - switch (reason) { - case TagErrorReason.TagAlreadyExists: - return `${baseMessage} because it already exists`; - case TagErrorReason.TagNotFound: - return `${baseMessage} because it does not exist`; - case TagErrorReason.InvalidTagName: - return `${baseMessage} because the tag name is invalid`; - case TagErrorReason.PermissionDenied: - return `${baseMessage} because you don't have permission to push to this remote repository.`; - case TagErrorReason.RemoteRejected: - return `${baseMessage} because the remote repository rejected the push.`; - default: - return baseMessage; - } - } - update(changes: { tag?: string; action?: string }): this { this._tag = changes.tag === null ? undefined : (changes.tag ?? this._tag); this._action = changes.action === null ? undefined : (changes.action ?? this._action); diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 0ccc2d225dba0..c92dddfc449ee 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -154,39 +154,7 @@ export interface BranchContributionsOverview extends GitCommitStats { } export interface GitRepositoryProvider { - checkout?( - repoPath: string, - ref: string, - options?: { createBranch?: string | undefined } | { path?: string | undefined }, - ): Promise; excludeIgnoredUris(repoPath: string, uris: Uri[]): Promise; - fetch?( - repoPath: string, - options?: { - all?: boolean | undefined; - branch?: GitBranchReference | undefined; - prune?: boolean | undefined; - pull?: boolean | undefined; - remote?: string | undefined; - }, - ): Promise; - pull?( - repoPath: string, - options?: { - branch?: GitBranchReference | undefined; - rebase?: boolean | undefined; - tags?: boolean | undefined; - }, - ): Promise; - push?( - repoPath: string, - options?: { - reference?: GitReference | undefined; - force?: boolean | undefined; - publish?: { remote: string }; - }, - ): Promise; - reset?(repoPath: string, ref: string, options?: { hard?: boolean } | { soft?: boolean }): Promise; getLastFetchedTimestamp(repoPath: string): Promise; runGitCommandViaTerminal?( @@ -202,7 +170,9 @@ export interface GitRepositoryProvider { contributors: GitContributorsSubProvider; diff: GitDiffSubProvider; graph: GitGraphSubProvider; + ops?: GitOperationsSubProvider; patch?: GitPatchSubProvider; + pausedOps?: GitPausedOperationsSubProvider; refs: GitRefsSubProvider; remotes: GitRemotesSubProvider; revision: GitRevisionSubProvider; @@ -337,7 +307,6 @@ export interface IncomingActivityOptions extends GitLogOptionsBase { } export interface GitCommitsSubProvider { - cherryPick?(repoPath: string, revs: string[], options?: { edit?: boolean; noCommit?: boolean }): Promise; getCommit(repoPath: string, rev: string, cancellation?: CancellationToken): Promise; getCommitCount(repoPath: string, rev: string, cancellation?: CancellationToken): Promise; getCommitFiles(repoPath: string, rev: string, cancellation?: CancellationToken): Promise; @@ -395,6 +364,51 @@ export interface GitCommitsSubProvider { ): Promise; } +export interface GitOperationsSubProvider { + checkout( + repoPath: string, + ref: string, + options?: { createBranch?: string | undefined } | { path?: string | undefined }, + ): Promise; + cherryPick(repoPath: string, revs: string[], options?: { edit?: boolean; noCommit?: boolean }): Promise; + fetch( + repoPath: string, + options?: { + all?: boolean | undefined; + branch?: GitBranchReference | undefined; + prune?: boolean | undefined; + pull?: boolean | undefined; + remote?: string | undefined; + }, + ): Promise; + pull( + repoPath: string, + options?: { + branch?: GitBranchReference | undefined; + rebase?: boolean | undefined; + tags?: boolean | undefined; + }, + ): Promise; + push( + repoPath: string, + options?: { + reference?: GitReference | undefined; + force?: boolean | undefined; + publish?: { remote: string }; + }, + ): Promise; + reset(repoPath: string, ref: string, options?: { hard?: boolean } | { soft?: boolean }): Promise; +} + +export interface GitPausedOperationsSubProvider { + getPausedOperationStatus( + repoPath: string, + cancellation?: CancellationToken, + ): Promise; + abortPausedOperation(repoPath: string, options?: { quit?: boolean }): Promise; + continuePausedOperation(repoPath: string, options?: { skip?: boolean }): Promise; +} + export interface GitConfigSubProvider { getConfig?(repoPath: string, key: GitConfigKeys): Promise; setConfig?(repoPath: string, key: GitConfigKeys, value: string | undefined): Promise; @@ -727,13 +741,6 @@ export interface GitStatusSubProvider { cancellation?: CancellationToken, ): Promise; - getPausedOperationStatus?( - repoPath: string, - cancellation?: CancellationToken, - ): Promise; - abortPausedOperation?(repoPath: string, options?: { quit?: boolean }): Promise; - continuePausedOperation?(repoPath: string, options?: { skip?: boolean }): Promise; - /** * Quickly check if the repository has any working changes * @param repoPath Repository path @@ -836,7 +843,9 @@ export type GitSubProvider = | GitContributorsSubProvider | GitDiffSubProvider | GitGraphSubProvider + | GitOperationsSubProvider | GitPatchSubProvider + | GitPausedOperationsSubProvider | GitRefsSubProvider | GitRemotesSubProvider | GitRevisionSubProvider diff --git a/src/git/gitRepositoryService.ts b/src/git/gitRepositoryService.ts index 715f44a3f0f3d..cf1b0cc9b6763 100644 --- a/src/git/gitRepositoryService.ts +++ b/src/git/gitRepositoryService.ts @@ -1,8 +1,6 @@ import type { Uri } from 'vscode'; import { GlyphChars } from '../constants'; -import { ProviderNotSupportedError } from '../errors'; import type { Features } from '../features'; -import { gate } from '../system/decorators/gate'; import { debug, log } from '../system/decorators/log'; import { groupByFilterMap } from '../system/iterable'; import { getSettledValue } from '../system/promise'; @@ -13,7 +11,9 @@ import type { GitContributorsSubProvider, GitDiffSubProvider, GitGraphSubProvider, + GitOperationsSubProvider, GitPatchSubProvider, + GitPausedOperationsSubProvider, GitProvider, GitProviderDescriptor, GitRefsSubProvider, @@ -34,7 +34,6 @@ import { createSubProviderProxyForRepo } from './gitProvider'; import type { GitProviderService } from './gitProviderService'; import type { GitBranch } from './models/branch'; import type { GitFile } from './models/file'; -import type { GitBranchReference, GitReference } from './models/reference'; import { deletedOrMissing } from './models/revision'; import type { GitTag } from './models/tag'; import { getRemoteThemeIconString } from './utils/remote.utils'; @@ -74,32 +73,11 @@ export class GitRepositoryService implements IGitRepositoryService { this.getRepository = svc.getRepository.bind(svc, path); } - @log() - checkout(ref: string, options?: { createBranch?: string } | { path?: string }): Promise { - if (this._provider.checkout == null) throw new ProviderNotSupportedError(this._provider.descriptor.name); - - return this._provider.checkout(this.path, ref, options); - } - @log({ args: { 0: uris => uris.length } }) excludeIgnoredUris(uris: Uri[]): Promise { return this._provider.excludeIgnoredUris(this.path, uris); } - @gate() - @log() - fetch(options?: { - all?: boolean; - branch?: GitBranchReference; - prune?: boolean; - pull?: boolean; - remote?: string; - }): Promise { - if (this._provider.fetch == null) throw new ProviderNotSupportedError(this._provider.descriptor.name); - - return this._provider.fetch(this.path, options); - } - getAbsoluteUri: IGitRepositoryService['getAbsoluteUri']; @log() @@ -235,29 +213,6 @@ export class GitRepositoryService implements IGitRepositoryService { return this._provider.getWorkingUri(this.path, uri); } - @gate() - @log() - pull(options?: { rebase?: boolean; tags?: boolean }): Promise { - if (this._provider.pull == null) throw new ProviderNotSupportedError(this._provider.descriptor.name); - - return this._provider.pull(this.path, options); - } - - @gate() - @log() - push(options?: { reference?: GitReference; force?: boolean; publish?: { remote: string } }): Promise { - if (this._provider.push == null) throw new ProviderNotSupportedError(this._provider.descriptor.name); - - return this._provider.push(this.path, options); - } - - @log() - async reset(ref: string, options?: { hard?: boolean } | { soft?: boolean }): Promise { - if (this._provider.reset == null) throw new ProviderNotSupportedError(this._provider.descriptor.name); - - return this._provider.reset(this.path, ref, options); - } - @log({ args: false }) async runGitCommandViaTerminal(command: string, args: string[], options?: { execute?: boolean }): Promise { return this._provider.runGitCommandViaTerminal?.(this.path, command, args, options); @@ -289,9 +244,15 @@ export class GitRepositoryService implements IGitRepositoryService { get graph(): GitSubProviderForRepo { return this.getSubProviderProxy('graph'); } + get ops(): GitSubProviderForRepo | undefined { + return this.getSubProviderProxy('ops'); + } get patch(): GitSubProviderForRepo | undefined { return this.getSubProviderProxy('patch'); } + get pausedOps(): GitSubProviderForRepo | undefined { + return this.getSubProviderProxy('pausedOps'); + } get refs(): GitSubProviderForRepo { return this.getSubProviderProxy('refs'); } diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 9236790df3cd3..d41bbd7b21adb 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -513,7 +513,7 @@ export class Repository implements Disposable { remote?: string; }) { try { - await this.git.fetch(options); + await this.git.ops?.fetch(options); this.fireChange(RepositoryChange.Unknown); } catch (ex) { @@ -593,10 +593,10 @@ export class Repository implements Disposable { try { const withTags = configuration.getCore('git.pullTags', this.uri); if (configuration.getCore('git.fetchOnPull', this.uri)) { - await this.git.fetch(); + await this.git.ops?.fetch(); } - await this.git.pull({ ...options, tags: withTags }); + await this.git.ops?.pull({ ...options, tags: withTags }); this.fireChange(RepositoryChange.Unknown); } catch (ex) { @@ -660,7 +660,7 @@ export class Repository implements Disposable { private async pushCore(options?: { force?: boolean; reference?: GitReference; publish?: { remote: string } }) { try { - await this.git.push({ + await this.git.ops?.push({ reference: options?.reference, force: options?.force, publish: options?.publish, @@ -742,7 +742,7 @@ export class Repository implements Disposable { private async switchCore(ref: string, options?: { createBranch?: string }) { try { - await this.git.checkout(ref, options); + await this.git.ops?.checkout(ref, options); this.fireChange(RepositoryChange.Unknown); } catch (ex) { diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index ea3e63b880fc4..8a854bb3e4f9f 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -231,7 +231,7 @@ export class BranchNode ] = await Promise.allSettled([ this.getLog(svc), svc.getBranchesAndTagsTipsLookup(branch.name), - this.options.showStatus && branch.current ? svc.status.getPausedOperationStatus?.() : undefined, + this.options.showStatus && branch.current ? svc.pausedOps?.getPausedOperationStatus?.() : undefined, !branch.remote ? getBranchAheadRange(svc, branch).then(range => range diff --git a/src/views/nodes/fileRevisionAsCommitNode.ts b/src/views/nodes/fileRevisionAsCommitNode.ts index 28ea941f36deb..6490187a14ccb 100644 --- a/src/views/nodes/fileRevisionAsCommitNode.ts +++ b/src/views/nodes/fileRevisionAsCommitNode.ts @@ -64,7 +64,7 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode< const pausedOpStatus = await this.view.container.git .getRepositoryService(this.commit.repoPath) - .status.getPausedOperationStatus?.(); + .pausedOps?.getPausedOperationStatus?.(); if (pausedOpStatus == null) return []; return [ diff --git a/src/views/nodes/repositoryNode.ts b/src/views/nodes/repositoryNode.ts index 0b5a8989391b1..5beb6d6a80530 100644 --- a/src/views/nodes/repositoryNode.ts +++ b/src/views/nodes/repositoryNode.ts @@ -96,7 +96,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit status.rebasing, ); - const pausedOpStatus = await this.repo.git.status.getPausedOperationStatus?.(); + const pausedOpStatus = await this.repo.git.pausedOps?.getPausedOperationStatus?.(); if (pausedOpStatus != null) { children.push(new PausedOperationStatusNode(this.view, this, branch, pausedOpStatus, true, status)); } else if (this.view.config.showUpstreamStatus) { diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index 3a5872d4e680b..666c0a4cb0dba 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -2047,7 +2047,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider `${r.branchId}, upstream: ${r.branchUpstreamName}` }, }) private pushBranch(ref: BranchRef) { - void this.container.git.getRepositoryService(ref.repoPath).push({ + void this.container.git.getRepositoryService(ref.repoPath).ops?.push({ reference: { name: ref.branchName, ref: ref.branchId, @@ -1991,7 +1991,9 @@ async function getWipInfo( const [statusResult, pausedOpStatusResult] = await Promise.allSettled([ statusPromise, - active ? container.git.getRepositoryService(branch.repoPath).status.getPausedOperationStatus?.() : undefined, + active + ? container.git.getRepositoryService(branch.repoPath).pausedOps?.getPausedOperationStatus?.() + : undefined, ]); const status = getSettledValue(statusResult); diff --git a/src/webviews/plus/composer/composerWebview.ts b/src/webviews/plus/composer/composerWebview.ts index 40ade32b28edd..d28d922279a1e 100644 --- a/src/webviews/plus/composer/composerWebview.ts +++ b/src/webviews/plus/composer/composerWebview.ts @@ -1240,7 +1240,7 @@ export class ComposerWebviewProvider implements WebviewProvider