Auto-close copy notification after 3 seconds + configuration support (#24037)

This commit is contained in:
Cheena Malhotra
2023-08-01 10:58:41 -07:00
committed by GitHub
parent 85f3cbc751
commit e0120356cb
5 changed files with 47 additions and 15 deletions

View File

@@ -32,6 +32,7 @@ export interface IQueryEditorConfiguration {
readonly inMemoryDataProcessingThreshold: number;
readonly openAfterSave: boolean;
readonly showActionBar: boolean;
readonly showCopyCompletedNotification: boolean;
readonly preferProvidersCopyHandler: boolean;
readonly promptForLargeRowSelection: boolean;
},

View File

@@ -413,7 +413,7 @@ export class DataResourceDataProvider implements IGridDataProvider {
private async copyResultsAsync(selection: Slick.Range[], includeHeaders?: boolean, tableView?: IDisposableDataProvider<Slick.SlickData>): Promise<void> {
try {
await copySelectionToClipboard(this._clipboardService, this._notificationService, this, selection, includeHeaders, tableView);
await copySelectionToClipboard(this._clipboardService, this._notificationService, this._configurationService, this, selection, includeHeaders, tableView);
} catch (error) {
this._notificationService.error(localize('copyFailed', "Copy failed with error: {0}", getErrorMessage(error)));
}

View File

@@ -303,6 +303,11 @@ const queryEditorConfiguration: IConfigurationNode = {
'description': localize('queryEditor.results.copyRemoveNewLine', "Configuration options for copying multi-line results from the Results View"),
'default': true
},
'queryEditor.results.showCopyCompletedNotification': {
'type': 'boolean',
'description': localize('queryEditor.results.showCopyCompletedNotification', "Whether to show notifications when a results grid copy operation is completed."),
'default': true
},
'queryEditor.results.skipNewLineAfterTrailingLineBreak': {
'type': 'boolean',
'description': localize('queryEditor.results.skipNewLineAfterTrailingLineBreak', "Whether to skip adding a line break between rows when copying results if the previous row already has a trailing line break. The default value is false."),

View File

@@ -13,6 +13,8 @@ import { toAction } from 'vs/base/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { GridRange } from 'sql/base/common/gridRange';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IQueryEditorConfiguration } from 'sql/platform/query/common/query';
export interface IGridDataProvider {
@@ -55,9 +57,10 @@ export interface IGridDataProvider {
serializeResults(format: SaveFormat, selection: Slick.Range[]): Thenable<void>;
}
export async function executeCopyWithNotification(notificationService: INotificationService, selections: Slick.Range[], copyHandler: (notification: INotificationHandle, rowCount: number) => Promise<void>, cancellationTokenSource?: CancellationTokenSource): Promise<void> {
export async function executeCopyWithNotification(notificationService: INotificationService, configurationService: IConfigurationService, selections: Slick.Range[], copyHandler: (notification: INotificationHandle, rowCount: number) => Promise<void>, cancellationTokenSource?: CancellationTokenSource): Promise<void> {
const rowRanges = GridRange.getUniqueRows(GridRange.fromSlickRanges(selections));
const rowCount = rowRanges.map(range => range.end - range.start + 1).reduce((p, c) => p + c);
const showCopyCompleteNotifications = configurationService.getValue<IQueryEditorConfiguration>('queryEditor').results.showCopyCompletedNotification;
const notificationHandle = notificationService.notify({
message: nls.localize('gridDataProvider.copying', "Copying..."),
severity: Severity.Info,
@@ -80,15 +83,30 @@ export async function executeCopyWithNotification(notificationService: INotifica
await copyHandler(notificationHandle, rowCount);
if (cancellationTokenSource === undefined || !cancellationTokenSource.token.isCancellationRequested) {
notificationHandle.progress.done();
notificationHandle.updateActions({
primary: [
toAction({
id: 'closeCopyResultsNotification',
label: nls.localize('gridDataProvider.closeNotification', "Close"),
run: () => { notificationHandle.close(); }
})]
});
notificationHandle.updateMessage(nls.localize('gridDataProvider.copyResultsCompleted', "Selected data has been copied to the clipboard. Row count: {0}.", rowCount));
if (showCopyCompleteNotifications) {
notificationHandle.updateActions({
primary: [
toAction({
id: 'closeCopyResultsNotification',
label: nls.localize('gridDataProvider.closeNotification', 'Close'),
run: () => { notificationHandle.close(); }
}),
toAction({
id: 'disableCopyNotification',
label: nls.localize('gridDataProvider.disableCopyNotification', `Don't show again`),
run: () => {
updateConfigTurnOffCopyNotifications(configurationService);
notificationService.info(nls.localize('gridDataProvider.turnOnCopyNotificationsMessage',
'Copy completed notifications are now disabled. To re-enable, modify the setting: queryEditor.results.showCopyCompletedNotification'))
}
})]
});
notificationHandle.updateMessage(nls.localize('gridDataProvider.copyResultsCompleted', "Selected data has been copied to the clipboard. Row count: {0}.", rowCount));
// Auto-close notification after 3 seconds.
setTimeout(() => notificationHandle.close(), 3000);
} else {
notificationHandle.close();
}
}
}
catch (err) {
@@ -97,9 +115,10 @@ export async function executeCopyWithNotification(notificationService: INotifica
}
}
export async function copySelectionToClipboard(clipboardService: IClipboardService, notificationService: INotificationService, provider: IGridDataProvider, selections: Slick.Range[], includeHeaders?: boolean, tableView?: IDisposableDataProvider<Slick.SlickData>): Promise<void> {
export async function copySelectionToClipboard(clipboardService: IClipboardService, notificationService: INotificationService, configurationService: IConfigurationService,
provider: IGridDataProvider, selections: Slick.Range[], includeHeaders?: boolean, tableView?: IDisposableDataProvider<Slick.SlickData>): Promise<void> {
const cancellationTokenSource = new CancellationTokenSource()
await executeCopyWithNotification(notificationService, selections, async (notificationHandle, rowCount) => {
await executeCopyWithNotification(notificationService, configurationService, selections, async (notificationHandle, rowCount) => {
const eol = provider.getEolString();
const valueSeparator = '\t';
const shouldRemoveNewLines = provider.shouldRemoveNewLines();
@@ -214,3 +233,10 @@ function removeNewLines(inputString: string): string {
let outputString: string = inputString.replace(/(\r\n|\n|\r)/gm, ' ');
return outputString;
}
/**
* Disables data copy configuration setting.
*/
function updateConfigTurnOffCopyNotifications(configurationService: IConfigurationService) {
configurationService.updateValue('queryEditor.results.showCopyCompletedNotification', false);
}

View File

@@ -581,7 +581,7 @@ export class QueryGridDataProvider implements IGridDataProvider {
if (preferProvidersCopyHandler && providerSupportCopyResults && (tableView === undefined || !tableView.isDataInMemory)) {
await this.handleCopyRequestByProvider(selections, includeHeaders);
} else {
await copySelectionToClipboard(this._clipboardService, this._notificationService, this, selections, includeHeaders, tableView);
await copySelectionToClipboard(this._clipboardService, this._notificationService, this._configurationService, this, selections, includeHeaders, tableView);
}
} catch (error) {
this._notificationService.error(nls.localize('copyFailed', "Copy failed with error: {0}", getErrorMessage(error)));
@@ -589,7 +589,7 @@ export class QueryGridDataProvider implements IGridDataProvider {
}
private async handleCopyRequestByProvider(selections: Slick.Range[], includeHeaders?: boolean): Promise<void> {
executeCopyWithNotification(this._notificationService, selections, async () => {
executeCopyWithNotification(this._notificationService, this._configurationService, selections, async () => {
await this.queryRunner.copyResults(selections, this.batchId, this.resultSetId, this.shouldIncludeHeaders(includeHeaders));
});
}