Compare commits

..

3 Commits
1.1.4 ... 1.1.3

Author SHA1 Message Date
Karl Burtram
b17882a1c1 Bump agent and import extension versions (#2949) 2018-10-17 21:41:18 -07:00
Gene Lee
f309979126 Added feature to disable checkbox of checkboxTreeNode (#2942) 2018-10-17 19:26:56 -07:00
Matt Irvine
5a0490e81f Display multi-line messages correctly in query results (#2935) 2018-10-17 15:43:00 -07:00
24 changed files with 164 additions and 291 deletions

View File

@@ -2,7 +2,7 @@
"name": "agent",
"displayName": "SQL Server Agent",
"description": "Manage and troubleshoot SQL Server Agent jobs",
"version": "0.33.0",
"version": "0.34.0",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",

View File

@@ -2,7 +2,7 @@
"name": "import",
"displayName": "SQL Server Import",
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
"version": "0.2.0",
"version": "0.3.0",
"publisher": "Microsoft",
"preview": true,
"engines": {

View File

@@ -1,18 +1,18 @@
{
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "1.5.0-alpha.48",
"version": "1.5.0-alpha.43",
"downloadFileNames": {
"Windows_86": "win-x86-netcoreapp2.2.zip",
"Windows_64": "win-x64-netcoreapp2.2.zip",
"OSX": "osx-x64-netcoreapp2.2.tar.gz",
"CentOS_7": "rhel-x64-netcoreapp2.2.tar.gz",
"Debian_8": "rhel-x64-netcoreapp2.2.tar.gz",
"Fedora_23": "rhel-x64-netcoreapp2.2.tar.gz",
"OpenSUSE_13_2": "rhel-x64-netcoreapp2.2.tar.gz",
"RHEL_7": "rhel-x64-netcoreapp2.2.tar.gz",
"SLES_12_2": "rhel-x64-netcoreapp2.2.tar.gz",
"Ubuntu_14": "rhel-x64-netcoreapp2.2.tar.gz",
"Ubuntu_16": "rhel-x64-netcoreapp2.2.tar.gz"
"Windows_86": "win-x86-netcoreapp2.1.zip",
"Windows_64": "win-x64-netcoreapp2.1.zip",
"OSX": "osx-x64-netcoreapp2.1.tar.gz",
"CentOS_7": "rhel-x64-netcoreapp2.1.tar.gz",
"Debian_8": "rhel-x64-netcoreapp2.1.tar.gz",
"Fedora_23": "rhel-x64-netcoreapp2.1.tar.gz",
"OpenSUSE_13_2": "rhel-x64-netcoreapp2.1.tar.gz",
"RHEL_7": "rhel-x64-netcoreapp2.1.tar.gz",
"SLES_12_2": "rhel-x64-netcoreapp2.1.tar.gz",
"Ubuntu_14": "rhel-x64-netcoreapp2.1.tar.gz",
"Ubuntu_16": "rhel-x64-netcoreapp2.1.tar.gz"
},
"installDirectory": "../sqltoolsservice/{#platform#}/{#version#}",
"executableFiles": ["MicrosoftSqlToolsServiceLayer.exe", "MicrosoftSqlToolsServiceLayer"]

View File

@@ -1,6 +1,6 @@
{
"name": "azuredatastudio",
"version": "1.1.4",
"version": "1.1.3",
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
"author": {
"name": "Microsoft Corporation"

View File

@@ -63,7 +63,7 @@ export class TabbedPanel extends Disposable implements IThemable {
private tabHistory: string[] = [];
constructor(container: HTMLElement, private options: IPanelOptions = defaultOptions) {
constructor(private container: HTMLElement, private options: IPanelOptions = defaultOptions) {
super();
this.parent = $('.tabbedPanel');
container.appendChild(this.parent);
@@ -87,13 +87,6 @@ export class TabbedPanel extends Disposable implements IThemable {
this.parent.appendChild(this.body);
}
public dispose() {
this.header.remove();
this.tabList.remove();
this.body.remove();
this.parent.remove();
}
public contains(tab: IPanelTab): boolean {
return this._tabMap.has(tab.identifier);
}

View File

@@ -10,9 +10,10 @@ import * as TelemetryUtils from 'sql/common/telemetryUtilities';
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { memoize, unmemoize } from 'sql/base/common/decorators';
import { mixin } from 'sql/base/common/objects';
import { LegendPosition, ChartType, defaultChartConfig, IChartConfig, IDataSet, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { LegendPosition, DataDirection, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import * as colors from 'vs/platform/theme/common/colorRegistry';
import { Color } from 'vs/base/common/color';
import * as types from 'vs/base/common/types';
import { Disposable } from 'vs/base/common/lifecycle';
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
@@ -21,6 +22,51 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
declare var Chart: any;
export function customMixin(destination: any, source: any, overwrite?: boolean): any {
if (types.isObject(source)) {
mixin(destination, source, overwrite, customMixin);
} else if (types.isArray(source)) {
for (let i = 0; i < source.length; i++) {
if (destination[i]) {
mixin(destination[i], source[i], overwrite, customMixin);
} else {
destination[i] = source[i];
}
}
} else {
destination = source;
}
return destination;
}
export interface IDataSet {
data: Array<number>;
label?: string;
}
export interface IPointDataSet {
data: Array<{ x: number | string, y: number }>;
label?: string;
fill: boolean;
backgroundColor?: Color;
}
export interface IChartConfig {
colorMap?: { [column: string]: string };
labelFirstColumn?: boolean;
legendPosition?: LegendPosition;
dataDirection?: DataDirection;
columnsAsLabels?: boolean;
showTopNData?: number;
}
export const defaultChartConfig: IChartConfig = {
labelFirstColumn: true,
columnsAsLabels: true,
legendPosition: LegendPosition.Top,
dataDirection: DataDirection.Vertical
};
@Component({
template: ` <div style="display: block; width: 100%; height: 100%; position: relative">
<canvas #canvas *ngIf="_isDataAvailable && _hasInit"

View File

@@ -3,11 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Color } from 'vs/base/common/color';
import * as types from 'vs/base/common/types';
import { mixin } from 'sql/base/common/objects';
export enum ChartType {
Bar = 'bar',
Doughnut = 'doughnut',
@@ -34,49 +29,4 @@ export enum LegendPosition {
export enum DataType {
Number = 'number',
Point = 'point'
}
export function customMixin(destination: any, source: any, overwrite?: boolean): any {
if (types.isObject(source)) {
mixin(destination, source, overwrite, customMixin);
} else if (types.isArray(source)) {
for (let i = 0; i < source.length; i++) {
if (destination[i]) {
mixin(destination[i], source[i], overwrite, customMixin);
} else {
destination[i] = source[i];
}
}
} else {
destination = source;
}
return destination;
}
export interface IDataSet {
data: Array<number>;
label?: string;
}
export interface IPointDataSet {
data: Array<{ x: number | string, y: number }>;
label?: string;
fill: boolean;
backgroundColor?: Color;
}
export interface IChartConfig {
colorMap?: { [column: string]: string };
labelFirstColumn?: boolean;
legendPosition?: LegendPosition;
dataDirection?: DataDirection;
columnsAsLabels?: boolean;
showTopNData?: number;
}
export const defaultChartConfig: IChartConfig = {
labelFirstColumn: true,
columnsAsLabels: true,
legendPosition: LegendPosition.Top,
dataDirection: DataDirection.Vertical
};
}

View File

@@ -3,9 +3,9 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ChartInsight } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import { ChartInsight, customMixin, IChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import { mixin } from 'sql/base/common/objects';
import { ChartType, IChartConfig, customMixin } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import * as colors from 'vs/platform/theme/common/colorRegistry';

View File

@@ -5,10 +5,11 @@
import { mixin } from 'vs/base/common/objects';
import { defaultChartConfig, IDataSet, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import BarChart, { IBarChartConfig } from './barChart.component';
import { memoize, unmemoize } from 'sql/base/common/decorators';
import { clone } from 'sql/base/common/objects';
import { ChartType, DataType, defaultChartConfig, IDataSet, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ChartType, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
export interface ILineConfig extends IBarChartConfig {
dataType?: DataType;

View File

@@ -3,9 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { defaultChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import LineChart, { ILineConfig } from './lineChart.component';
import { clone } from 'sql/base/common/objects';
import { ChartType, defaultChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { mixin } from 'vs/base/common/objects';

View File

@@ -3,9 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { defaultChartConfig, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import LineChart, { ILineConfig } from './lineChart.component';
import { clone } from 'sql/base/common/objects';
import { ChartType, defaultChartConfig, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { mixin } from 'vs/base/common/objects';
import { Color } from 'vs/base/common/color';

View File

@@ -71,6 +71,13 @@ export class TreeDataTemplate extends Disposable {
}
}
public set enableCheckbox(value: boolean) {
if (value === undefined) {
value = true;
}
this._checkbox.disabled = !value;
}
public get checkbox(): HTMLInputElement {
return this._checkbox;
}
@@ -155,6 +162,7 @@ export class TreeComponentRenderer extends Disposable implements IRenderer {
templateData.label.textContent = label;
templateData.root.title = label;
templateData.checkboxState = this.getCheckboxState(treeNode);
templateData.enableCheckbox = treeNode.enabled;
}
private getCheckboxState(treeNode: ITreeComponentItem): TreeCheckboxState {

View File

@@ -18,8 +18,7 @@ export enum ControlType {
combo,
numberInput,
input,
checkbox,
dateInput
checkbox
}
export interface IChartOption {
@@ -116,20 +115,6 @@ const xAxisMaxInput: IChartOption = {
default: undefined
};
const xAxisMinDateInput: IChartOption = {
label: localize('xAxisMinDate', 'X Axis Minimum Date'),
type: ControlType.dateInput,
configEntry: 'xAxisMin',
default: undefined
};
const xAxisMaxDateInput: IChartOption = {
label: localize('xAxisMaxDate', 'X Axis Maximum Date'),
type: ControlType.dateInput,
configEntry: 'xAxisMax',
default: undefined
};
const dataTypeInput: IChartOption = {
label: localize('dataTypeLabel', 'Data Type'),
type: ControlType.combo,
@@ -165,11 +150,7 @@ export const ChartOptions: IChartOptions = {
[ChartType.TimeSeries]: [
legendInput,
yAxisLabelInput,
yAxisMinInput,
yAxisMaxInput,
xAxisLabelInput,
xAxisMinDateInput,
xAxisMaxDateInput,
xAxisLabelInput
],
[ChartType.Bar]: [
dataDirectionOption,

View File

@@ -18,7 +18,7 @@ export class ChartTab implements IPanelTab {
public readonly identifier = 'ChartTab';
public readonly view: ChartView;
constructor( @IInstantiationService instantiationService: IInstantiationService) {
constructor(@IInstantiationService instantiationService: IInstantiationService) {
this.view = instantiationService.createInstance(ChartView);
}
@@ -26,11 +26,7 @@ export class ChartTab implements IPanelTab {
this.view.queryRunner = runner;
}
public chart(dataId: { batchId: number, resultId: number }): void {
public chart(dataId: { batchId: number, resultId: number}): void {
this.view.chart(dataId);
}
public dispose() {
this.view.dispose();
}
}

View File

@@ -24,7 +24,7 @@ import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { Builder } from 'vs/base/browser/builder';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { attachSelectBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -43,7 +43,7 @@ declare class Proxy {
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
export class ChartView extends Disposable implements IPanelView {
export class ChartView implements IPanelView {
private insight: Insight;
private _queryRunner: QueryRunner;
private _data: IInsightData;
@@ -82,7 +82,6 @@ export class ChartView extends Disposable implements IPanelView {
@IInstantiationService private _instantiationService: IInstantiationService,
@IContextMenuService contextMenuService: IContextMenuService
) {
super();
this.taskbarContainer = $('div.taskbar-container');
this.taskbar = new Taskbar(this.taskbarContainer, contextMenuService);
this.optionsControl = $('div.options-container');
@@ -325,24 +324,6 @@ export class ChartView extends Disposable implements IPanelView {
};
this.optionDisposables.push(attachInputBoxStyler(numberInput, this._themeService));
break;
case ControlType.dateInput:
let dateInput = new InputBox(optionContainer, this._contextViewService, { type: 'date' });
dateInput.value = value || '';
dateInput.onDidChange(e => {
if (this.options[option.configEntry] !== e) {
this.options[option.configEntry] = e;
if (this.insight) {
this.insight.options = this.options;
}
}
});
setFunc = (val: string) => {
if (!isUndefinedOrNull(val)) {
dateInput.value = val;
}
};
this.optionDisposables.push(attachInputBoxStyler(dateInput, this._themeService));
break;
}
this.optionMap[option.configEntry] = { element: optionContainer, set: setFunc };
container.appendChild(optionContainer);

View File

@@ -7,7 +7,7 @@
import { Chart as ChartJs } from 'chart.js';
import { mixin } from 'sql/base/common/objects';
import { mixin } from 'vs/base/common/objects';
import { localize } from 'vs/nls';
import * as colors from 'vs/platform/theme/common/colorRegistry';
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
@@ -15,28 +15,10 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { IInsightOptions, IInsight } from './interfaces';
import { ChartType, DataDirection, LegendPosition, DataType, IPointDataSet, customMixin } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ChartType, DataDirection, LegendPosition } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
const noneLineGraphs = [ChartType.Doughnut, ChartType.Pie];
const timeSeriesScales = {
scales: {
xAxes: [{
type: 'time',
display: true,
ticks: {
autoSkip: false,
maxRotation: 45,
minRotation: 45
}
}],
yAxes: [{
display: true,
}]
}
};
const defaultOptions: IInsightOptions = {
type: ChartType.Bar,
dataDirection: DataDirection.Horizontal
@@ -48,8 +30,6 @@ export class Graph implements IInsight {
private chartjs: ChartJs;
private _data: IInsightData;
private originalType: ChartType;
public static readonly types = [ChartType.Bar, ChartType.Doughnut, ChartType.HorizontalBar, ChartType.Line, ChartType.Pie, ChartType.Scatter, ChartType.TimeSeries];
public readonly types = Graph.types;
@@ -103,51 +83,37 @@ export class Graph implements IInsight {
labels = data.rows.map(row => row[0]);
}
if (this.originalType === ChartType.TimeSeries) {
let dataSetMap: { [label: string]: IPointDataSet } = {};
this._data.rows.map(row => {
if (row && row.length >= 3) {
let legend = row[0];
if (!dataSetMap[legend]) {
dataSetMap[legend] = { label: legend, data: [], fill: false };
}
dataSetMap[legend].data.push({ x: row[1], y: Number(row[2]) });
}
});
chartData = Object.values(dataSetMap);
} else {
if (this.options.dataDirection === DataDirection.Horizontal) {
if (this.options.labelFirstColumn) {
chartData = data.rows.map((row) => {
return {
data: row.map(item => Number(item)).slice(1),
label: row[0]
};
});
} else {
chartData = data.rows.map((row, i) => {
return {
data: row.map(item => Number(item)),
label: localize('series', 'Series {0}', i)
};
});
}
if (this.options.dataDirection === DataDirection.Horizontal) {
if (this.options.labelFirstColumn) {
chartData = data.rows.map((row) => {
return {
data: row.map(item => Number(item)).slice(1),
label: row[0]
};
});
} else {
if (this.options.columnsAsLabels) {
chartData = data.rows[0].slice(1).map((row, i) => {
return {
data: data.rows.map(row => Number(row[i + 1])),
label: data.columns[i + 1]
};
});
} else {
chartData = data.rows[0].slice(1).map((row, i) => {
return {
data: data.rows.map(row => Number(row[i + 1])),
label: localize('series', 'Series {0}', i + 1)
};
});
}
chartData = data.rows.map((row, i) => {
return {
data: row.map(item => Number(item)),
label: localize('series', 'Series {0}', i)
};
});
}
} else {
if (this.options.columnsAsLabels) {
chartData = data.rows[0].slice(1).map((row, i) => {
return {
data: data.rows.map(row => Number(row[i + 1])),
label: data.columns[i + 1]
};
});
} else {
chartData = data.rows[0].slice(1).map((row, i) => {
return {
data: data.rows.map(row => Number(row[i + 1])),
label: localize('series', 'Series {0}', i + 1)
};
});
}
}
@@ -221,35 +187,6 @@ export class Graph implements IInsight {
color: gridLines
}
}];
if (this.originalType === ChartType.TimeSeries) {
retval = mixin(retval, timeSeriesScales, true, customMixin);
if (options.xAxisMax) {
retval = mixin(retval, {
scales: {
xAxes: [{
type: 'time',
time: {
max: options.xAxisMax
}
}],
}
}, true, customMixin);
}
if (options.xAxisMin) {
retval = mixin(retval, {
scales: {
xAxes: [{
type: 'time',
time: {
min: options.xAxisMin
}
}],
}
}, true, customMixin);
}
}
}
retval.legend = <ChartJs.ChartLegendOptions>{
@@ -271,12 +208,6 @@ export class Graph implements IInsight {
public set options(options: IInsightOptions) {
this._options = options;
this.originalType = options.type as ChartType;
if (this.options.type === ChartType.TimeSeries) {
this.options.type = ChartType.Line;
this.options.dataType = DataType.Point;
this.options.dataDirection = DataDirection.Horizontal;
}
this.data = this._data;
}

View File

@@ -7,7 +7,7 @@
import { Graph } from './graphInsight';
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { DataDirection, ChartType, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { DataDirection, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ImageInsight } from './imageInsight';
import { TableInsight } from './tableInsight';
import { IInsightOptions, IInsight, InsightType, IInsightCtor } from './interfaces';
@@ -16,7 +16,6 @@ import { CountInsight } from './countInsight';
import { Builder } from 'vs/base/browser/builder';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Dimension } from 'vs/base/browser/dom';
import { deepClone } from 'vs/base/common/objects';
const defaultOptions: IInsightOptions = {
type: ChartType.Bar,
@@ -48,13 +47,13 @@ export class Insight {
}
public set options(val: IInsightOptions) {
this._options = deepClone(val);
this._options = val;
if (this.insight) {
// check to see if we need to change the insight type
if (!this.insight.types.includes(this.options.type)) {
if (!this.insight.types.includes(val.type)) {
this.buildInsight();
} else {
this.insight.options = this.options;
this.insight.options = val;
}
}
}

View File

@@ -21,7 +21,6 @@ import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugi
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
import * as sqlops from 'sqlops';
import * as pretty from 'pretty-data';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -478,27 +477,7 @@ class GridTable<T> extends Disposable implements IView {
if (column && (column.isXml || column.isJson)) {
this.runner.getQueryRows(event.cell.row, 1, this.resultSet.batchId, this.resultSet.id).then(d => {
let value = d.resultSubset.rows[0][event.cell.cell - 1];
let content = value.displayValue;
if (column.isXml) {
try {
content = pretty.pd.xml(content);
} catch (e) {
// If Xml fails to parse, fall back on original Xml content
}
} else {
let jsonContent: string = undefined;
try {
jsonContent = JSON.parse(content);
} catch (e) {
// If Json fails to parse, fall back on original Json content
}
if (jsonContent) {
// If Json content was valid and parsed, pretty print content to a string
content = JSON.stringify(jsonContent, undefined, 4);
}
}
let input = this.untitledEditorService.createOrGet(undefined, column.isXml ? 'xml' : 'json', content);
let input = this.untitledEditorService.createOrGet(undefined, column.isXml ? 'xml' : 'json', value.displayValue);
this.editorService.openEditor(input);
});
}

View File

@@ -74,8 +74,9 @@ export class MessagePanelState {
}
export class MessagePanel extends ViewletPanel {
private messageLineCountMap = new Map<IResultMessage, number>();
private ds = new MessageDataSource();
private renderer = new MessageRenderer();
private renderer = new MessageRenderer(this.messageLineCountMap);
private model = new Model();
private controller: MessageController;
private container = $('div message-tree').getHTMLElement();
@@ -143,29 +144,40 @@ export class MessagePanel extends ViewletPanel {
private onMessage(message: IResultMessage | IResultMessage[]) {
let hasError = false;
let lines: number;
if (isArray(message)) {
hasError = message.find(e => e.isError) ? true : false;
lines = message.reduce((currentTotal, resultMessage) => currentTotal + this.countMessageLines(resultMessage), 0);
this.model.messages.push(...message);
} else {
hasError = message.isError;
lines = this.countMessageLines(message);
this.model.messages.push(message);
}
this.maximumBodySize += lines * 22;
if (hasError) {
this.setExpanded(true);
}
if (this.state.scrollPosition) {
this.tree.refresh(this.model).then(() => {
this.tree.setScrollPosition(1);
// Restore the previous scroll position when switching between tabs
this.tree.setScrollPosition(this.state.scrollPosition);
});
} else {
const previousScrollPosition = this.tree.getScrollPosition();
this.tree.refresh(this.model).then(() => {
// Scroll to the end if the user was already at the end otherwise leave the current scroll position
if (previousScrollPosition === 1) {
this.tree.setScrollPosition(1);
}
});
}
this.maximumBodySize = this.model.messages.length * 22;
}
private countMessageLines(resultMessage: IResultMessage): number {
let lines = resultMessage.message.split('\n').length;
this.messageLineCountMap.set(resultMessage, lines);
return lines;
}
private reset() {
@@ -220,8 +232,15 @@ class MessageDataSource implements IDataSource {
}
class MessageRenderer implements IRenderer {
constructor(private messageLineCountMap: Map<IResultMessage, number>) {
}
getHeight(tree: ITree, element: any): number {
return 22;
const lineHeight = 22;
if (this.messageLineCountMap.has(element)) {
return lineHeight * this.messageLineCountMap.get(element);
}
return lineHeight;
}
getTemplateId(tree: ITree, element: any): string {
@@ -258,7 +277,7 @@ class MessageRenderer implements IRenderer {
renderElement(tree: ITree, element: IResultMessage, templateId: string, templateData: IMessageTemplate | IBatchTemplate): void {
if (templateId === TemplateIds.MESSAGE || templateId === TemplateIds.ERROR) {
let data: IMessageTemplate = templateData;
data.message.innerText = element.message.replace(/(\r\n|\n|\r)/g, ' ');
data.message.innerText = element.message;
} else if (templateId === TemplateIds.BATCH) {
let data = templateData as IBatchTemplate;
data.timeStamp.innerText = element.time;

View File

@@ -18,9 +18,9 @@ import { PanelViewlet } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import * as DOM from 'vs/base/browser/dom';
import { once, anyEvent } from 'vs/base/common/event';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
class ResultsView extends Disposable implements IPanelView {
class ResultsView implements IPanelView {
private panelViewlet: PanelViewlet;
private gridPanel: GridPanel;
private messagePanel: MessagePanel;
@@ -30,10 +30,10 @@ class ResultsView extends Disposable implements IPanelView {
private _state: ResultsViewState;
constructor(private instantiationService: IInstantiationService) {
super();
this.panelViewlet = this._register(this.instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false }));
this.gridPanel = this._register(this.instantiationService.createInstance(GridPanel, { title: nls.localize('gridPanel', 'Results'), id: 'gridPanel' }));
this.messagePanel = this._register(this.instantiationService.createInstance(MessagePanel, { title: nls.localize('messagePanel', 'Messages'), minimumBodySize: 0, id: 'messagePanel' }));
this.panelViewlet = this.instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false });
this.gridPanel = this.instantiationService.createInstance(GridPanel, { title: nls.localize('gridPanel', 'Results'), id: 'gridPanel' });
this.messagePanel = this.instantiationService.createInstance(MessagePanel, { title: nls.localize('messagePanel', 'Messages'), minimumBodySize: 0, id: 'messagePanel' });
this.gridPanel.render();
this.messagePanel.render();
this.panelViewlet.create(this.container).then(() => {
@@ -147,13 +147,9 @@ class ResultsTab implements IPanelTab {
public set queryRunner(runner: QueryRunner) {
this.view.queryRunner = runner;
}
public dispose() {
dispose(this.view);
}
}
export class QueryResultsView extends Disposable {
export class QueryResultsView {
private _panelView: TabbedPanel;
private _input: QueryResultsInput;
private resultsTab: ResultsTab;
@@ -167,17 +163,16 @@ export class QueryResultsView extends Disposable {
@IInstantiationService instantiationService: IInstantiationService,
@IQueryModelService private queryModelService: IQueryModelService
) {
super();
this.resultsTab = this._register(new ResultsTab(instantiationService));
this.chartTab = this._register(new ChartTab(instantiationService));
this._panelView = this._register(new TabbedPanel(container, { showHeaderWhenSingleView: false }));
this.qpTab = this._register(new QueryPlanTab());
this.resultsTab = new ResultsTab(instantiationService);
this.chartTab = new ChartTab(instantiationService);
this._panelView = new TabbedPanel(container, { showHeaderWhenSingleView: false });
this.qpTab = new QueryPlanTab();
this._panelView.pushTab(this.resultsTab);
this._register(this._panelView.onTabChange(e => {
this._panelView.onTabChange(e => {
if (this.input) {
this.input.state.activeTab = e;
}
}));
});
}
public style() {

View File

@@ -10,8 +10,8 @@ import { IPanelView, IPanelTab } from 'sql/base/browser/ui/panel/panel';
import { Dimension } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import * as UUID from 'vs/base/common/uuid';
import { Builder } from 'vs/base/browser/builder';
import { dispose, Disposable } from 'vs/base/common/lifecycle';
export class QueryPlanState {
xml: string;
@@ -25,10 +25,6 @@ export class QueryPlanTab implements IPanelTab {
constructor() {
this.view = new QueryPlanView();
}
public dispose() {
dispose(this.view);
}
}
export class QueryPlanView implements IPanelView {
@@ -48,12 +44,6 @@ export class QueryPlanView implements IPanelView {
this.container.style.overflow = 'scroll';
}
dispose() {
this.container.remove();
this.qp = undefined;
this.container = undefined;
}
public layout(dimension: Dimension): void {
this.container.style.width = dimension.width + 'px';
this.container.style.height = dimension.height + 'px';

View File

@@ -58,6 +58,7 @@ declare module 'sqlops' {
export class TreeComponentItem extends vscode.TreeItem {
checked?: boolean;
enabled?: boolean;
}
export interface ComponentBuilder<T extends Component> {

View File

@@ -164,7 +164,7 @@ export class ExtHostTreeView<T> extends vsTreeExt.ExtHostTreeView<T> {
protected createTreeItem(element: T, extensionTreeItem: sqlops.TreeComponentItem, parent?: vsTreeExt.TreeNode): ITreeComponentItem {
let item = super.createTreeItem(element, extensionTreeItem, parent);
item = Object.assign({}, item, { checked: extensionTreeItem.checked });
item = Object.assign({}, item, { checked: extensionTreeItem.checked, enabled: extensionTreeItem.enabled });
return item;
}
}

View File

@@ -7,6 +7,7 @@ import { ITreeViewDataProvider, ITreeItem } from 'vs/workbench/common/views';
export interface ITreeComponentItem extends ITreeItem {
checked?: boolean;
enabled?: boolean;
onCheckedChanged?: (checked: boolean) => void;
children?: ITreeComponentItem[];
}