Skip to content

Commit c1e8b95

Browse files
committed
Adds "pro" indicators for integrations (closes #3972)
1 parent 377a369 commit c1e8b95

File tree

3 files changed

+79
-27
lines changed

3 files changed

+79
-27
lines changed

src/constants.integrations.ts

+7
Original file line numberDiff line numberDiff line change
@@ -46,42 +46,49 @@ export interface IntegrationDescriptor {
4646
name: string;
4747
icon: string;
4848
supports: IntegrationFeatures[];
49+
requiresPro: boolean;
4950
}
5051
export const supportedCloudIntegrationDescriptors: IntegrationDescriptor[] = [
5152
{
5253
id: HostingIntegrationId.GitHub,
5354
name: 'GitHub',
5455
icon: 'gl-provider-github',
5556
supports: ['prs', 'issues'],
57+
requiresPro: false,
5658
},
5759
{
5860
id: SelfHostedIntegrationId.CloudGitHubEnterprise,
5961
name: 'GitHub Enterprise',
6062
icon: 'gl-provider-github',
6163
supports: ['prs', 'issues'],
64+
requiresPro: true,
6265
},
6366
{
6467
id: HostingIntegrationId.GitLab,
6568
name: 'GitLab',
6669
icon: 'gl-provider-gitlab',
6770
supports: ['prs', 'issues'],
71+
requiresPro: false,
6872
},
6973
{
7074
id: SelfHostedIntegrationId.CloudGitLabSelfHosted,
7175
name: 'GitLab Self-Managed',
7276
icon: 'gl-provider-gitlab',
7377
supports: ['prs', 'issues'],
78+
requiresPro: true,
7479
},
7580
{
7681
id: HostingIntegrationId.AzureDevOps,
7782
name: 'Azure DevOps',
7883
icon: 'gl-provider-azdo',
7984
supports: ['prs', 'issues'],
85+
requiresPro: true,
8086
},
8187
{
8288
id: IssueIntegrationId.Jira,
8389
name: 'Jira',
8490
icon: 'gl-provider-jira',
8591
supports: ['issues'],
92+
requiresPro: true,
8693
},
8794
];

src/webviews/apps/plus/shared/components/integrations-chip.ts

+69-27
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import type {
77
} from '../../../../../commands/cloudIntegrations';
88
import type { IntegrationFeatures } from '../../../../../constants.integrations';
99
import type { Source } from '../../../../../constants.telemetry';
10-
import { hasAccountFromSubscriptionState } from '../../../../../plus/gk/utils/subscription.utils';
10+
import {
11+
hasAccountFromSubscriptionState,
12+
isSubscriptionStatePaidOrTrial,
13+
} from '../../../../../plus/gk/utils/subscription.utils';
1114
import { createCommandLink } from '../../../../../system/commands';
1215
import type { IntegrationState, State } from '../../../../home/protocol';
1316
import { stateContext } from '../../../home/context';
@@ -18,6 +21,7 @@ import '../../../shared/components/button-container';
1821
import '../../../shared/components/code-icon';
1922
import '../../../shared/components/overlays/popover';
2023
import '../../../shared/components/overlays/tooltip';
24+
import '../../../shared/components/feature-badge';
2125

2226
@customElement('gl-integrations-chip')
2327
export class GLIntegrationsChip extends LitElement {
@@ -67,11 +71,7 @@ export class GLIntegrationsChip extends LitElement {
6771
color: var(--color-foreground--25);
6872
}
6973
70-
.status--connected .status-indicator {
71-
color: var(--status-color--connected);
72-
}
73-
74-
.status--connected .status-indicator {
74+
.status--connected:not(.is-locked) .status-indicator {
7575
color: var(--status-color--connected);
7676
}
7777
@@ -96,16 +96,21 @@ export class GLIntegrationsChip extends LitElement {
9696
color: var(--color-foreground--25);
9797
}
9898
99-
.status--disconnected .integration__title {
100-
color: var(--color-foreground--50);
99+
.integration__title {
100+
display: block;
101+
}
102+
103+
.integration__title gl-feature-badge {
104+
vertical-align: super;
101105
}
102106
103107
.integration__details {
104-
display: flex;
108+
display: block;
105109
color: var(--color-foreground--75);
106110
font-size: 1rem;
107111
}
108112
113+
.status--disconnected .integration__title,
109114
.status--disconnected .integration__details {
110115
color: var(--color-foreground--50);
111116
}
@@ -141,6 +146,10 @@ export class GLIntegrationsChip extends LitElement {
141146
return hasAccountFromSubscriptionState(this._state.subscription?.state);
142147
}
143148

149+
private get isProAccount() {
150+
return isSubscriptionStatePaidOrTrial(this._state.subscription?.state);
151+
}
152+
144153
private get hasConnectedIntegrations() {
145154
return this.hasAccount && this.integrations.some(i => i.connected);
146155
}
@@ -213,6 +222,15 @@ export class GLIntegrationsChip extends LitElement {
213222
}
214223

215224
private renderIntegrationStatus(integration: IntegrationState, anyConnected: boolean) {
225+
if (integration.requiresPro && !this.isProAccount) {
226+
return html`<span
227+
class="integration status--${integration.connected ? 'connected' : 'disconnected'} is-locked"
228+
slot="anchor"
229+
><code-icon icon="${integration.icon}"></code-icon
230+
><code-icon class="status-indicator" icon="lock" size="12"></code-icon
231+
></span>`;
232+
}
233+
216234
return html`<span
217235
class="integration status--${integration.connected ? 'connected' : 'disconnected'}"
218236
slot="anchor"
@@ -227,30 +245,54 @@ export class GLIntegrationsChip extends LitElement {
227245
}
228246

229247
private renderIntegrationRow(integration: IntegrationState) {
230-
return html`<div class="integration-row status--${integration.connected ? 'connected' : 'disconnected'}">
248+
const shouldLock = integration.requiresPro && !this.isProAccount;
249+
return html`<div
250+
class="integration-row status--${integration.connected ? 'connected' : 'disconnected'}${shouldLock
251+
? ' is-locked'
252+
: ''}"
253+
>
231254
<span slot="anchor"><code-icon class="integration__icon" icon="${integration.icon}"></code-icon></span>
232255
<span>
233-
<span class="integration__title">${integration.name}</span>
256+
<span class="integration__title">
257+
${integration.name}
258+
${shouldLock
259+
? html` <gl-feature-badge
260+
placement="right"
261+
.source=${{ source: 'account', detail: 'integrations' }}
262+
cloud
263+
></gl-feature-badge>`
264+
: nothing}
265+
</span>
234266
<span class="integration__details">${getIntegrationDetails(integration)}</span>
235267
</span>
236268
<span class="integration__actions">
237-
${integration.connected
238-
? html`<gl-tooltip class="status-indicator status--connected" placement="bottom" content="Connected"
239-
><code-icon class="status-indicator" icon="check"></code-icon
269+
${shouldLock
270+
? html`<gl-tooltip
271+
class="status-indicator status--disconnected"
272+
placement="bottom"
273+
content="Unlock ${integration.name} features with GitLens Pro"
274+
><code-icon class="status-indicator" icon="lock"></code-icon
240275
></gl-tooltip>`
241-
: html`<gl-button
242-
appearance="toolbar"
243-
href="${createCommandLink<ConnectCloudIntegrationsCommandArgs>(
244-
'gitlens.plus.cloudIntegrations.connect',
245-
{
246-
integrationIds: [integration.id],
247-
source: 'account',
248-
},
249-
)}"
250-
tooltip="Connect ${integration.name}"
251-
aria-label="Connect ${integration.name}"
252-
><code-icon icon="plug"></code-icon
253-
></gl-button>`}
276+
: integration.connected
277+
? html`<gl-tooltip
278+
class="status-indicator status--connected"
279+
placement="bottom"
280+
content="Connected"
281+
><code-icon class="status-indicator" icon="check"></code-icon
282+
></gl-tooltip>`
283+
: html`<gl-button
284+
appearance="toolbar"
285+
href="${createCommandLink<ConnectCloudIntegrationsCommandArgs>(
286+
'gitlens.plus.cloudIntegrations.connect',
287+
{
288+
integrationIds: [integration.id],
289+
source: 'account',
290+
},
291+
)}"
292+
tooltip="Connect ${integration.name}"
293+
aria-label="Connect ${integration.name}"
294+
><code-icon icon="plug"></code-icon
295+
></gl-button>`}
254296
</span>
255297
</div>`;
256298
}

src/webviews/home/homeWebview.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,9 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
10061006
: providersMetadata[i.integrationId].type === 'issues'
10071007
? ['issues']
10081008
: [],
1009+
requiresPro:
1010+
supportedCloudIntegrationDescriptors.find(item => item.id === i.integrationId)
1011+
?.requiresPro ?? false,
10091012
} satisfies IntegrationState)
10101013
: undefined,
10111014
);

0 commit comments

Comments
 (0)