Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions src/commands/git/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,7 @@ import type {
StepSelection,
StepState,
} from '../quickCommand';
import {
canPickStepContinue,
createPickStep,
endSteps,
freezeStep,
QuickCommand,
StepResultBreak,
} from '../quickCommand';
import { canPickStepContinue, createPickStep, endSteps, QuickCommand, StepResultBreak } from '../quickCommand';
import {
MatchAllToggleQuickInputButton,
MatchCaseToggleQuickInputButton,
Expand Down Expand Up @@ -470,7 +463,7 @@ async function updateSearchQuery(
let append = false;

if (usePickers?.author && item.item === 'author:') {
using frozen = freezeStep(step, quickpick);
using _frozen = step.freeze?.();

const authors = ops.get('author:');

Expand All @@ -492,8 +485,6 @@ async function updateSearchQuery(
},
);

frozen[Symbol.dispose]();

if (contributors != null) {
const authors = contributors
.map(c => c.email ?? c.name ?? c.username)
Expand All @@ -507,7 +498,7 @@ async function updateSearchQuery(
append = true;
}
} else if (usePickers?.file && item.item === 'file:') {
using frozen = freezeStep(step, quickpick);
using _frozen = step.freeze?.();

let files = ops.get('file:');

Expand All @@ -520,8 +511,6 @@ async function updateSearchQuery(
defaultUri: state.repo.folder?.uri,
});

frozen[Symbol.dispose]();

if (uris?.length) {
if (files == null) {
files = new Set();
Expand Down
37 changes: 24 additions & 13 deletions src/commands/quickCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export interface QuickPickStep<T extends QuickPickItem = QuickPickItem> {
value?: string;
selectValueWhenShown?: boolean;

quickpick?: QuickPick<DirectiveQuickPickItem | T>;
freeze?: () => Disposable;
frozen?: boolean;

onDidActivate?(quickpick: QuickPick<DirectiveQuickPickItem | T>): void;
Expand Down Expand Up @@ -361,7 +363,28 @@ export function createInputStep<T extends string>(step: Optional<QuickInputStep<
}

export function createPickStep<T extends QuickPickItem>(step: Optional<QuickPickStep<T>, 'type'>): QuickPickStep<T> {
return { type: 'pick', ...step };
const original = step.onDidActivate;
step = { type: 'pick' as const, ...step };
step.onDidActivate = qp => {
step.quickpick = qp;
step.freeze = () => {
qp.enabled = false;
const originalFocusOut = qp.ignoreFocusOut;
qp.ignoreFocusOut = true;
step.frozen = true;
return {
[Symbol.dispose]: () => {
step.frozen = false;
qp.enabled = true;
qp.ignoreFocusOut = originalFocusOut;
qp.show();
},
};
};
original?.(qp);
};

return step as QuickPickStep<T>;
}

export function createCustomStep<T>(step: Optional<CustomStep<T>, 'type'>): CustomStep<T> {
Expand All @@ -372,18 +395,6 @@ export function endSteps(state: PartialStepState) {
state.counter = -1;
}

export function freezeStep(step: QuickPickStep, quickpick: QuickPick<any>): Disposable {
quickpick.enabled = false;
step.frozen = true;
return {
[Symbol.dispose]: () => {
step.frozen = false;
quickpick.enabled = true;
quickpick.show();
},
};
}

export interface CrossCommandReference<T = unknown> {
command: Commands;
args?: T;
Expand Down
11 changes: 11 additions & 0 deletions src/constants.commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,17 @@ export type CoreGitCommands =
| 'git.pushForce'
| 'git.undoCommit';

export type CustomViewCommands =
| 'gitlens.home.openInGraph'
| 'gitlens.home.fetch'
| 'gitlens.home.openPullRequestChanges'
| 'gitlens.home.openPullRequestOnRemote'
| 'gitlens.home.createPullRequest'
| 'gitlens.home.openWorktree'
| 'gitlens.home.switchToBranch'
| 'gitlens.home.createBranch'
| 'gitlens.home.startWork';

export type TreeViewCommands = `gitlens.views.${
| `branches.${
| 'copy'
Expand Down
27 changes: 15 additions & 12 deletions src/constants.telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type { CustomEditorTypes, TreeViewTypes, WebviewTypes, WebviewViewTypes }
import type { FeaturePreviews, FeaturePreviewStatus } from './features';
import type { GitContributionTiers } from './git/models/contributor';
import type { Subscription, SubscriptionAccount } from './plus/gk/account/subscription';
import type { StartWorkType } from './plus/startWork/startWork';
import type { GraphColumnConfig } from './plus/webviews/graph/protocol';
import type { Period } from './plus/webviews/timeline/protocol';
import type { Flatten } from './system/object';
Expand Down Expand Up @@ -227,6 +226,10 @@ export type TelemetryEvents = {
enabled: boolean;
version: string;
};
/** Sent when the user chooses to create a branch from the home view */
'home/createBranch': void;
/** Sent when the user chooses to start work on an issue from the home view */
'home/startWork': void;

/** Sent when the user takes an action on the Launchpad title bar */
'launchpad/title/action': {
Expand Down Expand Up @@ -360,25 +363,26 @@ export type TelemetryEvents = {
'startWork/open': StartWorkEventDataBase;
/** Sent when the launchpad is opened; use `instance` to correlate a StartWork "session" */
'startWork/opened': StartWorkConnectedEventData;
/** Sent when the user chooses an option to start work in the first step */
'startWork/type/chosen': {
type: StartWorkType;
} & StartWorkConnectedEventData;
/** Sent when the user takes an action on a StartWork issue */
'startWork/issue/action': {
action: 'soft-open';
type: StartWorkType;
} & StartWorkConnectedEventData &
Partial<Record<`item.${string}`, string | number | boolean>>;
/** Sent when the user chooses an issue to start work in the second step */
'startWork/issue/chosen': {
type: StartWorkType;
} & StartWorkConnectedEventData &
'startWork/issue/chosen': StartWorkConnectedEventData &
Partial<Record<`item.${string}`, string | number | boolean>>;
/** Sent when the Start Work has "reloaded" (while open, e.g. user refreshed or back button) and is disconnected; use `instance` to correlate a Start Work "session" */
'startWork/steps/type': StartWorkConnectedEventData;
/** Sent when the user reaches the "connect an integration" step of Start Work */
'startWork/steps/connect': StartWorkConnectedEventData;
/** Sent when the user reaches the "choose an issue" step of Start Work */
'startWork/steps/issue': StartWorkConnectedEventData;
/** Sent when the user chooses to connect an integration */
'startWork/title/action': StartWorkConnectedEventData & {
action: 'connect';
};
/** Sent when the user chooses to manage integrations */
'startWork/action': StartWorkConnectedEventData & {
action: 'manage' | 'connect';
};

/** Sent when the subscription is loaded */
subscription: SubscriptionEventData;
Expand Down Expand Up @@ -602,7 +606,6 @@ interface RepositoryOpenedEventData extends RepositoryEventData, RepositoryContr

type StartWorkEventDataBase = {
instance: number;
type?: StartWorkType;
};

type StartWorkEventData = {
Expand Down
94 changes: 44 additions & 50 deletions src/plus/launchpad/launchpad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
canPickStepContinue,
createPickStep,
endSteps,
freezeStep,
QuickCommand,
StepResultBreak,
} from '../../commands/quickCommand';
Expand Down Expand Up @@ -978,20 +977,23 @@ export class LaunchpadCommand extends QuickCommand<State> {
state: StepState<State>,
context: Context,
): AsyncStepResultGenerator<{ connected: boolean | IntegrationId; resume: () => void }> {
const confirmations: (QuickPickItemOfT<IntegrationId> | DirectiveQuickPickItem)[] = [
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked',
detail: 'Click to learn more about Launchpad',
iconPath: new ThemeIcon('rocket'),
onDidSelect: () =>
void executeCommand<OpenWalkthroughCommandArgs>(Commands.OpenWalkthrough, {
step: 'accelerate-pr-reviews',
source: 'launchpad',
detail: 'info',
const hasConnectedIntegration = some(context.connectedIntegrations.values(), c => c);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should filter to the supported integrations for Launchpad

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context.connectedIntegrations is already filtered to supported Launchpad integrations where it is set up. See getConnectedIntegrations of LaunchpadProvider

const confirmations: (QuickPickItemOfT<IntegrationId> | DirectiveQuickPickItem)[] = !hasConnectedIntegration
? [
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked',
detail: 'Click to learn more about Launchpad',
iconPath: new ThemeIcon('rocket'),
onDidSelect: () =>
void executeCommand<OpenWalkthroughCommandArgs>(Commands.OpenWalkthrough, {
step: 'accelerate-pr-reviews',
source: 'launchpad',
detail: 'info',
}),
}),
}),
createQuickPickSeparator(),
];
createQuickPickSeparator(),
]
: [];

for (const integration of supportedLaunchpadIntegrations) {
if (context.connectedIntegrations.get(integration)) {
Expand Down Expand Up @@ -1032,19 +1034,12 @@ export class LaunchpadCommand extends QuickCommand<State> {
{ placeholder: 'Connect an integration to get started with Launchpad', buttons: [], ignoreFocusOut: false },
);

// Note: This is a hack to allow the quickpick to stay alive after the user finishes connecting the integration.
// Otherwise it disappears.
let freeze!: () => Disposable;
step.onDidActivate = qp => {
freeze = () => freezeStep(step, qp);
};

const selection: StepSelection<typeof step> = yield step;
if (canPickStepContinue(step, state, selection)) {
const resume = freeze();
const resume = step.freeze?.();
const chosenIntegrationId = selection[0].item;
const connected = await this.ensureIntegrationConnected(chosenIntegrationId);
return { connected: connected ? chosenIntegrationId : false, resume: () => resume[Symbol.dispose]() };
return { connected: connected ? chosenIntegrationId : false, resume: () => resume?.[Symbol.dispose]() };
}

return StepResultBreak;
Expand All @@ -1058,18 +1053,22 @@ export class LaunchpadCommand extends QuickCommand<State> {
const step = this.createConfirmStep(
`${this.title} \u00a0\u2022\u00a0 Connect an ${hasConnectedIntegration ? 'Additional ' : ''}Integration`,
[
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked',
detail: 'Click to learn more about Launchpad',
iconPath: new ThemeIcon('rocket'),
onDidSelect: () =>
void executeCommand<OpenWalkthroughCommandArgs>(Commands.OpenWalkthrough, {
step: 'accelerate-pr-reviews',
source: 'launchpad',
detail: 'info',
}),
}),
createQuickPickSeparator(),
...(hasConnectedIntegration
? []
: [
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked',
detail: 'Click to learn more about Launchpad',
iconPath: new ThemeIcon('rocket'),
onDidSelect: () =>
void executeCommand<OpenWalkthroughCommandArgs>(Commands.OpenWalkthrough, {
step: 'accelerate-pr-reviews',
source: 'launchpad',
detail: 'info',
}),
}),
createQuickPickSeparator(),
]),
createQuickPickItemOfT(
{
label: `Connect an ${hasConnectedIntegration ? 'Additional ' : ''}Integration...`,
Expand All @@ -1091,30 +1090,25 @@ export class LaunchpadCommand extends QuickCommand<State> {
},
);

// Note: This is a hack to allow the quickpick to stay alive after the user finishes connecting the integration.
// Otherwise it disappears.
let freeze!: () => Disposable;
let quickpick!: QuickPick<any>;
step.onDidActivate = qp => {
quickpick = qp;
freeze = () => freezeStep(step, qp);
};

const selection: StepSelection<typeof step> = yield step;

if (canPickStepContinue(step, state, selection)) {
const previousPlaceholder = quickpick.placeholder;
quickpick.placeholder = 'Connecting integrations...';
quickpick.ignoreFocusOut = true;
const resume = freeze();
let previousPlaceholder: string | undefined;
if (step.quickpick) {
previousPlaceholder = step.quickpick.placeholder;
step.quickpick.placeholder = 'Connecting integrations...';
}
const resume = step.freeze?.();
const connected = await this.container.integrations.connectCloudIntegrations(
{ integrationIds: supportedLaunchpadIntegrations },
{
source: 'launchpad',
},
);
quickpick.placeholder = previousPlaceholder;
return { connected: connected, resume: () => resume[Symbol.dispose]() };
if (step.quickpick) {
step.quickpick.placeholder = previousPlaceholder;
}
return { connected: connected, resume: () => resume?.[Symbol.dispose]() };
}

return StepResultBreak;
Expand Down
4 changes: 3 additions & 1 deletion src/plus/launchpad/launchpadProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,9 @@ export class LaunchpadProvider implements Disposable {
await Promise.allSettled(
supportedLaunchpadIntegrations.map(async integrationId => {
const integration = await this.container.integrations.get(integrationId);
connected.set(integrationId, integration.maybeConnected ?? (await integration.isConnected()));
const isConnected = integration.maybeConnected ?? (await integration.isConnected());
const hasAccess = isConnected && (await integration.access());
connected.set(integrationId, hasAccess);
}),
);

Expand Down
Loading
Loading