adding feedback dialog and support request buttons

This commit is contained in:
Brian Harris
2021-05-20 14:09:45 -07:00
parent 8a0c183114
commit 866ced5c08
13 changed files with 306 additions and 8 deletions

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.5938 14.6953L19.5 24L12 18.2344L4.5 24L7.40625 14.6953L0 9H9.1875L12 0L14.8125 9H24L16.5938 14.6953Z" fill="#C8C6C4"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.60021 10.4C10.174 10.0352 10.648 9.53353 10.9797 8.94002C11.3114 8.34651 11.4902 7.67983 11.5002 7C11.5002 5.93913 11.0788 4.92172 10.3286 4.17157C9.57849 3.42143 8.56107 3 7.50021 3C6.43934 3 5.42192 3.42143 4.67178 4.17157C3.92163 4.92172 3.50021 5.93913 3.50021 7C3.51016 7.67983 3.68903 8.34651 4.0207 8.94002C4.35237 9.53353 4.82643 10.0352 5.40021 10.4C4.25008 10.8144 3.25707 11.5758 2.55842 12.5789C1.85978 13.5821 1.49 14.7776 1.50021 16H2.50021C2.50021 14.6739 3.02699 13.4021 3.96467 12.4645C4.90235 11.5268 6.17412 11 7.50021 11C8.82629 11 10.0981 11.5268 11.0357 12.4645C11.9734 13.4021 12.5002 14.6739 12.5002 16H13.5002C13.5104 14.7776 13.1406 13.5821 12.442 12.5789C11.7433 11.5758 10.7503 10.8144 9.60021 10.4ZM4.50021 7C4.48685 6.61911 4.54869 6.23932 4.68222 5.88235C4.81574 5.52539 5.01832 5.19824 5.27836 4.91961C5.53841 4.64099 5.85083 4.41636 6.19775 4.25857C6.54468 4.10077 6.9193 4.01291 7.30021 4C7.36687 4 7.43354 4 7.50021 4C7.88109 3.98664 8.26088 4.04849 8.61785 4.18201C8.97482 4.31553 9.30197 4.51811 9.58059 4.77816C9.85921 5.0382 10.0838 5.35062 10.2416 5.69755C10.3994 6.04447 10.4873 6.4191 10.5002 6.8C10.5002 6.86667 10.5002 6.93333 10.5002 7C10.5136 7.38089 10.4517 7.76068 10.3182 8.11765C10.1847 8.47462 9.9821 8.80176 9.72205 9.08039C9.462 9.35901 9.14958 9.58364 8.80266 9.74143C8.45574 9.89923 8.08111 9.98709 7.70021 10C7.63354 10 7.56687 10 7.50021 10C7.11932 10.0134 6.73953 9.95151 6.38256 9.81799C6.02559 9.68447 5.69844 9.48189 5.41982 9.22184C5.1412 8.9618 4.91657 8.64938 4.75877 8.30245C4.60098 7.95553 4.51311 7.5809 4.50021 7.2C4.50021 7.13333 4.50021 7.06667 4.50021 7Z" fill="#0078D4"/>
<path d="M14.5 7C14.5267 6.1074 14.3773 5.2183 14.0603 4.38344C13.7434 3.54859 13.2651 2.78434 12.6528 2.13433C12.0404 1.48432 11.3061 0.961276 10.4917 0.595068C9.6772 0.228859 8.7986 0.0266543 7.906 0C7.771 0 7.635 0 7.5 0C6.03483 0.0318025 4.62829 0.581585 3.52993 1.55181C2.43157 2.52203 1.71239 3.84996 1.5 5.3C1.5 5.43261 1.55268 5.55979 1.64645 5.65355C1.74021 5.74732 1.86739 5.8 2 5.8C2.09374 5.81785 2.19063 5.8085 2.27923 5.77306C2.36782 5.73763 2.44443 5.67757 2.5 5.6C2.68072 4.37665 3.27585 3.25239 4.18592 2.41513C5.09599 1.57787 6.26586 1.07833 7.5 1C8.27483 0.986756 9.04468 1.12628 9.76557 1.41061C10.4865 1.69494 11.1443 2.11851 11.7015 2.65711C12.2586 3.19571 12.7042 3.8388 13.0128 4.54964C13.3214 5.26049 13.487 6.02517 13.5 6.8C13.5 6.868 13.5 6.935 13.5 7V8H9C8.86739 8 8.74021 8.05268 8.64645 8.14645C8.55268 8.24021 8.5 8.36739 8.5 8.5C8.5 8.63261 8.55268 8.75979 8.64645 8.85355C8.74021 8.94732 8.86739 9 9 9H14C14.1326 9 14.2598 8.94732 14.3536 8.85355C14.4473 8.75979 14.5 8.63261 14.5 8.5V7Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.48438 10.375C8.01042 10.5833 8.48958 10.8594 8.92188 11.2031C9.35417 11.5469 9.72396 11.9453 10.0312 12.3984C10.3385 12.8516 10.5755 13.3385 10.7422 13.8594C10.9089 14.3802 10.9948 14.9271 11 15.5V16H10V15.5C10 14.8802 9.88281 14.2969 9.64844 13.75C9.41406 13.2031 9.09115 12.7266 8.67969 12.3203C8.26823 11.9141 7.79167 11.5938 7.25 11.3594C6.70833 11.125 6.125 11.0052 5.5 11C4.88021 11 4.29688 11.1172 3.75 11.3516C3.20312 11.5859 2.72656 11.9089 2.32031 12.3203C1.91406 12.7318 1.59375 13.2083 1.35938 13.75C1.125 14.2917 1.00521 14.875 1 15.5V16H0V15.5C0 14.9323 0.0833333 14.3854 0.25 13.8594C0.416667 13.3333 0.65625 12.8464 0.96875 12.3984C1.28125 11.9505 1.65104 11.5547 2.07812 11.2109C2.50521 10.8672 2.98438 10.5885 3.51562 10.375C3.28125 10.2135 3.07031 10.026 2.88281 9.8125C2.69531 9.59896 2.53646 9.36979 2.40625 9.125C2.27604 8.88021 2.17708 8.61979 2.10938 8.34375C2.04167 8.06771 2.00521 7.78646 2 7.5C2 7.01562 2.09115 6.5625 2.27344 6.14062C2.45573 5.71875 2.70573 5.34896 3.02344 5.03125C3.34115 4.71354 3.71094 4.46354 4.13281 4.28125C4.55469 4.09896 5.01042 4.00521 5.5 4C5.98438 4 6.4375 4.09115 6.85938 4.27344C7.28125 4.45573 7.65104 4.70573 7.96875 5.02344C8.28646 5.34115 8.53646 5.71094 8.71875 6.13281C8.90104 6.55469 8.99479 7.01042 9 7.5C9 7.78646 8.96615 8.0651 8.89844 8.33594C8.83073 8.60677 8.72917 8.86719 8.59375 9.11719C8.45833 9.36719 8.29948 9.59896 8.11719 9.8125C7.9349 10.026 7.72396 10.2135 7.48438 10.375ZM5.5 10C5.84375 10 6.16667 9.9349 6.46875 9.80469C6.77083 9.67448 7.03385 9.4974 7.25781 9.27344C7.48177 9.04948 7.66146 8.78385 7.79688 8.47656C7.93229 8.16927 8 7.84375 8 7.5C8 7.15625 7.9349 6.83333 7.80469 6.53125C7.67448 6.22917 7.49479 5.96615 7.26562 5.74219C7.03646 5.51823 6.77083 5.33854 6.46875 5.20312C6.16667 5.06771 5.84375 5 5.5 5C5.15625 5 4.83333 5.0651 4.53125 5.19531C4.22917 5.32552 3.96354 5.50521 3.73438 5.73438C3.50521 5.96354 3.32552 6.22917 3.19531 6.53125C3.0651 6.83333 3 7.15625 3 7.5C3 7.84375 3.0651 8.16667 3.19531 8.46875C3.32552 8.77083 3.5026 9.03646 3.72656 9.26562C3.95052 9.49479 4.21615 9.67448 4.52344 9.80469C4.83073 9.9349 5.15625 10 5.5 10ZM16 0V8H14L11 11V8H10V7H12V8.58594L13.5859 7H15V1H5V2.79688C4.83333 2.81771 4.66667 2.84375 4.5 2.875C4.33333 2.90625 4.16667 2.95312 4 3.01562V0H16Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.5938 14.6953L19.5 24L12 18.2344L4.5 24L7.40625 14.6953L0 9H9.1875L12 0L14.8125 9H24L16.5938 14.6953Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

