@codingame/monaco-vscode-extension-gallery-service-override 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/vscode/src/vs/base/common/paging.js +5 -5
- package/vscode/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.js +11 -14
- package/vscode/src/vs/platform/extensionManagement/common/extensionGalleryService.js +12 -8
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionEditor.js +23 -45
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.js +17 -8
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensions.contribution.js +126 -118
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsList.js +1 -3
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.js +20 -9
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViews.js +85 -72
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.js +10 -22
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.js +26 -6
- package/vscode/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.js +3 -0
- package/vscode/src/vs/workbench/contrib/extensions/common/extensionQuery.js +2 -11
- package/vscode/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.js +10 -0
- package/vscode/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.js +9 -5
- package/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.js +5 -2
|
@@ -16,7 +16,7 @@ import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAct
|
|
|
16
16
|
import { IExtensionManagementService } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagement';
|
|
17
17
|
import { IExtensionManagementServerService, IWorkbenchExtensionEnablementService } from 'vscode/vscode/vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
18
18
|
import { ExtensionsInput } from 'vscode/vscode/vs/workbench/contrib/extensions/common/extensionsInput';
|
|
19
|
-
import { ServerInstalledExtensionsView, DefaultPopularExtensionsView, DefaultRecommendedExtensionsView, EnabledExtensionsView, DisabledExtensionsView, SearchMarketplaceExtensionsView, ExtensionsListView, RecentlyUpdatedExtensionsView, OutdatedExtensionsView, WorkspaceRecommendedExtensionsView, RecommendedExtensionsView,
|
|
19
|
+
import { ServerInstalledExtensionsView, DefaultPopularExtensionsView, DefaultRecommendedExtensionsView, EnabledExtensionsView, DisabledExtensionsView, SearchMarketplaceExtensionsView, ExtensionsListView, RecentlyUpdatedExtensionsView, OutdatedExtensionsView, WorkspaceRecommendedExtensionsView, RecommendedExtensionsView, NONE_CATEGORY, StaticQueryExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, DeprecatedExtensionsView } from './extensionsViews.js';
|
|
20
20
|
import { IProgressService } from 'vscode/vscode/vs/platform/progress/common/progress';
|
|
21
21
|
import { IEditorGroupsService } from 'vscode/vscode/vs/workbench/services/editor/common/editorGroupsService';
|
|
22
22
|
import Severity from 'vscode/vscode/vs/base/common/severity';
|
|
@@ -36,6 +36,7 @@ import { ViewPaneContainer } from 'vscode/vscode/vs/workbench/browser/parts/view
|
|
|
36
36
|
import { Query } from '../common/extensionQuery.js';
|
|
37
37
|
import { SuggestEnabledInput } from 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput';
|
|
38
38
|
import { alert } from 'vscode/vscode/vs/base/browser/ui/aria/aria';
|
|
39
|
+
import { EXTENSION_CATEGORIES } from 'vscode/vscode/vs/platform/extensions/common/extensions';
|
|
39
40
|
import { Registry } from 'vscode/vscode/vs/platform/registry/common/platform';
|
|
40
41
|
import { ILabelService } from 'vscode/vscode/vs/platform/label/common/label';
|
|
41
42
|
import { SyncDescriptor } from 'vscode/vscode/vs/platform/instantiation/common/descriptors';
|
|
@@ -59,6 +60,7 @@ const DefaultViewsContext = ( new RawContextKey('defaultExtensionViews', true));
|
|
|
59
60
|
const ExtensionsSortByContext = ( new RawContextKey('extensionsSortByValue', ''));
|
|
60
61
|
const SearchMarketplaceExtensionsContext = ( new RawContextKey('searchMarketplaceExtensions', false));
|
|
61
62
|
const SearchHasTextContext = ( new RawContextKey('extensionSearchHasText', false));
|
|
63
|
+
const InstalledExtensionsContext = ( new RawContextKey('installedExtensions', false));
|
|
62
64
|
const SearchInstalledExtensionsContext = ( new RawContextKey('searchInstalledExtensions', false));
|
|
63
65
|
const SearchRecentlyUpdatedExtensionsContext = ( new RawContextKey('searchRecentlyUpdatedExtensions', false));
|
|
64
66
|
const SearchExtensionUpdatesContext = ( new RawContextKey('searchExtensionUpdates', false));
|
|
@@ -179,11 +181,11 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
179
181
|
constructor() {
|
|
180
182
|
super({
|
|
181
183
|
id: 'workbench.extensions.actions.installLocalExtensionsInRemote',
|
|
182
|
-
title:
|
|
184
|
+
title: ( localize2WithPath(
|
|
183
185
|
'vs/workbench/contrib/extensions/browser/extensionsViewlet',
|
|
184
186
|
'install remote in local',
|
|
185
|
-
|
|
186
|
-
)),
|
|
187
|
+
'Install Remote Extensions Locally...'
|
|
188
|
+
)),
|
|
187
189
|
category: REMOTE_CATEGORY,
|
|
188
190
|
f1: true
|
|
189
191
|
});
|
|
@@ -275,7 +277,7 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
275
277
|
"Installed"
|
|
276
278
|
)),
|
|
277
279
|
ctorDescriptor: ( new SyncDescriptor(ExtensionsListView, [{}])),
|
|
278
|
-
when: ( ContextKeyExpr.
|
|
280
|
+
when: ( ContextKeyExpr.or(( ContextKeyExpr.has('searchInstalledExtensions')), ( ContextKeyExpr.has('installedExtensions')))),
|
|
279
281
|
});
|
|
280
282
|
viewDescriptors.push({
|
|
281
283
|
id: 'workbench.views.extensions.searchRecentlyUpdated',
|
|
@@ -369,6 +371,10 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
369
371
|
}
|
|
370
372
|
createBuiltinExtensionsViewDescriptors() {
|
|
371
373
|
const viewDescriptors = [];
|
|
374
|
+
const configuredCategories = ['themes', 'programming languages'];
|
|
375
|
+
const otherCategories = EXTENSION_CATEGORIES.filter(c => !configuredCategories.includes(c.toLowerCase()));
|
|
376
|
+
otherCategories.push(NONE_CATEGORY);
|
|
377
|
+
const otherCategoriesQuery = `${( otherCategories.map(c => `category:"${c}"`)).join(' ')} ${( configuredCategories.map(c => `category:"-${c}"`)).join(' ')}`;
|
|
372
378
|
viewDescriptors.push({
|
|
373
379
|
id: 'workbench.views.extensions.builtinFeatureExtensions',
|
|
374
380
|
name: ( localize2WithPath(
|
|
@@ -376,7 +382,7 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
376
382
|
'builtinFeatureExtensions',
|
|
377
383
|
"Features"
|
|
378
384
|
)),
|
|
379
|
-
ctorDescriptor: ( new SyncDescriptor(
|
|
385
|
+
ctorDescriptor: ( new SyncDescriptor(StaticQueryExtensionsView, [{ query: `@builtin ${otherCategoriesQuery}` }])),
|
|
380
386
|
when: ( ContextKeyExpr.has('builtInExtensions')),
|
|
381
387
|
});
|
|
382
388
|
viewDescriptors.push({
|
|
@@ -386,7 +392,7 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
386
392
|
'builtInThemesExtensions',
|
|
387
393
|
"Themes"
|
|
388
394
|
)),
|
|
389
|
-
ctorDescriptor: ( new SyncDescriptor(
|
|
395
|
+
ctorDescriptor: ( new SyncDescriptor(StaticQueryExtensionsView, [{ query: `@builtin category:themes` }])),
|
|
390
396
|
when: ( ContextKeyExpr.has('builtInExtensions')),
|
|
391
397
|
});
|
|
392
398
|
viewDescriptors.push({
|
|
@@ -396,7 +402,10 @@ let ExtensionsViewletViewsContribution = class ExtensionsViewletViewsContributio
|
|
|
396
402
|
'builtinProgrammingLanguageExtensions',
|
|
397
403
|
"Programming Languages"
|
|
398
404
|
)),
|
|
399
|
-
ctorDescriptor: ( new SyncDescriptor(
|
|
405
|
+
ctorDescriptor: ( new SyncDescriptor(
|
|
406
|
+
StaticQueryExtensionsView,
|
|
407
|
+
[{ query: `@builtin category:"programming languages"` }]
|
|
408
|
+
)),
|
|
400
409
|
when: ( ContextKeyExpr.has('builtInExtensions')),
|
|
401
410
|
});
|
|
402
411
|
return viewDescriptors;
|
|
@@ -484,6 +493,7 @@ let ExtensionsViewPaneContainer = class ExtensionsViewPaneContainer extends View
|
|
|
484
493
|
this.searchMarketplaceExtensionsContextKey = SearchMarketplaceExtensionsContext.bindTo(contextKeyService);
|
|
485
494
|
this.searchHasTextContextKey = SearchHasTextContext.bindTo(contextKeyService);
|
|
486
495
|
this.sortByUpdateDateContextKey = SortByUpdateDateContext.bindTo(contextKeyService);
|
|
496
|
+
this.installedExtensionsContextKey = InstalledExtensionsContext.bindTo(contextKeyService);
|
|
487
497
|
this.searchInstalledExtensionsContextKey = SearchInstalledExtensionsContext.bindTo(contextKeyService);
|
|
488
498
|
this.searchRecentlyUpdatedExtensionsContextKey = SearchRecentlyUpdatedExtensionsContext.bindTo(contextKeyService);
|
|
489
499
|
this.searchExtensionUpdatesContextKey = SearchExtensionUpdatesContext.bindTo(contextKeyService);
|
|
@@ -665,7 +675,8 @@ let ExtensionsViewPaneContainer = class ExtensionsViewPaneContainer extends View
|
|
|
665
675
|
this.contextKeyService.bufferChangeEvents(() => {
|
|
666
676
|
const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value);
|
|
667
677
|
this.searchHasTextContextKey.set(value.trim() !== '');
|
|
668
|
-
this.
|
|
678
|
+
this.installedExtensionsContextKey.set(ExtensionsListView.isInstalledExtensionsQuery(value));
|
|
679
|
+
this.searchInstalledExtensionsContextKey.set(ExtensionsListView.isSearchInstalledExtensionsQuery(value));
|
|
669
680
|
this.searchRecentlyUpdatedExtensionsContextKey.set(ExtensionsListView.isSearchRecentlyUpdatedQuery(value) && !ExtensionsListView.isSearchExtensionUpdatesQuery(value));
|
|
670
681
|
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value) && !ExtensionsListView.isSearchExtensionUpdatesQuery(value));
|
|
671
682
|
this.searchExtensionUpdatesContextKey.set(ExtensionsListView.isSearchExtensionUpdatesQuery(value));
|
|
@@ -48,7 +48,7 @@ import { isOfflineError } from 'vscode/vscode/vs/base/parts/request/common/reque
|
|
|
48
48
|
import { defaultCountBadgeStyles } from 'vscode/vscode/vs/platform/theme/browser/defaultStyles';
|
|
49
49
|
|
|
50
50
|
var ExtensionsListView_1;
|
|
51
|
-
const
|
|
51
|
+
const NONE_CATEGORY = 'none';
|
|
52
52
|
class ExtensionsViewState extends Disposable {
|
|
53
53
|
constructor() {
|
|
54
54
|
super(...arguments);
|
|
@@ -363,65 +363,51 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
363
363
|
return { extensions, canIncludeInstalledExtensions };
|
|
364
364
|
}
|
|
365
365
|
filterBuiltinExtensions(local, query, options) {
|
|
366
|
-
let value = query.value;
|
|
367
|
-
const showThemesOnly = /@builtin:themes/i.test(value);
|
|
368
|
-
if (showThemesOnly) {
|
|
369
|
-
value = value.replace(/@builtin:themes/g, '');
|
|
370
|
-
}
|
|
371
|
-
const showBasicsOnly = /@builtin:basics/i.test(value);
|
|
372
|
-
if (showBasicsOnly) {
|
|
373
|
-
value = value.replace(/@builtin:basics/g, '');
|
|
374
|
-
}
|
|
375
|
-
const showFeaturesOnly = /@builtin:features/i.test(value);
|
|
376
|
-
if (showFeaturesOnly) {
|
|
377
|
-
value = value.replace(/@builtin:features/g, '');
|
|
378
|
-
}
|
|
366
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
379
367
|
value = value.replace(/@builtin/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
|
380
368
|
const result = local
|
|
381
|
-
.filter(e => e.isBuiltin && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
return this.sortExtensions(themesExtensions, options);
|
|
369
|
+
.filter(e => e.isBuiltin && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
370
|
+
&& this.filterExtensionByCategory(e, includedCategories, excludedCategories));
|
|
371
|
+
return this.sortExtensions(result, options);
|
|
372
|
+
}
|
|
373
|
+
filterExtensionByCategory(e, includedCategories, excludedCategories) {
|
|
374
|
+
if (!includedCategories.length && !excludedCategories.length) {
|
|
375
|
+
return true;
|
|
389
376
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (showFeaturesOnly) {
|
|
399
|
-
const others = result.filter(e => {
|
|
400
|
-
return e.local
|
|
401
|
-
&& e.local.manifest
|
|
402
|
-
&& !isThemeExtension(e)
|
|
403
|
-
&& !isLanguageBasicExtension(e);
|
|
404
|
-
});
|
|
405
|
-
return this.sortExtensions(others, options);
|
|
377
|
+
if (e.categories.length) {
|
|
378
|
+
if (excludedCategories.length && ( e.categories.some(category => excludedCategories.includes(category.toLowerCase())))) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
return ( e.categories.some(category => includedCategories.includes(category.toLowerCase())));
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
return includedCategories.includes(NONE_CATEGORY);
|
|
406
385
|
}
|
|
407
|
-
return this.sortExtensions(result, options);
|
|
408
386
|
}
|
|
409
387
|
parseCategories(value) {
|
|
410
|
-
const
|
|
388
|
+
const includedCategories = [];
|
|
389
|
+
const excludedCategories = [];
|
|
411
390
|
value = value.replace(/\bcategory:("([^"]*)"|([^"]\S*))(\s+|\b|$)/g, (_, quotedCategory, category) => {
|
|
412
391
|
const entry = (category || quotedCategory || '').toLowerCase();
|
|
413
|
-
if (
|
|
414
|
-
|
|
392
|
+
if (entry.startsWith('-')) {
|
|
393
|
+
if (excludedCategories.indexOf(entry) === -1) {
|
|
394
|
+
excludedCategories.push(entry);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
if (includedCategories.indexOf(entry) === -1) {
|
|
399
|
+
includedCategories.push(entry);
|
|
400
|
+
}
|
|
415
401
|
}
|
|
416
402
|
return '';
|
|
417
403
|
});
|
|
418
|
-
return { value,
|
|
404
|
+
return { value, includedCategories, excludedCategories };
|
|
419
405
|
}
|
|
420
406
|
filterInstalledExtensions(local, runningExtensions, query, options) {
|
|
421
|
-
let { value,
|
|
407
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
422
408
|
value = value.replace(/@installed/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
|
423
409
|
const matchingText = (e) => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1 || e.description.toLowerCase().indexOf(value) > -1)
|
|
424
|
-
&&
|
|
410
|
+
&& this.filterExtensionByCategory(e, includedCategories, excludedCategories);
|
|
425
411
|
let result;
|
|
426
412
|
if (options.sortBy !== undefined) {
|
|
427
413
|
result = local.filter(e => !e.isBuiltin && matchingText(e));
|
|
@@ -473,27 +459,27 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
473
459
|
return result;
|
|
474
460
|
}
|
|
475
461
|
filterOutdatedExtensions(local, query, options) {
|
|
476
|
-
let { value,
|
|
462
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
477
463
|
value = value.replace(/@outdated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
|
478
464
|
const result = local
|
|
479
465
|
.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName))
|
|
480
466
|
.filter(extension => extension.outdated
|
|
481
467
|
&& (extension.name.toLowerCase().indexOf(value) > -1 || extension.displayName.toLowerCase().indexOf(value) > -1)
|
|
482
|
-
&&
|
|
468
|
+
&& this.filterExtensionByCategory(extension, includedCategories, excludedCategories));
|
|
483
469
|
return this.sortExtensions(result, options);
|
|
484
470
|
}
|
|
485
471
|
filterDisabledExtensions(local, runningExtensions, query, options) {
|
|
486
|
-
let { value,
|
|
472
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
487
473
|
value = value.replace(/@disabled/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
|
488
474
|
const result = local
|
|
489
475
|
.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName))
|
|
490
476
|
.filter(e => runningExtensions.every(r => !areSameExtensions({ id: r.identifier.value, uuid: r.uuid }, e.identifier))
|
|
491
477
|
&& (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
492
|
-
&&
|
|
478
|
+
&& this.filterExtensionByCategory(e, includedCategories, excludedCategories));
|
|
493
479
|
return this.sortExtensions(result, options);
|
|
494
480
|
}
|
|
495
481
|
filterEnabledExtensions(local, runningExtensions, query, options) {
|
|
496
|
-
let { value,
|
|
482
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
497
483
|
value = value ? value.replace(/@enabled/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase() : '';
|
|
498
484
|
local = local.filter(e => !e.isBuiltin);
|
|
499
485
|
const result = local
|
|
@@ -502,7 +488,7 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
502
488
|
r => areSameExtensions({ id: r.identifier.value, uuid: r.uuid }, e.identifier)
|
|
503
489
|
))
|
|
504
490
|
&& (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
505
|
-
&&
|
|
491
|
+
&& this.filterExtensionByCategory(e, includedCategories, excludedCategories));
|
|
506
492
|
return this.sortExtensions(result, options);
|
|
507
493
|
}
|
|
508
494
|
filterWorkspaceUnsupportedExtensions(local, query, options) {
|
|
@@ -561,12 +547,12 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
561
547
|
return this.sortExtensions(local, options);
|
|
562
548
|
}
|
|
563
549
|
filterRecentlyUpdatedExtensions(local, query, options) {
|
|
564
|
-
let { value,
|
|
550
|
+
let { value, includedCategories, excludedCategories } = this.parseCategories(query.value);
|
|
565
551
|
const currentTime = Date.now();
|
|
566
552
|
local = local.filter(e => !e.isBuiltin && !e.outdated && e.local?.updated && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView_1.RECENT_UPDATE_DURATION);
|
|
567
553
|
value = value.replace(/@recentlyUpdated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
|
568
|
-
const result = local.filter(e => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
569
|
-
|
|
554
|
+
const result = local.filter(e => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
|
|
555
|
+
&& this.filterExtensionByCategory(e, includedCategories, excludedCategories));
|
|
570
556
|
options.sortBy = options.sortBy ?? "UpdateDate" ;
|
|
571
557
|
return this.sortExtensions(result, options);
|
|
572
558
|
}
|
|
@@ -921,6 +907,7 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
921
907
|
}
|
|
922
908
|
static isLocalExtensionsQuery(query, sortBy) {
|
|
923
909
|
return this.isInstalledExtensionsQuery(query)
|
|
910
|
+
|| this.isSearchInstalledExtensionsQuery(query)
|
|
924
911
|
|| this.isOutdatedExtensionsQuery(query)
|
|
925
912
|
|| this.isEnabledExtensionsQuery(query)
|
|
926
913
|
|| this.isDisabledExtensionsQuery(query)
|
|
@@ -946,7 +933,10 @@ let ExtensionsListView = class ExtensionsListView extends ViewPane {
|
|
|
946
933
|
return /^\s*@workspaceUnsupported(:(untrusted|virtual)(Partial)?)?(\s|$)/i.test(query);
|
|
947
934
|
}
|
|
948
935
|
static isInstalledExtensionsQuery(query) {
|
|
949
|
-
return /@installed
|
|
936
|
+
return /@installed$/i.test(query);
|
|
937
|
+
}
|
|
938
|
+
static isSearchInstalledExtensionsQuery(query) {
|
|
939
|
+
return /@installed\s./i.test(query);
|
|
950
940
|
}
|
|
951
941
|
static isOutdatedExtensionsQuery(query) {
|
|
952
942
|
return /@outdated/i.test(query);
|
|
@@ -1072,9 +1062,11 @@ class OutdatedExtensionsView extends ExtensionsListView {
|
|
|
1072
1062
|
if (ExtensionsListView.isSearchExtensionUpdatesQuery(query)) {
|
|
1073
1063
|
query = query.replace('@updates', '@outdated');
|
|
1074
1064
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1065
|
+
return super.show(query.trim());
|
|
1066
|
+
}
|
|
1067
|
+
updateSize() {
|
|
1068
|
+
super.updateSize();
|
|
1069
|
+
this.setExpanded(this.count() > 0);
|
|
1078
1070
|
}
|
|
1079
1071
|
}
|
|
1080
1072
|
class RecentlyUpdatedExtensionsView extends ExtensionsListView {
|
|
@@ -1086,21 +1078,42 @@ class RecentlyUpdatedExtensionsView extends ExtensionsListView {
|
|
|
1086
1078
|
return super.show(query.trim());
|
|
1087
1079
|
}
|
|
1088
1080
|
}
|
|
1089
|
-
class
|
|
1090
|
-
|
|
1091
|
-
|
|
1081
|
+
let StaticQueryExtensionsView = class StaticQueryExtensionsView extends ExtensionsListView {
|
|
1082
|
+
constructor(options, viewletViewOptions, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, extensionRecommendationsService, telemetryService, configurationService, contextService, extensionManagementServerService, extensionManifestPropertiesService, extensionManagementService, workspaceService, productService, contextKeyService, viewDescriptorService, openerService, preferencesService, storageService, workspaceTrustManagementService, extensionEnablementService, layoutService, logService) {
|
|
1083
|
+
super(options, viewletViewOptions, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, extensionRecommendationsService, telemetryService, configurationService, contextService, extensionManagementServerService, extensionManifestPropertiesService, extensionManagementService, workspaceService, productService, contextKeyService, viewDescriptorService, openerService, preferencesService, storageService, workspaceTrustManagementService, extensionEnablementService, layoutService, logService);
|
|
1084
|
+
this.options = options;
|
|
1092
1085
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
async show(query) {
|
|
1096
|
-
return (query && query.trim() !== '@builtin') ? this.showEmptyModel() : super.show('@builtin:themes');
|
|
1086
|
+
show() {
|
|
1087
|
+
return super.show(this.options.query);
|
|
1097
1088
|
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1089
|
+
};
|
|
1090
|
+
StaticQueryExtensionsView = ( __decorate([
|
|
1091
|
+
( __param(2, INotificationService)),
|
|
1092
|
+
( __param(3, IKeybindingService)),
|
|
1093
|
+
( __param(4, IContextMenuService)),
|
|
1094
|
+
( __param(5, IInstantiationService)),
|
|
1095
|
+
( __param(6, IThemeService)),
|
|
1096
|
+
( __param(7, IExtensionService)),
|
|
1097
|
+
( __param(8, IExtensionsWorkbenchService)),
|
|
1098
|
+
( __param(9, IExtensionRecommendationsService)),
|
|
1099
|
+
( __param(10, ITelemetryService)),
|
|
1100
|
+
( __param(11, IConfigurationService)),
|
|
1101
|
+
( __param(12, IWorkspaceContextService)),
|
|
1102
|
+
( __param(13, IExtensionManagementServerService)),
|
|
1103
|
+
( __param(14, IExtensionManifestPropertiesService)),
|
|
1104
|
+
( __param(15, IWorkbenchExtensionManagementService)),
|
|
1105
|
+
( __param(16, IWorkspaceContextService)),
|
|
1106
|
+
( __param(17, IProductService)),
|
|
1107
|
+
( __param(18, IContextKeyService)),
|
|
1108
|
+
( __param(19, IViewDescriptorService)),
|
|
1109
|
+
( __param(20, IOpenerService)),
|
|
1110
|
+
( __param(21, IPreferencesService)),
|
|
1111
|
+
( __param(22, IStorageService)),
|
|
1112
|
+
( __param(23, IWorkspaceTrustManagementService)),
|
|
1113
|
+
( __param(24, IWorkbenchExtensionEnablementService)),
|
|
1114
|
+
( __param(25, IWorkbenchLayoutService)),
|
|
1115
|
+
( __param(26, ILogService))
|
|
1116
|
+
], StaticQueryExtensionsView));
|
|
1104
1117
|
function toSpecificWorkspaceUnsupportedQuery(query, qualifier) {
|
|
1105
1118
|
if (!query) {
|
|
1106
1119
|
return '@workspaceUnsupported:' + qualifier;
|
|
@@ -1267,4 +1280,4 @@ function getAriaLabelForExtension(extension) {
|
|
|
1267
1280
|
return `${extension.displayName}, ${deprecated ? `${deprecated}, ` : ''}${extension.version}, ${publisher}, ${extension.description} ${rating ? `, ${rating}` : ''}`;
|
|
1268
1281
|
}
|
|
1269
1282
|
|
|
1270
|
-
export {
|
|
1283
|
+
export { DefaultPopularExtensionsView, DefaultRecommendedExtensionsView, DeprecatedExtensionsView, DisabledExtensionsView, EnabledExtensionsView, ExtensionsListView, NONE_CATEGORY, OutdatedExtensionsView, RecentlyUpdatedExtensionsView, RecommendedExtensionsView, SearchMarketplaceExtensionsView, ServerInstalledExtensionsView, StaticQueryExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, WorkspaceRecommendedExtensionsView, getAriaLabelForExtension };
|
|
@@ -20,7 +20,7 @@ import { IConfigurationService } from 'vscode/vscode/vs/platform/configuration/c
|
|
|
20
20
|
import { IUserDataSyncEnablementService } from 'vscode/vscode/vs/platform/userDataSync/common/userDataSync';
|
|
21
21
|
import { starFullIcon, verifiedPublisherIcon, sponsorIcon, installCountIcon, starHalfIcon, starEmptyIcon, remoteIcon, ratingIcon, preReleaseIcon, syncIgnoredIcon, activationTimeIcon, errorIcon, warningIcon, infoIcon } from 'vscode/vscode/vs/workbench/contrib/extensions/browser/extensionsIcons';
|
|
22
22
|
import { registerColor, textLinkForeground } from 'vscode/vscode/vs/platform/theme/common/colorRegistry';
|
|
23
|
-
import { IHoverService } from 'vscode/vscode/vs/
|
|
23
|
+
import { IHoverService } from 'vscode/vscode/vs/platform/hover/browser/hover';
|
|
24
24
|
import { MarkdownString } from 'vscode/vscode/vs/base/common/htmlContent';
|
|
25
25
|
import { URI } from 'vscode/vscode/vs/base/common/uri';
|
|
26
26
|
import { IExtensionService } from 'vscode/vscode/vs/workbench/services/extensions/common/extensions';
|
|
@@ -277,18 +277,11 @@ class PreReleaseBookmarkWidget extends ExtensionWidget {
|
|
|
277
277
|
}
|
|
278
278
|
render() {
|
|
279
279
|
this.clear();
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (this.extension.state === 1 && !this.extension.local?.isPreReleaseVersion) {
|
|
287
|
-
return;
|
|
280
|
+
if (this.extension?.state === 1 ? this.extension.preRelease : this.extension?.hasPreReleaseVersion) {
|
|
281
|
+
this.element = append(this.parent, $('div.extension-bookmark'));
|
|
282
|
+
const preRelease = append(this.element, $('.pre-release'));
|
|
283
|
+
append(preRelease, $('span' + ThemeIcon.asCSSSelector(preReleaseIcon)));
|
|
288
284
|
}
|
|
289
|
-
this.element = append(this.parent, $('div.extension-bookmark'));
|
|
290
|
-
const preRelease = append(this.element, $('.pre-release'));
|
|
291
|
-
append(preRelease, $('span' + ThemeIcon.asCSSSelector(preReleaseIcon)));
|
|
292
285
|
}
|
|
293
286
|
}
|
|
294
287
|
let RemoteBadgeWidget = class RemoteBadgeWidget extends ExtensionWidget {
|
|
@@ -497,15 +490,7 @@ let ExtensionHoverWidget = ExtensionHoverWidget_1 = class ExtensionHoverWidget e
|
|
|
497
490
|
const markdown = ( new MarkdownString('', { isTrusted: true, supportThemeIcons: true }));
|
|
498
491
|
markdown.appendMarkdown(`**${this.extension.displayName}**`);
|
|
499
492
|
if (valid(this.extension.version)) {
|
|
500
|
-
markdown.appendMarkdown(` <span style="background-color:#8080802B;">** _v${this.extension.version}_** </span>`);
|
|
501
|
-
}
|
|
502
|
-
if (this.extension.state === 1 ? this.extension.local?.isPreReleaseVersion : this.extension.gallery?.properties.isPreReleaseVersion) {
|
|
503
|
-
const extensionPreReleaseIcon = this.themeService.getColorTheme().getColor(extensionPreReleaseIconColor);
|
|
504
|
-
markdown.appendMarkdown(`** ** <span style="color:#ffffff;background-color:${extensionPreReleaseIcon ? Color.Format.CSS.formatHex(extensionPreReleaseIcon) : '#ffffff'};"> $(${preReleaseIcon.id}) ${( localizeWithPath(
|
|
505
|
-
'vs/workbench/contrib/extensions/browser/extensionsWidgets',
|
|
506
|
-
'pre-release-label',
|
|
507
|
-
"Pre-Release"
|
|
508
|
-
))} </span>`);
|
|
493
|
+
markdown.appendMarkdown(` <span style="background-color:#8080802B;">** _v${this.extension.version}${(this.extension.isPreReleaseVersion ? ' (pre-release)' : '')}_** </span>`);
|
|
509
494
|
}
|
|
510
495
|
markdown.appendText(`\n`);
|
|
511
496
|
if (this.extension.state === 1 ) {
|
|
@@ -678,7 +663,10 @@ let ExtensionHoverWidget = ExtensionHoverWidget_1 = class ExtensionHoverWidget e
|
|
|
678
663
|
if (extension.isBuiltin) {
|
|
679
664
|
return undefined;
|
|
680
665
|
}
|
|
681
|
-
if (extension.
|
|
666
|
+
if (extension.isPreReleaseVersion) {
|
|
667
|
+
return undefined;
|
|
668
|
+
}
|
|
669
|
+
if (extension.preRelease) {
|
|
682
670
|
return undefined;
|
|
683
671
|
}
|
|
684
672
|
const preReleaseVersionLink = `[${( localizeWithPath(
|
|
@@ -164,6 +164,9 @@ let Extension = class Extension {
|
|
|
164
164
|
get licenseUrl() {
|
|
165
165
|
return this.gallery && this.gallery.assets.license ? this.gallery.assets.license.uri : undefined;
|
|
166
166
|
}
|
|
167
|
+
get supportUrl() {
|
|
168
|
+
return this.gallery && this.gallery.supportLink ? this.gallery.supportLink : undefined;
|
|
169
|
+
}
|
|
167
170
|
get state() {
|
|
168
171
|
return this.stateProvider(this);
|
|
169
172
|
}
|
|
@@ -220,8 +223,17 @@ let Extension = class Extension {
|
|
|
220
223
|
get preview() {
|
|
221
224
|
return this.local?.manifest.preview ?? this.gallery?.preview ?? false;
|
|
222
225
|
}
|
|
226
|
+
get preRelease() {
|
|
227
|
+
return !!this.local?.preRelease;
|
|
228
|
+
}
|
|
229
|
+
get isPreReleaseVersion() {
|
|
230
|
+
if (this.local) {
|
|
231
|
+
return this.local.isPreReleaseVersion;
|
|
232
|
+
}
|
|
233
|
+
return !!this.gallery?.properties.isPreReleaseVersion;
|
|
234
|
+
}
|
|
223
235
|
get hasPreReleaseVersion() {
|
|
224
|
-
return !!this.gallery?.hasPreReleaseVersion;
|
|
236
|
+
return !!this.gallery?.hasPreReleaseVersion || !!this.local?.hasPreReleaseVersion;
|
|
225
237
|
}
|
|
226
238
|
get hasReleaseVersion() {
|
|
227
239
|
return !!this.gallery?.hasReleaseVersion;
|
|
@@ -535,7 +547,8 @@ let Extensions = Extensions_1 = class Extensions extends Disposable {
|
|
|
535
547
|
async onDidUpdateExtensionMetadata(local) {
|
|
536
548
|
const extension = this.installed.find(e => areSameExtensions(e.identifier, local.identifier));
|
|
537
549
|
if (extension?.local) {
|
|
538
|
-
const hasChanged = extension.local.pinned !== local.pinned
|
|
550
|
+
const hasChanged = extension.local.pinned !== local.pinned
|
|
551
|
+
|| extension.local.preRelease !== local.preRelease;
|
|
539
552
|
extension.local = local;
|
|
540
553
|
if (hasChanged) {
|
|
541
554
|
this._onChange.fire({ extension });
|
|
@@ -672,9 +685,6 @@ let ExtensionsWorkbenchService = class ExtensionsWorkbenchService extends Dispos
|
|
|
672
685
|
}));
|
|
673
686
|
urlService.registerHandler(this);
|
|
674
687
|
this.whenInitialized = this.initialize();
|
|
675
|
-
lifecycleService.when(4 ).then(() => {
|
|
676
|
-
telemetryService.publicLog2('extensions:autoupdate', { mode: `${this.getAutoUpdateValue()}` });
|
|
677
|
-
});
|
|
678
688
|
}
|
|
679
689
|
async initialize() {
|
|
680
690
|
await Promise.all([this.queryLocal(), this.extensionService.whenInstalledExtensionsRegistered()]);
|
|
@@ -925,7 +935,7 @@ let ExtensionsWorkbenchService = class ExtensionsWorkbenchService extends Dispos
|
|
|
925
935
|
if (isUninstalled) {
|
|
926
936
|
const canRemoveRunningExtension = runningExtension && this.extensionService.canRemoveExtension(runningExtension);
|
|
927
937
|
const isSameExtensionRunning = runningExtension && (!extension.server || extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
|
|
928
|
-
if (!canRemoveRunningExtension && isSameExtensionRunning) {
|
|
938
|
+
if (!canRemoveRunningExtension && isSameExtensionRunning && !runningExtension.isUnderDevelopment) {
|
|
929
939
|
return ( localizeWithPath(
|
|
930
940
|
'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService',
|
|
931
941
|
'postUninstallTooltip',
|
|
@@ -1549,6 +1559,16 @@ let ExtensionsWorkbenchService = class ExtensionsWorkbenchService extends Dispos
|
|
|
1549
1559
|
return extension.local ? !this.isInstalledExtensionSynced(extension.local)
|
|
1550
1560
|
: this.extensionsSyncManagementService.hasToNeverSyncExtension(extension.identifier.id);
|
|
1551
1561
|
}
|
|
1562
|
+
async togglePreRelease(extension) {
|
|
1563
|
+
if (!extension.local) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
if (extension.preRelease !== extension.isPreReleaseVersion) {
|
|
1567
|
+
await this.extensionManagementService.updateMetadata(extension.local, { preRelease: !extension.preRelease });
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
await this.install(extension, { installPreReleaseVersion: !extension.preRelease, preRelease: !extension.preRelease });
|
|
1571
|
+
}
|
|
1552
1572
|
async toggleExtensionIgnoredToSync(extension) {
|
|
1553
1573
|
const isIgnored = this.isExtensionIgnoredToSync(extension);
|
|
1554
1574
|
if (extension.local && isIgnored) {
|
|
@@ -108,6 +108,9 @@ let FileBasedRecommendations = class FileBasedRecommendations extends ExtensionR
|
|
|
108
108
|
disposableTimeout(() => this.promptImportantRecommendations(uri, model), 0, this._store);
|
|
109
109
|
}
|
|
110
110
|
promptImportantRecommendations(uri, model, extensionRecommendations) {
|
|
111
|
+
if (model.isDisposed()) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
111
114
|
const pattern = extname(uri).toLowerCase();
|
|
112
115
|
extensionRecommendations = extensionRecommendations ?? this.recommendationsByPattern.get(pattern) ?? this.fileOpenRecommendations;
|
|
113
116
|
const extensionRecommendationEntries = Object.entries(extensionRecommendations);
|
|
@@ -2,10 +2,9 @@ import { flatten } from 'vscode/vscode/vs/base/common/arrays';
|
|
|
2
2
|
import { EXTENSION_CATEGORIES } from 'vscode/vscode/vs/platform/extensions/common/extensions';
|
|
3
3
|
|
|
4
4
|
class Query {
|
|
5
|
-
constructor(value, sortBy
|
|
5
|
+
constructor(value, sortBy) {
|
|
6
6
|
this.value = value;
|
|
7
7
|
this.sortBy = sortBy;
|
|
8
|
-
this.groupBy = groupBy;
|
|
9
8
|
this.value = value.trim();
|
|
10
9
|
}
|
|
11
10
|
static suggestions(query) {
|
|
@@ -39,21 +38,13 @@ class Query {
|
|
|
39
38
|
sortBy = by;
|
|
40
39
|
return '';
|
|
41
40
|
});
|
|
42
|
-
|
|
43
|
-
value = value.replace(/@group:(\w+)(-\w*)?/g, (match, by, order) => {
|
|
44
|
-
groupBy = by;
|
|
45
|
-
return '';
|
|
46
|
-
});
|
|
47
|
-
return ( new Query(value, sortBy, groupBy));
|
|
41
|
+
return ( new Query(value, sortBy));
|
|
48
42
|
}
|
|
49
43
|
toString() {
|
|
50
44
|
let result = this.value;
|
|
51
45
|
if (this.sortBy) {
|
|
52
46
|
result = `${result}${result ? ' ' : ''}@sort:${this.sortBy}`;
|
|
53
47
|
}
|
|
54
|
-
if (this.groupBy) {
|
|
55
|
-
result = `${result}${result ? ' ' : ''}@group:${this.groupBy}`;
|
|
56
|
-
}
|
|
57
48
|
return result;
|
|
58
49
|
}
|
|
59
50
|
isValid() {
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
2
2
|
import { URI } from 'vscode/vscode/vs/base/common/uri';
|
|
3
3
|
import { EditorInput } from 'vscode/vscode/vs/workbench/common/editor/editorInput';
|
|
4
|
+
import { Codicon } from 'vscode/vscode/vs/base/common/codicons';
|
|
5
|
+
import { registerIcon } from 'vscode/vscode/vs/platform/theme/common/iconRegistry';
|
|
4
6
|
|
|
7
|
+
const RuntimeExtensionsEditorIcon = registerIcon('runtime-extensions-editor-label-icon', Codicon.extensions, ( localizeWithPath(
|
|
8
|
+
'vs/workbench/contrib/extensions/common/runtimeExtensionsInput',
|
|
9
|
+
'runtimeExtensionEditorLabelIcon',
|
|
10
|
+
'Icon of the runtime extensions editor label.'
|
|
11
|
+
)));
|
|
5
12
|
class RuntimeExtensionsInput extends EditorInput {
|
|
6
13
|
constructor() {
|
|
7
14
|
super(...arguments);
|
|
@@ -30,6 +37,9 @@ class RuntimeExtensionsInput extends EditorInput {
|
|
|
30
37
|
"Running Extensions"
|
|
31
38
|
));
|
|
32
39
|
}
|
|
40
|
+
getIcon() {
|
|
41
|
+
return RuntimeExtensionsEditorIcon;
|
|
42
|
+
}
|
|
33
43
|
matches(other) {
|
|
34
44
|
if (super.matches(other)) {
|
|
35
45
|
return true;
|
package/vscode/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.js
CHANGED
|
@@ -13,7 +13,7 @@ import { IExtensionGalleryService } from 'vscode/vscode/vs/platform/extensionMan
|
|
|
13
13
|
import { areSameExtensions, getExtensionId, getGalleryExtensionId } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagementUtil';
|
|
14
14
|
import { Disposable } from 'vscode/vscode/vs/base/common/lifecycle';
|
|
15
15
|
import { localizeManifest } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionNls';
|
|
16
|
-
import { localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
16
|
+
import { localize2WithPath, localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
17
17
|
import { gt, rcompare } from 'vscode-semver';
|
|
18
18
|
import { isString, isUndefined } from 'vscode/vscode/vs/base/common/types';
|
|
19
19
|
import { getErrorMessage } from 'vscode/vscode/vs/base/common/errors';
|
|
@@ -181,7 +181,7 @@ let WebExtensionsScannerService = class WebExtensionsScannerService extends Disp
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
catch (error) {
|
|
184
|
-
this.logService.info(`Error while fetching the additional builtin extension ${(
|
|
184
|
+
this.logService.info(`Error while fetching the additional builtin extension ${( extensionLocation.toString())}.`, getErrorMessage(error));
|
|
185
185
|
}
|
|
186
186
|
})));
|
|
187
187
|
return result;
|
|
@@ -804,6 +804,10 @@ let WebExtensionsScannerService = class WebExtensionsScannerService extends Disp
|
|
|
804
804
|
update = true;
|
|
805
805
|
webExtension.location = migratedLocation;
|
|
806
806
|
}
|
|
807
|
+
if (isUndefined(webExtension.metadata?.hasPreReleaseVersion) && webExtension.metadata?.preRelease) {
|
|
808
|
+
update = true;
|
|
809
|
+
webExtension.metadata.hasPreReleaseVersion = true;
|
|
810
|
+
}
|
|
807
811
|
return webExtension;
|
|
808
812
|
})));
|
|
809
813
|
if (update) {
|
|
@@ -862,11 +866,11 @@ if (isWeb) {
|
|
|
862
866
|
constructor() {
|
|
863
867
|
super({
|
|
864
868
|
id: 'workbench.extensions.action.openInstalledWebExtensionsResource',
|
|
865
|
-
title:
|
|
869
|
+
title: ( localize2WithPath(
|
|
866
870
|
'vs/workbench/services/extensionManagement/browser/webExtensionsScannerService',
|
|
867
871
|
'openInstalledWebExtensionsResource',
|
|
868
|
-
|
|
869
|
-
)),
|
|
872
|
+
'Open Installed Web Extensions Resource'
|
|
873
|
+
)),
|
|
870
874
|
category: Categories.Developer,
|
|
871
875
|
f1: true,
|
|
872
876
|
precondition: IsWebContext
|