Skip to content

Commit

Permalink
Updates autolink messaging and adds jira integration messaging
Browse files Browse the repository at this point in the history
  • Loading branch information
d13 committed May 10, 2024
1 parent 196a55a commit 4f69cb0
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 32 deletions.
2 changes: 1 addition & 1 deletion src/commands/cloudIntegrations.ts
Expand Up @@ -5,7 +5,7 @@ import { command } from '../system/command';
import { Command } from './base';

export interface ManageCloudIntegrationsCommandArgs {
source?: 'settings' | 'account' | 'home';
source?: 'settings' | 'account' | 'home' | 'commitDetails';
integrationId?: IssueIntegrationId.Jira;
}
@command()
Expand Down
2 changes: 1 addition & 1 deletion src/plus/integrations/integrationService.ts
Expand Up @@ -106,7 +106,7 @@ export class IntegrationService implements Disposable {
}

async manageCloudIntegrations(
source: 'settings' | 'account' | 'home' | 'commandPalette',
source: 'settings' | 'account' | 'home' | 'commandPalette' | 'commitDetails',
integrationId?: IssueIntegrationId.Jira,
) {
if (this.container.telemetry.enabled) {
Expand Down
9 changes: 9 additions & 0 deletions src/webviews/apps/commitDetails/commitDetails.scss
Expand Up @@ -153,3 +153,12 @@ hr {
padding: 0px 4px 2px 4px;
font-family: var(--vscode-editor-font-family);
}

.inline-popover {
display: inline-block;
}

.tooltip-hint {
white-space: nowrap;
border-bottom: 1px dashed currentColor;
}
17 changes: 10 additions & 7 deletions src/webviews/apps/commitDetails/components/commit-details-app.ts
Expand Up @@ -7,10 +7,11 @@ import type { Serialized } from '../../../../system/serialize';
import { pluralize } from '../../../../system/string';
import type { DraftState, ExecuteCommitActionsParams, Mode, State } from '../../../commitDetails/protocol';
import {
AutolinkSettingsCommand,
ChangeReviewModeCommand,
CreatePatchFromWipCommand,
DidChangeConnectedJiraNotification,
DidChangeDraftStateNotification,
DidChangeHasAccountNotification,
DidChangeNotification,
DidChangeWipStateNotification,
ExecuteCommitActionCommand,
Expand Down Expand Up @@ -198,7 +199,6 @@ export class GlCommitDetailsApp extends LitElement {
DOM.on('[data-action="wip"]', 'click', e => this.onSwitchMode(e, 'wip')),
DOM.on('[data-action="details"]', 'click', e => this.onSwitchMode(e, 'commit')),
DOM.on('[data-action="search-commit"]', 'click', e => this.onSearchCommit(e)),
DOM.on('[data-action="autolink-settings"]', 'click', e => this.onAutolinkSettings(e)),
DOM.on('[data-action="files-layout"]', 'click', e => this.onToggleFilesLayout(e)),
DOM.on<GlInspectNav, undefined>('gl-inspect-nav', 'gl-pin', () => this.onTogglePin()),
DOM.on<GlInspectNav, undefined>('gl-inspect-nav', 'gl-back', () => this.onNavigate('back')),
Expand Down Expand Up @@ -321,6 +321,14 @@ export class GlCommitDetailsApp extends LitElement {
case DidChangeDraftStateNotification.is(msg):
this.onDraftStateChanged(msg.params.inReview, true);
break;
case DidChangeConnectedJiraNotification.is(msg):
this.state = { ...this.state!, hasConnectedJira: msg.params.hasConnectedJira };
this.dispatchEvent(new CustomEvent('state-changed', { detail: this.state }));
break;
case DidChangeHasAccountNotification.is(msg):
this.state = { ...this.state!, hasAccount: msg.params.hasAccount };
this.dispatchEvent(new CustomEvent('state-changed', { detail: this.state }));
break;
}
}

Expand Down Expand Up @@ -600,11 +608,6 @@ export class GlCommitDetailsApp extends LitElement {
this._hostIpc.sendCommand(PinCommand, { pin: !this.state!.pinned });
}

private onAutolinkSettings(e: MouseEvent) {
e.preventDefault();
this._hostIpc.sendCommand(AutolinkSettingsCommand, undefined);
}

private onPickCommit(_e: MouseEvent) {
this._hostIpc.sendCommand(PickCommitCommand, undefined);
}
Expand Down
66 changes: 61 additions & 5 deletions src/webviews/apps/commitDetails/components/gl-commit-details.ts
Expand Up @@ -20,6 +20,8 @@ import '../../shared/components/actions/action-item';
import '../../shared/components/actions/action-nav';
import '../../shared/components/commit/commit-identity';
import '../../shared/components/commit/commit-stats';
import '../../shared/components/overlays/popover';
import '../../shared/components/overlays/tooltip';
import '../../shared/components/rich/issue-pull-request';

interface ExplainState {
Expand Down Expand Up @@ -161,6 +163,35 @@ export class GlCommitDetails extends GlDetailsBase {
`;
}

private renderJiraLink() {
if (this.state == null) return 'Jira issues';

const { hasAccount, hasConnectedJira } = this.state;

let message = html`<a
href="command:gitlens.plus.cloudIntegrations.manage?${encodeURIComponent(
JSON.stringify({
source: 'commitDetails',
integrationId: 'jira',
}),
)}"
>Connect to Jira Cloud</a
>
&mdash; ${hasAccount ? '' : 'sign up and '}get access to automatic rich Jira autolinks.`;

if (hasAccount && hasConnectedJira) {
message = html`<i class="codicon codicon-check" style="vertical-align: text-bottom"></i> Jira connected
&mdash; automatic rich Jira autolinks are enabled.`;
}

return html`<gl-popover class="inline-popover" placement="bottom">
<span class="tooltip-hint" slot="anchor"
>Jira issues <code-icon icon="${hasConnectedJira ? 'check' : 'gl-unplug'}"></code-icon
></span>
<span slot="content">${message}</span>
</gl-popover>`;
}

private renderAutoLinks() {
if (this.isUncommitted) return undefined;

Expand Down Expand Up @@ -205,6 +236,13 @@ export class GlCommitDetails extends GlDetailsBase {
}
}

const jiraIntegrationLink = `command:gitlens.plus.cloudIntegrations.manage?${encodeURIComponent(
JSON.stringify({
source: 'commitDetails',
integrationId: 'jira',
}),
)}`;

return html`
<webview-pane
collapsable
Expand All @@ -219,6 +257,19 @@ export class GlCommitDetails extends GlDetailsBase {
? ''
: '…'}</span
>
<action-nav slot="actions">
<action-item
data-action="autolinks-settings"
label="Autolinks Settings"
icon="info"
href="command:gitlens.showSettingsPage!autolinks"
></action-item>
<action-item
label="Manage Jira"
icon="gl-provider-jira"
href="${jiraIntegrationLink}"
></action-item>
</action-nav>
${when(
this.state == null,
() => html`
Expand All @@ -240,11 +291,16 @@ export class GlCommitDetails extends GlDetailsBase {
<div class="section" data-region="rich-info">
<p>
<code-icon icon="info"></code-icon>&nbsp;Use
<a href="#" data-action="autolink-settings" title="Configure autolinks"
>autolinks</a
>
to linkify external references, like Jira issues or Zendesk tickets, in commit
messages.
<gl-tooltip>
<a
href="command:gitlens.showSettingsPage!autolinks"
data-action="autolink-settings"
>autolinks</a
>
<span slot="content">Configure autolinks</span>
</gl-tooltip>
to linkify external references, like ${this.renderJiraLink()} or Zendesk
tickets, in commit messages.
</p>
</div>
`;
Expand Down
11 changes: 8 additions & 3 deletions src/webviews/apps/shared/components/actions/action-item.ts
Expand Up @@ -37,13 +37,17 @@ export class ActionItem extends LitElement {
pointer-events: none;
opacity: 0.5;
}
a {
color: inherit;
}
`;

@property()
href?: string;

@property()
label = '';
label?: string;

@property()
icon = '';
Expand All @@ -56,9 +60,10 @@ export class ActionItem extends LitElement {
<a
role="${!this.href ? 'button' : nothing}"
type="${!this.href ? 'button' : nothing}"
aria-label="${this.label}"
title="${this.label}"
aria-label="${this.label ?? nothing}"
title="${this.label ?? nothing}"
?disabled=${this.disabled}
href=${this.href ?? nothing}
>
<code-icon icon="${this.icon}"></code-icon>
</a>
Expand Down
79 changes: 64 additions & 15 deletions src/webviews/commitDetails/commitDetailsWebview.ts
Expand Up @@ -37,8 +37,10 @@ import type { Repository } from '../../git/models/repository';
import { RepositoryChange, RepositoryChangeComparisonMode } from '../../git/models/repository';
import type { CreateDraftChange, Draft, DraftVisibility } from '../../gk/models/drafts';
import { showPatchesView } from '../../plus/drafts/actions';
import { isSubscriptionPaid } from '../../plus/gk/account/subscription';
import type { Subscription } from '../../plus/gk/account/subscription';
import type { SubscriptionChangeEvent } from '../../plus/gk/account/subscriptionService';
import type { ConnectionStateChangeEvent } from '../../plus/integrations/integrationService';
import { IssueIntegrationId } from '../../plus/integrations/providers/models';
import { getEntityIdentifierInput } from '../../plus/integrations/providers/utils';
import { confirmDraftStorage, ensureAccount } from '../../plus/utils';
import type { ShowInCommitGraphCommandArgs } from '../../plus/webviews/graph/protocol';
Expand Down Expand Up @@ -81,10 +83,11 @@ import type {
WipChange,
} from './protocol';
import {
AutolinkSettingsCommand,
ChangeReviewModeCommand,
CreatePatchFromWipCommand,
DidChangeConnectedJiraNotification,
DidChangeDraftStateNotification,
DidChangeHasAccountNotification,
DidChangeNotification,
DidChangeWipStateNotification,
ExecuteCommitActionCommand,
Expand Down Expand Up @@ -148,6 +151,8 @@ interface Context {
inReview: boolean;
orgSettings: State['orgSettings'];
source?: 'commitDetails' | 'patchDetails' | 'repoStatus' | 'deepLink' | 'launchpad';
hasConnectedJira: boolean | undefined;
hasAccount: boolean | undefined;
}

export class CommitDetailsWebviewProvider
Expand Down Expand Up @@ -185,12 +190,15 @@ export class CommitDetailsWebviewProvider
pullRequest: undefined,
wip: undefined,
orgSettings: this.getOrgSettings(),
hasConnectedJira: undefined,
hasAccount: undefined,
};

this._disposable = Disposable.from(
configuration.onDidChangeAny(this.onAnyConfigurationChanged, this),
onDidChangeContext(this.onContextChanged, this),
this.container.subscription.onDidChange(this.onSubscriptionChanged, this),
container.integrations.onDidChangeConnectionState(this.onIntegrationConnectionStateChanged, this),
);
}

Expand Down Expand Up @@ -428,10 +436,6 @@ export class CommitDetailsWebviewProvider
this.switchMode(e.params);
break;

case AutolinkSettingsCommand.is(e):
this.showAutolinkSettings();
break;

case PinCommand.is(e):
this.updatePinned(e.params.pin ?? false, true);
break;
Expand Down Expand Up @@ -809,8 +813,50 @@ export class CommitDetailsWebviewProvider
}
}

private onSubscriptionChanged(_e: SubscriptionChangeEvent) {
private onSubscriptionChanged(e: SubscriptionChangeEvent) {
void this.updateCodeSuggestions();
this.updateHasAccount(e.current);
}

updateHasAccount(subscription: Subscription) {
const hasAccount = subscription.account != null;
if (this._context.hasAccount == hasAccount) return;

this._context.hasAccount = hasAccount;
void this.host.notify(DidChangeHasAccountNotification, { hasAccount: hasAccount });
}

onIntegrationConnectionStateChanged(e: ConnectionStateChangeEvent) {
if (e.key === 'jira') {
const hasConnectedJira = e.reason === 'connected';
if (this._context.hasConnectedJira === hasConnectedJira) return;

this._context.hasConnectedJira = hasConnectedJira;
void this.host.notify(DidChangeConnectedJiraNotification, {
hasConnectedJira: this._context.hasConnectedJira,
});
}
}

async getHasJiraConnection(force = false): Promise<boolean> {
if (this._context.hasConnectedJira != null && !force) return this._context.hasConnectedJira;

const jira = await this.container.integrations.get(IssueIntegrationId.Jira);
if (jira == null) {
this._context.hasConnectedJira = false;
} else {
this._context.hasConnectedJira = jira.maybeConnected ?? (await jira.isConnected());
}

return this._context.hasConnectedJira;
}

async getHasAccount(force = false): Promise<boolean> {
if (this._context.hasAccount != null && !force) return this._context.hasAccount;

this._context.hasAccount = (await this.container.subscription.getSubscription())?.account != null;

return this._context.hasAccount;
}

private getPreferences(): Preferences {
Expand Down Expand Up @@ -1062,6 +1108,14 @@ export class CommitDetailsWebviewProvider
}, 100);
}

if (current.hasConnectedJira == null) {
current.hasConnectedJira = await this.getHasJiraConnection();
}

if (current.hasAccount == null) {
current.hasAccount = await this.getHasAccount();
}

const state = serialize<State>({
...this.host.baseWebviewState,
mode: current.mode,
Expand All @@ -1075,6 +1129,8 @@ export class CommitDetailsWebviewProvider
wip: serializeWipContext(wip),
orgSettings: current.orgSettings,
inReview: current.inReview,
hasConnectedJira: current.hasConnectedJira,
hasAccount: current.hasAccount,
});
return state;
}
Expand Down Expand Up @@ -1185,10 +1241,7 @@ export class CommitDetailsWebviewProvider
}

private async canAccessDrafts(): Promise<boolean> {
const subscription = await this.container.subscription.getSubscription();
if (!isSubscriptionPaid(subscription)) {
return false;
}
if ((await this.getHasAccount()) === false) return false;

return getContext<boolean>('gitlens:gk:organization:drafts:enabled', false);
}
Expand Down Expand Up @@ -1651,10 +1704,6 @@ export class CommitDetailsWebviewProvider
return commit != null ? [commit, commit.file!] : undefined;
}

private showAutolinkSettings() {
void executeCommand(Commands.ShowSettingsPageAndJumpToAutolinks);
}

private showCommitPicker() {
void executeGitCommand({
command: 'log',
Expand Down

0 comments on commit 4f69cb0

Please sign in to comment.