View File

@@ -15,6 +15,8 @@
"activationEvents": [
"onDashboardOpen",
"onCommand:sqlmigration.start",
"onCommand:sqlmigration.newsupportrequest",
"onCommand:sqlmigration.sendfeedback",
"onCommand:sqlmigration.openNotebooks"
],
"main": "./out/main",
@@ -33,6 +35,18 @@
"category": "%migration-command-category%",
"icon": "./images/migration.svg"
},
{
"command": "sqlmigration.newsupportrequest",
"title": "%new-support-request-command%",
"category": "%migration-command-category%",
"icon": "./images/newSupportRequest.svg"
},
{
"command": "sqlmigration.sendfeedback",
"title": "%send-feedback-command%",
"category": "%migration-command-category%",
"icon": "./images/sendFeedback.svg"
},
{
"command": "sqlmigration.openNotebooks",
"title": "%migration-notebook-command-title%",
@@ -58,7 +72,9 @@
"col": 0,
"widget": {
"tasks-widget": [
"sqlmigration.start"
"sqlmigration.start",
"sqlmigration.newsupportrequest",
"sqlmigration.sendfeedback"
]
}
},

View File

@@ -5,5 +5,7 @@
"migration-dashboard-title": "Azure SQL Migration",
"migration-dashboard-tasks": "Migration Tasks",
"migration-command-category": "Azure SQL Migration",
"start-migration-command": "Migrate to Azure SQL"
"start-migration-command": "Migrate to Azure SQL",
"new-support-request-command": "New support request",
"send-feedback-command": "Feedback"
}

