mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-18 11:01:36 -05:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
201174e293 | ||
|
|
dc2f6235a1 | ||
|
|
0824c779db | ||
|
|
e002ad3b6a | ||
|
|
8a570069f8 | ||
|
|
bfe44c1621 | ||
|
|
b17882a1c1 | ||
|
|
f309979126 | ||
|
|
5a0490e81f |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,5 +1,21 @@
|
||||
# Change Log
|
||||
|
||||
## Version 1.1.3
|
||||
* Release date: October 18, 2018
|
||||
* Release status: General Availability
|
||||
|
||||
## What's new in this version
|
||||
* Introducing the Azure Resource Explorer to browse Azure SQL Databases
|
||||
* Improve Object Explorer and Query Editor connectivity robustness
|
||||
* SQL Server 2019 and SQL Agent extension improvements
|
||||
|
||||
## Contributions and "thank you"
|
||||
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
|
||||
|
||||
* philoushka for `center the icon #2760`
|
||||
* anthonypants for `Typo #2775`
|
||||
* kstolte for `Fix Invalid Configuration in Launch.json #2789`
|
||||
* kstolte for `Fixing a reference to SQL Ops Studio #2788`
|
||||
|
||||
## Version 1.0.0
|
||||
* Release date: September 24, 2018
|
||||
|
||||
18
README.md
18
README.md
@@ -4,16 +4,16 @@
|
||||
|
||||
Azure Data Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
|
||||
|
||||
**Download Azure Data Studio August Public Preview**
|
||||
**Download the latest Azure Data Studio release**
|
||||
|
||||
Platform | Link
|
||||
-- | --
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2024683
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2024680
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2024677
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2024675
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2024672
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2024668
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2030731
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2030736
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2030738
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2030741
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2030746
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2030750
|
||||
|
||||
Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions.
|
||||
|
||||
@@ -61,6 +61,10 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro
|
||||
## Contributions and "Thank You"
|
||||
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
|
||||
|
||||
* philoushka for `center the icon #2760`
|
||||
* anthonypants for `Typo #2775`
|
||||
* kstolte for `Fix Invalid Configuration in Launch.json #2789`
|
||||
* kstolte for `Fixing a reference to SQL Ops Studio #2788`
|
||||
* AlexFsmn `Feature: Ability to add connection name #2332`
|
||||
* AlexFsmn `Disabled connection name input when connecting to a server. #2566`
|
||||
* SebastianPfliegel `Added more saveAsCsv options #2099`
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.5.0-alpha.43",
|
||||
"version": "1.5.0-alpha.46",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "azuredatastudio",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.1",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Dimension, EventType, $, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { $ as quickBuilder } from 'vs/base/browser/builder';
|
||||
import { $ as qb } from 'vs/base/browser/builder';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionOptions, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
@@ -146,18 +146,18 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
}
|
||||
|
||||
if (this._shownTab) {
|
||||
this._tabMap.get(this._shownTab).label.classList.remove('active');
|
||||
this._tabMap.get(this._shownTab).header.classList.remove('active');
|
||||
qb(this._tabMap.get(this._shownTab).label).removeClass('active');
|
||||
qb(this._tabMap.get(this._shownTab).header).removeClass('active');
|
||||
this._tabMap.get(this._shownTab).header.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
|
||||
this._shownTab = id;
|
||||
this.tabHistory.push(id);
|
||||
quickBuilder(this.body).empty();
|
||||
qb(this.body).empty();
|
||||
let tab = this._tabMap.get(this._shownTab);
|
||||
this.body.setAttribute('aria-labelledby', tab.identifier);
|
||||
tab.label.classList.add('active');
|
||||
tab.header.classList.add('active');
|
||||
qb(tab.label).addClass('active');
|
||||
qb(tab.header).addClass('active');
|
||||
tab.header.setAttribute('aria-selected', 'true');
|
||||
tab.view.render(this.body);
|
||||
this._onTabChange.fire(id);
|
||||
@@ -168,11 +168,11 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
public removeTab(tab: PanelTabIdentifier) {
|
||||
let actualTab = this._tabMap.get(tab);
|
||||
quickBuilder(actualTab.header).destroy();
|
||||
qb(actualTab.header).destroy();
|
||||
if (actualTab.view.remove) {
|
||||
actualTab.view.remove();
|
||||
}
|
||||
quickBuilder(this._tabMap.get(tab).header).destroy();
|
||||
qb(this._tabMap.get(tab).header).destroy();
|
||||
this._tabMap.delete(tab);
|
||||
if (this._shownTab === tab) {
|
||||
this._shownTab = undefined;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -124,7 +124,7 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
try {
|
||||
// Create file path and file URI
|
||||
let objectName = schemaName ? schemaName + '.' + tableName : tableName;
|
||||
let filePath = this.createEditDataFileName(objectName);
|
||||
let filePath = this.createPrefixedSqlFilePath(objectName);
|
||||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||
|
||||
// Create a sql document pane with accoutrements
|
||||
@@ -265,45 +265,26 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
////// Private functions
|
||||
|
||||
private createUntitledSqlFilePath(): string {
|
||||
let sqlFileName = (counter: number): string => {
|
||||
return `${untitledFilePrefix}${counter}`;
|
||||
};
|
||||
|
||||
let counter = 1;
|
||||
// Get document name and check if it exists
|
||||
let filePath = sqlFileName(counter);
|
||||
while (fs.existsSync(filePath)) {
|
||||
counter++;
|
||||
filePath = sqlFileName(counter);
|
||||
}
|
||||
|
||||
// check if this document name already exists in any open documents
|
||||
let untitledEditors = this._untitledEditorService.getAll();
|
||||
while (untitledEditors.find(x => x.getName().toUpperCase() === filePath.toUpperCase())) {
|
||||
counter++;
|
||||
filePath = sqlFileName(counter);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
return this.createPrefixedSqlFilePath(untitledFilePrefix);
|
||||
}
|
||||
|
||||
private createEditDataFileName(tableName: string): string {
|
||||
let editDataFileName = (counter: number): string => {
|
||||
return encodeURIComponent(`${tableName}_${counter}`);
|
||||
private createPrefixedSqlFilePath(prefix: string): string {
|
||||
let prefixFileName = (counter: number): string => {
|
||||
return `${prefix}_${counter}`;
|
||||
};
|
||||
|
||||
let counter = 1;
|
||||
// Get document name and check if it exists
|
||||
let filePath = editDataFileName(counter);
|
||||
let filePath = prefixFileName(counter);
|
||||
while (fs.existsSync(filePath)) {
|
||||
counter++;
|
||||
filePath = editDataFileName(counter);
|
||||
filePath = prefixFileName(counter);
|
||||
}
|
||||
|
||||
let untitledEditors = this._untitledEditorService.getAll();
|
||||
while (untitledEditors.find(x => x.getName().toUpperCase() === filePath.toUpperCase())) {
|
||||
counter++;
|
||||
filePath = editDataFileName(counter);
|
||||
filePath = prefixFileName(counter);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
|
||||
1
src/sql/sqlops.proposed.d.ts
vendored
1
src/sql/sqlops.proposed.d.ts
vendored
@@ -58,6 +58,7 @@ declare module 'sqlops' {
|
||||
|
||||
export class TreeComponentItem extends vscode.TreeItem {
|
||||
checked?: boolean;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ComponentBuilder<T extends Component> {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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[];
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ ${this.description}
|
||||
|
||||
if (!changelogUrl) {
|
||||
if (this.type === LocalExtensionType.System) {
|
||||
return TPromise.as('Please check the [VS Code Release Notes](command:update.showCurrentReleaseNotes) for changes to the built-in extensions.');
|
||||
return TPromise.as('Please check the [Azure Data Studio Release Notes](command:update.showCurrentReleaseNotes) for changes to the built-in extensions.');
|
||||
}
|
||||
|
||||
return TPromise.wrapError<string>(new Error('not available'));
|
||||
|
||||
Reference in New Issue
Block a user