diff --git a/src/sql/workbench/browser/modal/calloutDialog.ts b/src/sql/workbench/browser/modal/calloutDialog.ts index a4c296c8b7..57331884a4 100644 --- a/src/sql/workbench/browser/modal/calloutDialog.ts +++ b/src/sql/workbench/browser/modal/calloutDialog.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/calloutDialog'; import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; -import { IDialogProperties, Modal, DialogWidth } from 'sql/workbench/browser/modal/modal'; +import { IDialogProperties, Modal, DialogWidth, DialogPosition } from 'sql/workbench/browser/modal/modal'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -20,6 +20,7 @@ export abstract class CalloutDialog extends Modal { title: string, width: DialogWidth, dialogProperties: IDialogProperties, + dialogPosition: DialogPosition, @IThemeService themeService: IThemeService, @ILayoutService layoutService: ILayoutService, @IAdsTelemetryService telemetryService: IAdsTelemetryService, @@ -40,7 +41,7 @@ export abstract class CalloutDialog extends Modal { contextKeyService, { dialogStyle: 'callout', - dialogPosition: 'below', + dialogPosition: dialogPosition, dialogProperties: dialogProperties, width: width }); diff --git a/src/sql/workbench/browser/modal/media/calloutDialog.css b/src/sql/workbench/browser/modal/media/calloutDialog.css index 66498918fa..527cc1e8ce 100644 --- a/src/sql/workbench/browser/modal/media/calloutDialog.css +++ b/src/sql/workbench/browser/modal/media/calloutDialog.css @@ -48,6 +48,12 @@ top: -0.2em; transform: rotate(135deg); } +.callout-arrow.from-above:before { + border-width: 0.5em; + left: 2em; + bottom: -0.2em; + transform: rotate(-45deg); +} .callout-arrow.from-left:before { background-color: var(--bodybackground); height: 26px; diff --git a/src/sql/workbench/browser/modal/modal.ts b/src/sql/workbench/browser/modal/modal.ts index f96e3b8c60..16ad1f9d8c 100644 --- a/src/sql/workbench/browser/modal/modal.ts +++ b/src/sql/workbench/browser/modal/modal.ts @@ -60,7 +60,7 @@ export interface IModalDialogStyles { export type DialogWidth = 'narrow' | 'medium' | 'wide' | number | string; export type DialogStyle = 'normal' | 'flyout' | 'callout'; -export type DialogPosition = 'left' | 'below'; +export type DialogPosition = 'left' | 'below' | 'above'; export interface IDialogProperties { xPos: number, @@ -438,7 +438,15 @@ export abstract class Modal extends Disposable implements IThemable { dialogWidth = this._modalOptions.width; } - if (this._modalOptions.dialogPosition === 'below') { + if (this._modalOptions.dialogPosition === 'above') { + if (this._modalOptions.dialogProperties) { + this._modalDialog.style.left = `${this._modalOptions.dialogProperties.xPos - this._modalOptions.dialogProperties.width}px`; + this._modalDialog.style.top = `${this._modalOptions.dialogProperties.yPos - 235}px`; + } else { + this._modalDialog.style.left = `${this._modalOptions.positionX}px`; + this._modalDialog.style.top = `${this._modalOptions.positionY - 235}px`; + } + } else if (this._modalOptions.dialogPosition === 'below') { if (this._modalOptions.dialogProperties) { this._modalDialog.style.left = `${this._modalOptions.dialogProperties.xPos - this._modalOptions.dialogProperties.width}px`; this._modalDialog.style.top = `${this._modalOptions.dialogProperties.yPos + (this._modalOptions.dialogProperties.height)}px`; @@ -446,9 +454,7 @@ export abstract class Modal extends Disposable implements IThemable { this._modalDialog.style.left = `${this._modalOptions.positionX}px`; this._modalDialog.style.top = `${this._modalOptions.positionY}px`; } - } - - if (this._modalOptions.dialogPosition === 'left') { + } else if (this._modalOptions.dialogPosition === 'left') { if (this._modalOptions.dialogProperties) { this._modalDialog.style.left = `${this._modalOptions.positionX - (dialogWidth + this._modalOptions.dialogProperties.width)}px`; this._modalDialog.style.top = `${this._modalOptions.positionY - this._modalOptions.dialogProperties.height * 2}px`; diff --git a/src/sql/workbench/contrib/notebook/browser/calloutDialog/imageCalloutDialog.ts b/src/sql/workbench/contrib/notebook/browser/calloutDialog/imageCalloutDialog.ts index 6a0a1ebff7..ab3b0240e5 100644 --- a/src/sql/workbench/contrib/notebook/browser/calloutDialog/imageCalloutDialog.ts +++ b/src/sql/workbench/contrib/notebook/browser/calloutDialog/imageCalloutDialog.ts @@ -24,7 +24,7 @@ import { Deferred } from 'sql/base/common/promise'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox'; import { RadioButton } from 'sql/base/browser/ui/radioButton/radioButton'; -import { DialogWidth } from 'sql/workbench/api/common/sqlExtHostTypes'; +import { DialogPosition, DialogWidth } from 'sql/workbench/api/common/sqlExtHostTypes'; import { attachModalDialogStyler } from 'sql/workbench/common/styler'; import { escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils'; @@ -51,6 +51,7 @@ export class ImageCalloutDialog extends CalloutDialog constructor( title: string, dialogProperties: IDialogProperties, + dialogPosition: DialogPosition, private readonly _defaultLabel: string = '', @IContextViewService private readonly _contextViewService: IContextViewService, @IThemeService themeService: IThemeService, @@ -57,6 +58,7 @@ export class LinkCalloutDialog extends CalloutDialog title, DEFAULT_DIALOG_WIDTH, dialogProperties, + dialogPosition, themeService, layoutService, telemetryService, diff --git a/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts b/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts index 0a691d8649..5fdaa78fa1 100644 --- a/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts @@ -278,11 +278,12 @@ export class MarkdownToolbarComponent extends AngularDisposable { const triggerHeight = triggerElement.offsetHeight; const triggerWidth = triggerElement.offsetWidth; const dialogProperties = { xPos: triggerPosX, yPos: triggerPosY, width: triggerWidth, height: triggerHeight }; + const dialogPosition = window.innerHeight - triggerPosY < 250 ? 'above' : 'below'; let calloutOptions; if (type === MarkdownButtonType.LINK_PREVIEW) { const defaultLabel = this.getCurrentSelectionText(); - this._linkCallout = this._instantiationService.createInstance(LinkCalloutDialog, this.insertLinkHeading, dialogProperties, defaultLabel); + this._linkCallout = this._instantiationService.createInstance(LinkCalloutDialog, this.insertLinkHeading, dialogProperties, dialogPosition, defaultLabel); this._linkCallout.render(); calloutOptions = await this._linkCallout.open(); } diff --git a/src/sql/workbench/contrib/notebook/test/calloutDialog/linkCalloutDialog.test.ts b/src/sql/workbench/contrib/notebook/test/calloutDialog/linkCalloutDialog.test.ts index 3cdf72661f..546df4440e 100644 --- a/src/sql/workbench/contrib/notebook/test/calloutDialog/linkCalloutDialog.test.ts +++ b/src/sql/workbench/contrib/notebook/test/calloutDialog/linkCalloutDialog.test.ts @@ -26,7 +26,7 @@ suite('Link Callout Dialog', function (): void { }); test('Should return empty markdown on cancel', async function (): Promise { - let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'defaultLabel', + let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', 'defaultLabel', undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); linkCalloutDialog.render(); @@ -47,7 +47,7 @@ suite('Link Callout Dialog', function (): void { test('Should return expected values on insert', async function (): Promise { const defaultLabel = 'defaultLabel'; const sampleUrl = 'https://www.aka.ms/azuredatastudio'; - let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, defaultLabel, + let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', defaultLabel, undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); linkCalloutDialog.render(); @@ -70,7 +70,7 @@ suite('Link Callout Dialog', function (): void { test('Should return expected values on insert when escape necessary', async function (): Promise { const defaultLabel = 'default[]Label'; const sampleUrl = 'https://www.aka.ms/azuredatastudio()'; - let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, defaultLabel, + let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', defaultLabel, undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); linkCalloutDialog.render();