View File

@@ -30,6 +30,10 @@ export class IconPathHelper {
public static cancel: IconPath;
public static warning: IconPath;
public static info: IconPath;
public static newSupportRequest: IconPath;
public static sendFeedback: IconPath;
public static solidBlueStar: IconPath;
public static blueStar: IconPath;
public static setExtensionContext(context: vscode.ExtensionContext) {
IconPathHelper.copy = {
@@ -108,5 +112,21 @@ export class IconPathHelper {
light: context.asAbsolutePath('images/info.svg'),
dark: context.asAbsolutePath('images/infoBox.svg')
};
IconPathHelper.newSupportRequest = {
light: context.asAbsolutePath('images/newSupportRequest.svg'),
dark: context.asAbsolutePath('images/newSupportRequest.svg')
};
IconPathHelper.sendFeedback = {
light: context.asAbsolutePath('images/sendFeedback.svg'),
dark: context.asAbsolutePath('images/sendFeedback.svg')
};
IconPathHelper.solidBlueStar = {
light: context.asAbsolutePath('images/solidBlueStar.svg'),
dark: context.asAbsolutePath('images/solidBlueStar.svg')
};
IconPathHelper.blueStar = {
light: context.asAbsolutePath('images/blueStar.svg'),
dark: context.asAbsolutePath('images/blueStar.svg')
};
}
}

View File

@@ -315,6 +315,8 @@ export const CANCEL_MIGRATION_CONFIRMATION = localize('sql.cancel.migration.conf
export const YES = localize('sql.migration.yes', "Yes");
export const NO = localize('sql.migration.no', "No");
export const NEW_SUPPORT_REQUEST = localize('sql.migration.newsupportrequest', "New support request");
//Migration confirm cutover dialog
export const BUSINESS_CRITICAL_INFO = localize('sql.migration.bc.info', "Managed Instance migration cutover for Business Critical service tier can take significantly longer than General Purpose as three secondary replicas have to be seeded for Always On High Availability group. This operation duration depends on the size of data. Seeding speed in 90% of cases is 220 GB/hour or higher.");
export const CUTOVER_HELP_MAIN = localize('sql.migration.cutover.help.main', "When you are ready to do the migration cutover, perform the following steps to complete the database migration. Please note that the database is ready for cutover only after a full backup has been restored on the target Azure SQL Database Managed Instance.");
@@ -421,3 +423,15 @@ export function WARNINGS_COUNT(totalCount: number): string {
export const AUTHENTICATION_TYPE = localize('sql.migration.authentication.type', "Authentication Type");
export const SQL_LOGIN = localize('sql.migration.sql.login', "SQL Login");
export const WINDOWS_AUTHENTICATION = localize('sql.migration.windows.auth', "Windows Authentication");
export const FEEDBACK_DIALOG_SUBMIT_BUTTON = localize('sql.migration.feedback.submit.button', "Submit");
export const FEEDBACK_DIALOG_CANCEL_BUTTON = localize('sql.migration.feedback.cancel.button', "Cancel");
export const FEEDBACK_DIALOG_TITLE = localize('sql.migration.feedback.title', "Submit Feedback");
export const FEEDBACK_DIALOG_HEADING = localize('sql.migration.feedback.heading', "Overall, how satisfied or dissatisfied are you with Azure SQL Migration experience?");
export const FEEDBACK_DIALOG_PLACEHOLDER = localize('sql.migration.feedback.placeholder', "We appreciate your feedback. How can we improve? (optional).");
export const FEEDBACK_DIALOG_RATING_1 = localize('sql.migration.feedback.rating.one', "Rating one out of five");
export const FEEDBACK_DIALOG_RATING_2 = localize('sql.migration.feedback.rating.two', "Rating two out of five");
export const FEEDBACK_DIALOG_RATING_3 = localize('sql.migration.feedback.rating.three', "Rating three out of five");
export const FEEDBACK_DIALOG_RATING_4 = localize('sql.migration.feedback.rating.four', "Rating four out of five");
export const FEEDBACK_DIALOG_RATING_5 = localize('sql.migration.feedback.rating.five', 'Rating five out of five');
export const FEEDBACK_DIALOG_SENT_MESSAGE = localize('sql.migration.feedback.sent.message', 'Thank you for the feedback! Your feedback was submitted successfully.');

View File

@@ -0,0 +1,184 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { IconPathHelper } from '../constants/iconPathHelper';
import * as loc from '../constants/strings';
import { sendSqlMigrationActionEvent, TelemetryActions, TelemetryViews } from '../telemtery';
export class FeedbackDialog {
private static readonly DialogName: string = 'FeedbackDialog';
private _dialog!: azdata.window.Dialog;
private _buttonGroup!: azdata.FlexContainer;
private _isOpen: boolean = false;
private _feedbackRating?: number;
private _feedbackText?: string;
constructor() {
}
public async openDialog() {
if (!this._isOpen) {
this._isOpen = true;
this._dialog = azdata.window.createModelViewDialog(
'',
FeedbackDialog.DialogName,
360,
'normal',
'below');
this._dialog.registerContent(async view => {
const headingGroup = view.modelBuilder
.flexContainer()
.withItems([
view.modelBuilder
.image()
.withProperties<azdata.ImageComponentProperties>({
iconPath: IconPathHelper.sendFeedback,
iconHeight: 32,
iconWidth: 32,
height: 32,
width: 32,
})
.component(),
view.modelBuilder
.text()
.withProperties<azdata.TextComponentProperties>({
value: loc.FEEDBACK_DIALOG_HEADING,
CSSStyles: {
'margin': '0 0 0 10px',
},
})
.component(),
])
.withLayout({
width: '100%',
alignContent: 'flex-start',
flexFlow: 'row',
})
.component();
this._buttonGroup = view.modelBuilder
.flexContainer()
.withItems([
this._createFeedbackButton(view, 0, loc.FEEDBACK_DIALOG_RATING_1),
this._createFeedbackButton(view, 1, loc.FEEDBACK_DIALOG_RATING_2),
this._createFeedbackButton(view, 2, loc.FEEDBACK_DIALOG_RATING_3),
this._createFeedbackButton(view, 3, loc.FEEDBACK_DIALOG_RATING_4),
this._createFeedbackButton(view, 4, loc.FEEDBACK_DIALOG_RATING_5),
])
.withLayout({
alignContent: 'flex-start',
flexFlow: 'row',
})
.withProperties<azdata.ComponentProperties>({
display: 'inline-flex',
ariaLabel: loc.FEEDBACK_DIALOG_HEADING,
})
.component();
const feedbackInputBox = view.modelBuilder
.inputBox()
.withProperties<azdata.InputBoxProperties>({
rows: 3,
inputType: 'text',
multiline: true,
placeHolder: loc.FEEDBACK_DIALOG_PLACEHOLDER,
CSSStyles: {
'white-space': 'normal!important',
},
})
.component();
feedbackInputBox.onTextChanged(
value => this._feedbackText = value);
const formModel = view.modelBuilder
.formContainer()
.withFormItems([{
components: [
{
component: headingGroup,
},
{
component: this._buttonGroup,
},
{
component: feedbackInputBox,
}
],
title: ''
}])
.withLayout({ width: '100%' })
.component();
await view.initializeModel(formModel);
await this._buttonGroup.items[0].focus();
});
this._dialog.okButton.label = loc.FEEDBACK_DIALOG_SUBMIT_BUTTON;
this._dialog.okButton.onClick(async () => await this._execute());
this._dialog.cancelButton.label = loc.FEEDBACK_DIALOG_CANCEL_BUTTON;
this._dialog.cancelButton.onClick(() => this._cancel());
azdata.window.openDialog(this._dialog);
}
}
private async _execute() {
sendSqlMigrationActionEvent(
TelemetryViews.FeedbackDialog,
TelemetryActions.SendFeedback,
{
'FeedbackRating': this._feedbackRating?.toString() || '',
'FeedbackMessage': this._feedbackText?.substr(0, 500) || '',
});
await vscode.window.showInformationMessage(loc.FEEDBACK_DIALOG_SENT_MESSAGE);
this._isOpen = false;
}
private _cancel() {
this._isOpen = false;
}
private _createFeedbackButton(view: azdata.ModelView, index: number, ariaLabel: string): azdata.Component {
const button = view.modelBuilder
.button()
.withProperties<azdata.ButtonProperties>({
ariaLabel: ariaLabel,
height: '26px',
width: '26px',
buttonType: azdata.ButtonType.Normal,
iconHeight: '24px',
iconWidth: '24px',
iconPath: IconPathHelper.blueStar,
CSSStyles: {
'margin': '0 10px 0 0',
'padding': '0 0 0 0',
},
})
.component();
button.onDidClick(() => this._updateButtonImages(index));
return button;
}
private _updateButtonImages(index: number): void {
const items: azdata.Component[] = this._buttonGroup?.items || [];
this._feedbackRating = index;
for (let i = 0; i < items.length; i++) {
const btn = items[i] as azdata.ButtonComponent;
btn.iconPath = i <= index
? IconPathHelper.solidBlueStar
: IconPathHelper.blueStar;
}
}
}

View File

@@ -24,6 +24,7 @@ export class MigrationCutoverDialog {
private _cancelButton!: azdata.ButtonComponent;
private _refreshLoader!: azdata.LoadingComponent;
private _copyDatabaseMigrationDetails!: azdata.ButtonComponent;
private _newSupportRequest!: azdata.ButtonComponent;
private _serverName!: azdata.TextComponent;
private _serverVersion!: azdata.TextComponent;
@@ -371,7 +372,6 @@ export class MigrationCutoverDialog {
flex: '0'
});
this._refreshButton = this._view.modelBuilder.button().withProps({
iconPath: IconPathHelper.refresh,
iconHeight: '16px',
@@ -419,6 +419,30 @@ export class MigrationCutoverDialog {
}
});
// create new support request button. Hiding button until sql migration support has been setup.
this._newSupportRequest = this._view.modelBuilder.button().withProps({
label: loc.NEW_SUPPORT_REQUEST,
iconPath: IconPathHelper.newSupportRequest,
iconHeight: '16px',
iconWidth: '16px',
height: '20px',
width: '140px',
display: 'none' // remove when support requests are setup for sql migrations
}).component();
this._newSupportRequest.onDidClick(async (e) => {
const serviceId = this._model._migration.controller.id;
const supportUrl = `https://portal.azure.com/#resource${serviceId}/supportrequest`;
await vscode.env.openExternal(vscode.Uri.parse(supportUrl));
});
headerActions.addItem(this._newSupportRequest, {
flex: '0',
CSSStyles: {
'margin-left': '5px'
}
});
this._refreshLoader = this._view.modelBuilder.loadingComponent().withProps({
loading: false,
height: '15px'

View File

@@ -10,6 +10,7 @@ import { promises as fs } from 'fs';
import * as loc from './constants/strings';
import { MigrationNotebookInfo, NotebookPathHelper } from './constants/notebookPathHelper';
import { IconPathHelper } from './constants/iconPathHelper';
import { FeedbackDialog } from './dialog/feedbackDialog';
import { DashboardWidget } from './dashboard/sqlServerDashboard';
import { MigrationLocalStorage } from './models/migrationLocalStorage';
@@ -56,6 +57,12 @@ class SQLMigration {
}),
azdata.tasks.registerTask('sqlmigration.start', async () => {
await this.launchMigrationWizard();
}),
azdata.tasks.registerTask('sqlmigration.newsupportrequest', async () => {
await this.launchNewSupportRequest();
}),
azdata.tasks.registerTask('sqlmigration.sendfeedback', async () => {
await this.sendFeedback();
})
];
@@ -77,6 +84,16 @@ class SQLMigration {
await wizardController.openWizard(connectionId);
}
async launchNewSupportRequest(): Promise<void> {
await vscode.env.openExternal(vscode.Uri.parse(
`https://portal.azure.com/#blade/Microsoft_Azure_Support/HelpAndSupportBlade/newsupportrequest`));
}
async sendFeedback(): Promise<void> {
const dialog = new FeedbackDialog();
await dialog.openDialog();
}
stop(): void {
}

View File

@@ -723,8 +723,11 @@ export class MigrationStateModel implements Model, vscode.Disposable {
vscode.window.showInformationMessage(localize("sql.migration.starting.migration.message", 'Starting migration for database {0} to {1} - {2}', this._migrationDbs[i], this._targetServerInstance.name, this._targetDatabaseNames[i]));
}
} catch (e) {
vscode.window.showErrorMessage(
localize('sql.migration.starting.migration.error', "Error message: '{0}'. stack:'{1}'",
e.message,
e.stack));
console.log(e);
vscode.window.showInformationMessage(e);
}
vscode.commands.executeCommand('sqlmigration.refreshMigrationTiles');

View File

@@ -18,12 +18,17 @@ export enum TelemetryViews {
AssessmentsDialog = 'AssessmentsDialog',
MigrationCutoverDialog = 'MigrationCutoverDialog',
MigrationStatusDialog = 'MigrationStatusDialog',
AssessmentsPage = 'AssessmentsPage'
AssessmentsPage = 'AssessmentsPage',
FeedbackDialog = 'FeedbackDialog',
}
export function sendSqlMigrationActionEvent(telemetryView: string, telemetryAction: string, additionalProps: TelemetryEventProperties, additionalMeasurements: TelemetryEventMeasures): void {
export enum TelemetryActions {
SendFeedback = 'SendFeedback',
}
export function sendSqlMigrationActionEvent(telemetryView: TelemetryViews, telemetryAction: TelemetryActions, additionalProps?: TelemetryEventProperties, additionalMeasurements?: TelemetryEventMeasures): void {
TelemetryReporter.createActionEvent(telemetryView, telemetryAction)
.withAdditionalProperties(additionalProps)
.withAdditionalMeasurements(additionalMeasurements)
.withAdditionalProperties(additionalProps || {})
.withAdditionalMeasurements(additionalMeasurements || {})
.send();
}