feat-command-filter.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. diff --git a/src/vs/workbench/contrib/commands/common/commands.contribution.ts b/src/vs/workbench/contrib/commands/common/commands.contribution.ts
  2. index 3fd6b59..97a0e04 100644
  3. --- a/src/vs/workbench/contrib/commands/common/commands.contribution.ts
  4. +++ b/src/vs/workbench/contrib/commands/common/commands.contribution.ts
  5. @@ -9,2 +9,3 @@ import { Action2, registerAction2 } from '../../../../platform/actions/common/ac
  6. import { ICommandService } from '../../../../platform/commands/common/commands.js';
  7. +import { ConfigurationScope, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';
  8. import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
  9. @@ -12,2 +13,3 @@ import { ILogService } from '../../../../platform/log/common/log.js';
  10. import { INotificationService } from '../../../../platform/notification/common/notification.js';
  11. +import { Registry } from '../../../../platform/registry/common/platform.js';
  12. @@ -156,2 +158,30 @@ class RunCommands extends Action2 {
  13. +Registry.as<IConfigurationRegistry>('base.contributions.configuration')
  14. + .registerConfiguration({
  15. + id: 'commands',
  16. + order: 30,
  17. + title: nls.localize('commandsConfigurationTitle', "Commands"),
  18. + type: 'object',
  19. + properties: {
  20. + 'commands.filters': {
  21. + additionalProperties: {
  22. + type: 'string',
  23. + enum: ['ask', 'off', 'on'],
  24. + enumDescriptions: [
  25. + nls.localize('commands.filters.ask', 'Ask the user before executing the command.'),
  26. + nls.localize('commands.filters.off', 'The command is never authorized.'),
  27. + nls.localize('commands.filters.on', 'The command is always authorized.'),
  28. + ],
  29. + description: nls.localize('commands.filters.value', "Authorization for the command."),
  30. + },
  31. + description: nls.localize('commands.filters', "Controls which commands are authorized to be executed."),
  32. + default: {
  33. + 'workbench.action.terminal.newLocal': 'off'
  34. + },
  35. + scope: ConfigurationScope.APPLICATION,
  36. + tags: []
  37. + },
  38. + }
  39. + });
  40. +
  41. registerAction2(RunCommands);
  42. diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts
  43. index 93d1631..0533cf0 100644
  44. --- a/src/vs/workbench/services/commands/common/commandService.ts
  45. +++ b/src/vs/workbench/services/commands/common/commandService.ts
  46. @@ -8,3 +8,6 @@ import { Emitter, Event } from '../../../../base/common/event.js';
  47. import { Disposable } from '../../../../base/common/lifecycle.js';
  48. +import Severity from '../../../../base/common/severity.js';
  49. import { CommandsRegistry, ICommandEvent, ICommandService } from '../../../../platform/commands/common/commands.js';
  50. +import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  51. +import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
  52. import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
  53. @@ -20,2 +23,3 @@ export class CommandService extends Disposable implements ICommandService {
  54. private _starActivation: CancelablePromise<void> | null;
  55. + private _commandFilters: Record<string, "ask" | "off" | "on">
  56. @@ -30,3 +34,5 @@ export class CommandService extends Disposable implements ICommandService {
  57. @IExtensionService private readonly _extensionService: IExtensionService,
  58. - @ILogService private readonly _logService: ILogService
  59. + @ILogService private readonly _logService: ILogService,
  60. + @IConfigurationService private readonly _configurationService: IConfigurationService,
  61. + @IDialogService private readonly _dialogService: IDialogService
  62. ) {
  63. @@ -35,2 +41,9 @@ export class CommandService extends Disposable implements ICommandService {
  64. this._starActivation = null;
  65. + this._commandFilters = this._configurationService.getValue('commands.filters') ?? { 'workbench.action.terminal.newLocal': 'off' };
  66. +
  67. + this._configurationService.onDidChangeConfiguration(async (event) => {
  68. + if (event.affectsConfiguration('commands.filters')) {
  69. + this._commandFilters = this._configurationService.getValue('commands.filters') ?? { 'workbench.action.terminal.newLocal': 'off' };
  70. + }
  71. + })
  72. }
  73. @@ -57,2 +70,27 @@ export class CommandService extends Disposable implements ICommandService {
  74. + const filter = this._commandFilters[id];
  75. + if (filter === 'off') {
  76. + return Promise.reject(new Error(`command '${id}' not authorized`));
  77. + }
  78. + else if (filter === 'ask') {
  79. + const { result } = await this._dialogService.prompt({
  80. + type: Severity.Error,
  81. + message: `Are you sure you want to execute the command "${id}"?`,
  82. + buttons: [
  83. + {
  84. + label: 'Yes',
  85. + run: () => true
  86. + },
  87. + {
  88. + label: 'No',
  89. + run: () => false
  90. + }
  91. + ],
  92. + });
  93. +
  94. + if (!result) {
  95. + return Promise.reject(new Error(`command '${id}' not authorized`));
  96. + }
  97. + }
  98. +
  99. if (commandIsRegistered) {
  100. diff --git a/src/vs/workbench/services/commands/test/common/commandService.test.ts b/src/vs/workbench/services/commands/test/common/commandService.test.ts
  101. index ca3be11..fb456a3 100644
  102. --- a/src/vs/workbench/services/commands/test/common/commandService.test.ts
  103. +++ b/src/vs/workbench/services/commands/test/common/commandService.test.ts
  104. @@ -12,2 +12,7 @@ import { NullExtensionService } from '../../../extensions/common/extensions.js';
  105. import { CommandService } from '../../common/commandService.js';
  106. +import { NullPolicyService } from '../../../../../platform/policy/common/policy.js';
  107. +import { FileService } from '../../../../../platform/files/common/fileService.js';
  108. +import { URI } from '../../../../../base/common/uri.js';
  109. +import { ConfigurationService } from '../../../../../platform/configuration/common/configurationService.js';
  110. +import { TestDialogService } from '../../../../../platform/dialogs/test/common/testDialogService.js';
  111. @@ -16,4 +21,16 @@ suite('CommandService', function () {
  112. const store = ensureNoDisposablesAreLeakedInTestSuite();
  113. + const testDisposables = ensureNoDisposablesAreLeakedInTestSuite();
  114. + let nullConfigService: ConfigurationService
  115. setup(function () {
  116. + const nullPolicyService = new NullPolicyService();
  117. + const nullLogService = testDisposables.add(new NullLogService());
  118. + const nullFileService = testDisposables.add(new FileService(nullLogService));
  119. + nullConfigService = testDisposables.add(new ConfigurationService(
  120. + URI.file('/config.json'),
  121. + nullFileService,
  122. + nullPolicyService,
  123. + nullLogService,
  124. + ));
  125. +
  126. store.add(CommandsRegistry.registerCommand('foo', function () { }));
  127. @@ -30,3 +47,3 @@ suite('CommandService', function () {
  128. }
  129. - }, new NullLogService()));
  130. + }, new NullLogService(), nullConfigService, new TestDialogService()));
  131. @@ -50,3 +67,3 @@ suite('CommandService', function () {
  132. - const service = store.add(new CommandService(new InstantiationService(), extensionService, new NullLogService()));
  133. + const service = store.add(new CommandService(new InstantiationService(), extensionService, new NullLogService(), nullConfigService, new TestDialogService()));
  134. @@ -68,3 +85,3 @@ suite('CommandService', function () {
  135. }
  136. - }, new NullLogService()));
  137. + }, new NullLogService(), nullConfigService, new TestDialogService()));
  138. @@ -85,3 +102,3 @@ suite('CommandService', function () {
  139. }
  140. - }, new NullLogService()));
  141. + }, new NullLogService(), nullConfigService, new TestDialogService()));
  142. @@ -125,3 +142,3 @@ suite('CommandService', function () {
  143. - }, new NullLogService()));
  144. + }, new NullLogService(), nullConfigService, new TestDialogService()));
  145. @@ -166,3 +183,3 @@ suite('CommandService', function () {
  146. - }, new NullLogService()));
  147. + }, new NullLogService(), nullConfigService, new TestDialogService()));
  148. @@ -187,3 +204,3 @@ suite('CommandService', function () {
  149. };
  150. - const service = store.add(new CommandService(new InstantiationService(), extensionService, new NullLogService()));
  151. + const service = store.add(new CommandService(new InstantiationService(), extensionService, new NullLogService(), nullConfigService, new TestDialogService()));