Skip to content

Commit 45fdad3

Browse files
committed
1 parent e78e63f commit 45fdad3

File tree

10 files changed

+75
-12
lines changed

10 files changed

+75
-12
lines changed

src/vs/platform/extensionManagement/common/extensionGalleryService.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,20 @@ interface IRawGalleryExtensionStatistics {
5454
readonly value: number;
5555
}
5656

57+
interface IRawGalleryExtensionPublisher {
58+
readonly displayName: string;
59+
readonly publisherId: string;
60+
readonly publisherName: string;
61+
readonly domain?: string | null;
62+
readonly isDomainVerified?: boolean;
63+
}
64+
5765
interface IRawGalleryExtension {
5866
readonly extensionId: string;
5967
readonly extensionName: string;
6068
readonly displayName: string;
6169
readonly shortDescription: string;
62-
readonly publisher: { displayName: string, publisherId: string, publisherName: string; };
70+
readonly publisher: IRawGalleryExtensionPublisher;
6371
readonly versions: IRawGalleryExtensionVersion[];
6472
readonly statistics: IRawGalleryExtensionStatistics[];
6573
readonly tags: string[] | undefined;
@@ -398,6 +406,7 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
398406
publisherId: galleryExtension.publisher.publisherId,
399407
publisher: galleryExtension.publisher.publisherName,
400408
publisherDisplayName: galleryExtension.publisher.displayName,
409+
publisherDomain: galleryExtension.publisher.domain ? { link: galleryExtension.publisher.domain, verified: !!galleryExtension.publisher.isDomainVerified } : undefined,
401410
description: galleryExtension.shortDescription || '',
402411
installCount: getStatistic(galleryExtension.statistics, 'install'),
403412
rating: getStatistic(galleryExtension.statistics, 'averagerating'),

src/vs/platform/extensionManagement/common/extensionManagement.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ export interface IGalleryExtension {
243243
publisherId: string;
244244
publisher: string;
245245
publisherDisplayName: string;
246+
publisherDomain?: { link: string, verified: boolean };
246247
description: string;
247248
installCount: number;
248249
rating: number;

src/vs/workbench/contrib/extensions/browser/extensionEditor.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
6969
import { attachKeybindingLabelStyler } from 'vs/platform/theme/common/styler';
7070
import { IEditorOptions } from 'vs/platform/editor/common/editor';
7171
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
72-
import { errorIcon, infoIcon, starEmptyIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
72+
import { errorIcon, infoIcon, starEmptyIcon, verifiedPublisherIcon as verifiedPublisherThemeIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
7373
import { MarkdownString } from 'vs/base/common/htmlContent';
7474
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
7575
import { ViewContainerLocation } from 'vs/workbench/common/views';
@@ -142,6 +142,8 @@ interface IExtensionEditorTemplate {
142142
builtin: HTMLElement;
143143
version: HTMLElement;
144144
publisher: HTMLElement;
145+
publisherDisplayName: HTMLElement;
146+
verifiedPublisherIcon: HTMLElement;
145147
installCount: HTMLElement;
146148
rating: HTMLElement;
147149
description: HTMLElement;
@@ -228,8 +230,10 @@ export class ExtensionEditor extends EditorPane {
228230
builtin.textContent = localize('builtin', "Built-in");
229231

230232
const subtitle = append(details, $('.subtitle'));
231-
const publisher = append(append(subtitle, $('.subtitle-entry')), $('span.publisher.clickable', { title: localize('publisher', "Publisher"), tabIndex: 0 }));
233+
const publisher = append(append(subtitle, $('.subtitle-entry')), $('.publisher.clickable', { title: localize('publisher', "Publisher"), tabIndex: 0 }));
232234
publisher.setAttribute('role', 'button');
235+
const verifiedPublisherIcon = append(publisher, $(`.publisher-verified${ThemeIcon.asCSSSelector(verifiedPublisherThemeIcon)}`));
236+
const publisherDisplayName = append(publisher, $('.publisher-name'));
233237
const installCount = append(append(subtitle, $('.subtitle-entry')), $('span.install', { title: localize('install count', "Install count"), tabIndex: 0 }));
234238
const rating = append(append(subtitle, $('.subtitle-entry')), $('span.rating.clickable', { title: localize('rating', "Rating"), tabIndex: 0 }));
235239
rating.setAttribute('role', 'link'); // #132645
@@ -278,6 +282,8 @@ export class ExtensionEditor extends EditorPane {
278282
navbar,
279283
preview,
280284
publisher,
285+
publisherDisplayName,
286+
verifiedPublisherIcon,
281287
rating,
282288
actionsAndStatusContainer,
283289
extensionActionBar,
@@ -366,8 +372,10 @@ export class ExtensionEditor extends EditorPane {
366372
template.name.classList.toggle('clickable', !!extension.url);
367373

368374
// subtitle
369-
template.publisher.textContent = extension.publisherDisplayName;
370375
template.publisher.classList.toggle('clickable', !!extension.url);
376+
template.publisherDisplayName.textContent = extension.publisherDisplayName;
377+
template.verifiedPublisherIcon.style.display = extension.publisherDomain?.verified ? 'inherit' : 'none';
378+
template.publisher.title = extension.publisherDomain?.link ?? '';
371379

372380
template.installCount.parentElement?.classList.toggle('hide', !extension.url);
373381

@@ -837,12 +845,15 @@ export class ExtensionEditor extends EditorPane {
837845
if (extension.url && extension.licenseUrl) {
838846
resources.push([localize('license', "License"), URI.parse(extension.licenseUrl)]);
839847
}
848+
if (extension.publisherDomain?.verified) {
849+
resources.push([extension.publisherDisplayName, URI.parse(extension.publisherDomain.link)]);
850+
}
840851
if (resources.length) {
841852
const resourcesContainer = append(container, $('.resources-container'));
842853
append(resourcesContainer, $('.additional-details-title', undefined, localize('resources', "Resources")));
843854
const resourcesElement = append(resourcesContainer, $('.resources'));
844855
for (const [label, uri] of resources) {
845-
this.transientDisposables.add(this.onClick(append(resourcesElement, $('a.resource', undefined, label)), () => this.openerService.open(uri)));
856+
this.transientDisposables.add(this.onClick(append(resourcesElement, $('a.resource', { title: uri.toString() }, label)), () => this.openerService.open(uri)));
846857
}
847858
}
848859
}

src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const syncIgnoredIcon = registerIcon('extensions-sync-ignored', Codicon.s
2424
export const remoteIcon = registerIcon('extensions-remote', Codicon.remote, localize('remoteIcon', 'Icon to indicate that an extension is remote in the extensions view and editor.'));
2525
export const installCountIcon = registerIcon('extensions-install-count', Codicon.cloudDownload, localize('installCountIcon', 'Icon shown along with the install count in the extensions view and editor.'));
2626
export const ratingIcon = registerIcon('extensions-rating', Codicon.star, localize('ratingIcon', 'Icon shown along with the rating in the extensions view and editor.'));
27+
export const verifiedPublisherIcon = registerIcon('extensions-verified-publisher', Codicon.verified, localize('verifiedPublisher', 'Icon used for the verified extension publisher in the extensions view and editor.'));
2728

2829
export const starFullIcon = registerIcon('extensions-star-full', Codicon.starFull, localize('starFullIcon', 'Full star icon used for the rating in the extensions editor.'));
2930
export const starHalfIcon = registerIcon('extensions-star-half', Codicon.starHalf, localize('starHalfIcon', 'Half star icon used for the rating in the extensions editor.'));

src/vs/workbench/contrib/extensions/browser/extensionsList.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import { IExtensionService, toExtension } from 'vs/workbench/services/extensions
2020
import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
2121
import { INotificationService } from 'vs/platform/notification/common/notification';
2222
import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
23-
import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
23+
import { registerThemingParticipant, IColorTheme, ICssStyleCollector, ThemeIcon } from 'vs/platform/theme/common/themeService';
2424
import { foreground, listActiveSelectionForeground, listActiveSelectionBackground, listInactiveSelectionForeground, listInactiveSelectionBackground, listFocusForeground, listFocusBackground, listHoverForeground, listHoverBackground } from 'vs/platform/theme/common/colorRegistry';
2525
import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme';
2626
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
2727
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
28+
import { verifiedPublisherIcon as verifiedPublisherThemeIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
2829

2930
export const EXTENSION_LIST_ELEMENT_HEIGHT = 62;
3031

@@ -38,7 +39,8 @@ export interface ITemplateData {
3839
element: HTMLElement;
3940
icon: HTMLImageElement;
4041
name: HTMLElement;
41-
author: HTMLElement;
42+
publisherDisplayName: HTMLElement;
43+
verifiedPublisherIcon: HTMLElement;
4244
description: HTMLElement;
4345
installCount: HTMLElement;
4446
ratings: HTMLElement;
@@ -92,7 +94,9 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
9294
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header, false);
9395
const description = append(details, $('.description.ellipsis'));
9496
const footer = append(details, $('.footer'));
95-
const author = append(footer, $('.author.ellipsis'));
97+
const publisher = append(footer, $('.author.ellipsis'));
98+
const verifiedPublisherIcon = append(publisher, $(`.publisher-verified${ThemeIcon.asCSSSelector(verifiedPublisherThemeIcon)}`));
99+
const publisherDisplayName = append(publisher, $('.publisher-name.ellipsis'));
96100
const actionbar = new ActionBar(footer, {
97101
animated: false,
98102
actionViewItemProvider: (action: IAction) => {
@@ -142,7 +146,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
142146
const disposable = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers);
143147

144148
return {
145-
root, element, icon, name, installCount, ratings, description, author, disposables: [disposable], actionbar,
149+
root, element, icon, name, installCount, ratings, description, publisherDisplayName, verifiedPublisherIcon, disposables: [disposable], actionbar,
146150
extensionDisposables: [],
147151
set extension(extension: IExtension) {
148152
extensionContainers.extension = extension;
@@ -159,7 +163,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
159163
data.icon.src = '';
160164
data.name.textContent = '';
161165
data.description.textContent = '';
162-
data.author.textContent = '';
166+
data.publisherDisplayName.textContent = '';
167+
data.verifiedPublisherIcon.style.display = 'none';
163168
data.installCount.style.display = 'none';
164169
data.ratings.style.display = 'none';
165170
data.extension = null;
@@ -202,7 +207,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
202207

203208
data.name.textContent = extension.displayName;
204209
data.description.textContent = extension.description;
205-
data.author.textContent = extension.publisherDisplayName;
210+
data.publisherDisplayName.textContent = extension.publisherDisplayName;
211+
data.verifiedPublisherIcon.style.display = extension.publisherDomain?.verified ? 'inherit' : 'none';
206212

207213
data.installCount.style.display = '';
208214
data.ratings.style.display = '';

src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
2020
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
2121
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2222
import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
23-
import { activationTimeIcon, errorIcon, infoIcon, installCountIcon, ratingIcon, remoteIcon, starEmptyIcon, starFullIcon, starHalfIcon, syncIgnoredIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
23+
import { activationTimeIcon, errorIcon, infoIcon, installCountIcon, ratingIcon, remoteIcon, starEmptyIcon, starFullIcon, starHalfIcon, syncIgnoredIcon, verifiedPublisherIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
2424
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
2525
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
2626
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
@@ -423,6 +423,12 @@ export class ExtensionHoverWidget extends ExtensionWidget {
423423
markdown.appendText(`\n`);
424424
}
425425

426+
if (this.extension.publisherDomain?.verified) {
427+
const bgColor = this.themeService.getColorTheme().getColor(extensionVerifiedPublisherIconColor);
428+
markdown.appendMarkdown(`<span style="color:${bgColor ? Color.Format.CSS.formatHex(bgColor) : '#ffffff'};">$(${verifiedPublisherIcon.id})</span>&nbsp;[${this.extension.publisherDomain.link.length > 50 ? `${this.extension.publisherDomain.link.substring(0, 50)}...` : this.extension.publisherDomain.link}](${this.extension.publisherDomain.link})`);
429+
markdown.appendText(`\n`);
430+
}
431+
426432
const extensionRuntimeStatus = this.extensionsWorkbenchService.getExtensionStatus(this.extension);
427433
const extensionStatus = this.extensionStatusAction.status;
428434
const reloadRequiredMessage = this.reloadAction.enabled ? this.reloadAction.tooltip : '';
@@ -493,6 +499,7 @@ export class ExtensionHoverWidget extends ExtensionWidget {
493499

494500
// Rating icon
495501
export const extensionRatingIconColor = registerColor('extensionIcon.starForeground', { light: '#DF6100', dark: '#FF8E00', hc: '#FF8E00' }, localize('extensionIconStarForeground', "The icon color for extension ratings."), true);
502+
export const extensionVerifiedPublisherIconColor = registerColor('extensionIcon.verifiedForeground', { dark: '#0E639C', light: '#007ACC', hc: null }, localize('extensionIconVerifiedForeground', "The icon color for extension verified publisher."), true);
496503

497504
registerThemingParticipant((theme, collector) => {
498505
const extensionRatingIcon = theme.getColor(extensionRatingIconColor);
@@ -510,4 +517,9 @@ registerThemingParticipant((theme, collector) => {
510517
collector.addRule(`.extension-bookmark .recommendation { border-top-color: ${bgColor}; }`);
511518
collector.addRule(`.monaco-workbench .extension-editor > .header > .details > .recommendation .codicon { color: ${bgColor}; }`);
512519
}
520+
521+
const extensionVerifiedPublisherIcon = theme.getColor(extensionVerifiedPublisherIconColor);
522+
if (extensionVerifiedPublisherIcon) {
523+
collector.addRule(`${ThemeIcon.asCSSSelector(verifiedPublisherIcon)} { color: ${extensionVerifiedPublisherIcon}; }`);
524+
}
513525
});

src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ class Extension implements IExtension {
112112
return this.local!.manifest.publisher;
113113
}
114114

115+
get publisherDomain(): { link: string, verified: boolean } | undefined {
116+
return this.gallery?.publisherDomain;
117+
}
118+
115119
get version(): string {
116120
return this.local ? this.local.manifest.version : this.latestVersion;
117121
}

src/vs/workbench/contrib/extensions/browser/media/extension.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,19 @@
153153

154154
.extension-list-item > .details > .footer > .author {
155155
flex: 1;
156+
display: flex;
157+
align-items: center;
158+
}
159+
160+
.extension-list-item > .details > .footer > .author > .publisher-name {
156161
font-size: 90%;
157162
font-weight: 600;
158163
}
159164

165+
.extension-list-item > .details > .footer > .author > .publisher-name:not(:first-child) {
166+
padding-left: 1px;
167+
}
168+
160169
.extension-list-item .ellipsis {
161170
overflow: hidden;
162171
white-space: nowrap;

src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,18 @@
115115
}
116116

117117
.extension-editor > .header > .details > .subtitle .publisher {
118+
display: flex;
119+
align-items: center;
120+
}
121+
122+
.extension-editor > .header > .details > .subtitle .publisher-name {
118123
font-size: 18px;
119124
}
120125

126+
.extension-editor > .header > .details > .subtitle .publisher-name:not(:first-child) {
127+
padding-left: 1px;
128+
}
129+
121130
.extension-editor > .header > .details > .subtitle,
122131
.extension-editor > .header > .details > .subtitle .install,
123132
.extension-editor > .header > .details > .subtitle .rating {

src/vs/workbench/contrib/extensions/common/extensions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface IExtension {
4545
readonly identifier: IExtensionIdentifier;
4646
readonly publisher: string;
4747
readonly publisherDisplayName: string;
48+
readonly publisherDomain?: { link: string, verified: boolean };
4849
readonly version: string;
4950
readonly latestVersion: string;
5051
readonly description: string;

0 commit comments

Comments
 (0)