Strict null scripting (#12126)

* strict null scripting

* fix compile

* fix tests

* fix icon
This commit is contained in:
Anthony Dresser
2020-09-04 18:04:08 -07:00
committed by GitHub
parent bbe5b98a2c
commit 503090856a
35 changed files with 427 additions and 403 deletions

6
src/sql/azdata.d.ts vendored
View File

@@ -322,7 +322,7 @@ declare module 'azdata' {
export interface IConnectionProfile extends ConnectionInfo {
connectionName?: string;
serverName: string;
databaseName: string;
databaseName?: string;
userName: string;
password: string;
authenticationType: string;
@@ -413,7 +413,7 @@ declare module 'azdata' {
/**
* database name
*/
databaseName: string;
databaseName?: string;
/**
* user name
*/
@@ -749,7 +749,7 @@ declare module 'azdata' {
}
export interface ScriptingParamDetails {
filePath: string;
filePath?: string;
scriptCompatibilityOption: string;
targetDatabaseEngineEdition: string;
targetDatabaseEngineType: string;

View File

@@ -8,6 +8,8 @@ import * as azdata from 'azdata';
import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import type { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IconPath } from 'sql/platform/connection/common/connectionProfile';
export const SERVICE_ID = 'capabilitiesService';
export const HOST_NAME = 'azdata';
@@ -20,6 +22,7 @@ export const clientCapabilities = {
export interface ConnectionProviderProperties {
providerId: string;
iconPath?: URI | IconPath | { id: string, path: IconPath }[]
displayName: string;
notebookKernelAlias?: string;
azureResource?: string;

View File

@@ -13,7 +13,13 @@ import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilit
import { isString } from 'vs/base/common/types';
import { deepClone } from 'vs/base/common/objects';
import * as Constants from 'sql/platform/connection/common/constants';
import { find } from 'vs/base/common/arrays';
import { URI } from 'vs/base/common/uri';
export interface IconPath {
light: URI;
dark: URI;
}
// Concrete implementation of the IConnectionProfile interface
@@ -29,6 +35,8 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
public groupId?: string;
public saveProfile: boolean;
public iconPath?: IconPath;
public isDisconnecting: boolean = false;
public constructor(
@@ -49,7 +57,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
let capabilities = this.capabilitiesService.getCapabilities(model.providerName);
if (capabilities && capabilities.connection && capabilities.connection.connectionOptions) {
const options = capabilities.connection.connectionOptions;
let appNameOption = find(options, option => option.specialValueType === interfaces.ConnectionOptionSpecialType.appName);
let appNameOption = options.find(option => option.specialValueType === interfaces.ConnectionOptionSpecialType.appName);
if (appNameOption) {
let appNameKey = appNameOption.name;
this.options[appNameKey] = Constants.applicationName;
@@ -87,9 +95,13 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
}
private static nullCheckEqualsIgnoreCase(a: string, b: string) {
let bothNull: boolean = !a && !b;
return bothNull ? bothNull : equalsIgnoreCase(a, b);
private static nullCheckEqualsIgnoreCase(a?: string, b?: string) {
if (a && !b || b && !a) {
return false;
} else {
let bothNull: boolean = !a && !b;
return bothNull ? bothNull : equalsIgnoreCase(a!, b!);
}
}
public generateNewId() {

View File

@@ -152,7 +152,7 @@ export class ConnectionStatusManager {
//Check if the existing connection database name is different the one in the summary
if (connection.connectionProfile.databaseName !== summary.connectionSummary.databaseName) {
//Add the ownerUri with database name to the map if not already exists
connection.connectionProfile.databaseName = summary.connectionSummary.databaseName;
connection.connectionProfile.databaseName = summary.connectionSummary.databaseName!;
let prefix = Utils.getUriPrefix(summary.ownerUri);
let ownerUriWithDbName = Utils.generateUriWithPrefix(connection.connectionProfile, prefix);
if (!(ownerUriWithDbName in this._connections)) {
@@ -186,7 +186,7 @@ export class ConnectionStatusManager {
let connection = this._connections[changedConnInfo.connectionUri];
if (connection && connection.connectionProfile) {
connection.connectionProfile.serverName = changedConnInfo.connection.serverName;
connection.connectionProfile.databaseName = changedConnInfo.connection.databaseName;
connection.connectionProfile.databaseName = changedConnInfo.connection.databaseName!;
connection.connectionProfile.userName = changedConnInfo.connection.userName;
return connection.connectionProfile;
}

View File

@@ -137,6 +137,6 @@ export function findProfileInGroup(og: IConnectionProfile, groups: ConnectionPro
export function isMaster(profile: IConnectionProfile): boolean {
// TODO: the connection profile should have a property to indicate whether the connection is a server connection or database connection
// created issue to track the problem: https://github.com/Microsoft/azuredatastudio/issues/5193.
return (profile.providerName === mssqlProviderName && profile.databaseName.toLowerCase() === 'master')
|| (profile.providerName.toLowerCase() === 'pgsql' && profile.databaseName.toLowerCase() === 'postgres');
return (profile.providerName === mssqlProviderName && profile.databaseName?.toLowerCase() === 'master')
|| (profile.providerName.toLowerCase() === 'pgsql' && profile.databaseName?.toLowerCase() === 'postgres');
}

View File

@@ -138,7 +138,7 @@ suite('SQL ConnectionProfileInfo tests', () => {
assert.equal(conn.serverName, undefined);
conn.connectionName = connectionProfile.connectionName!;
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.databaseName = connectionProfile.databaseName!;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;

View File

@@ -141,7 +141,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
assert.equal(conn.serverName, undefined);
conn.connectionName = connectionProfile.connectionName!;
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.databaseName = connectionProfile.databaseName!;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;
@@ -157,7 +157,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
let conn = new ProviderConnectionInfo(capabilitiesService, mssqlProviderName);
assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.databaseName = connectionProfile.databaseName!;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;

View File

@@ -95,7 +95,7 @@ export class DashboardInput extends EditorInput {
private isMasterMssql(): boolean {
return this.connectionProfile.providerName === mssqlProviderName
&& this.connectionProfile.databaseName.toLowerCase() === 'master';
&& this.connectionProfile.databaseName?.toLowerCase() === 'master';
}
public get uri(): string | undefined {

View File

@@ -27,8 +27,8 @@ export class ScriptSelectAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return scriptSelect(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService
@@ -52,8 +52,8 @@ export class ScriptExecuteAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return script(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService,
@@ -79,8 +79,8 @@ export class ScriptAlterAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return script(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService,
@@ -105,8 +105,8 @@ export class EditDataAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return scriptEditSelect(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService
@@ -130,8 +130,8 @@ export class ScriptCreateAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return script(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService,
@@ -157,8 +157,8 @@ export class ScriptDeleteAction extends Action {
public async run(actionContext: BaseActionContext): Promise<boolean> {
return script(
actionContext.profile,
actionContext.object,
actionContext.profile!,
actionContext.object!,
this._connectionManagementService,
this._queryEditorService,
this._scriptingService,

View File

@@ -42,7 +42,7 @@ const targetDatabaseEngineEditionMap = {
*/
export async function scriptSelect(connectionProfile: IConnectionProfile, metadata: azdata.ObjectMetadata, connectionService: IConnectionManagementService, queryEditorService: IQueryEditorService, scriptingService: IScriptingService): Promise<boolean> {
const connectionResult = await connectionService.connectIfNotConnected(connectionProfile);
let paramDetails: azdata.ScriptingParamDetails = getScriptingParamDetails(connectionService, connectionResult, metadata);
let paramDetails = getScriptingParamDetails(connectionService, connectionResult, metadata)!;
const result = await scriptingService.script(connectionResult, metadata, ScriptOperation.Select, paramDetails);
if (result && result.script) {
const owner = await queryEditorService.newSqlEditor({ initalContent: result.script }, connectionProfile?.providerName);
@@ -68,8 +68,8 @@ export async function scriptSelect(connectionProfile: IConnectionProfile, metada
*/
export async function scriptEditSelect(connectionProfile: IConnectionProfile, metadata: azdata.ObjectMetadata, connectionService: IConnectionManagementService, queryEditorService: IQueryEditorService, scriptingService: IScriptingService): Promise<boolean> {
const connectionResult = await connectionService.connectIfNotConnected(connectionProfile);
let paramDetails: azdata.ScriptingParamDetails = getScriptingParamDetails(connectionService, connectionResult, metadata);
const result = await scriptingService.script(connectionResult, metadata, ScriptOperation.Select, paramDetails);
let paramDetails = getScriptingParamDetails(connectionService, connectionResult, metadata);
const result = await scriptingService.script(connectionResult, metadata, ScriptOperation.Select, paramDetails!);
if (result && result.script) {
const owner = await queryEditorService.newEditDataEditor(metadata.schema, metadata.name, result.script);
// Connect our editor
@@ -120,7 +120,7 @@ export async function script(connectionProfile: IConnectionProfile, metadata: az
operation: ScriptOperation,
errorMessageService: IErrorMessageService): Promise<boolean> {
const connectionResult = await connectionService.connectIfNotConnected(connectionProfile);
let paramDetails = getScriptingParamDetails(connectionService, connectionResult, metadata);
let paramDetails = getScriptingParamDetails(connectionService, connectionResult, metadata)!;
const result = await scriptingService.script(connectionResult, metadata, operation, paramDetails);
if (result) {
let script: string = result.script;
@@ -160,18 +160,21 @@ export async function script(connectionProfile: IConnectionProfile, metadata: az
}
}
function getScriptingParamDetails(connectionService: IConnectionManagementService, ownerUri: string, metadata: azdata.ObjectMetadata): azdata.ScriptingParamDetails {
let serverInfo: azdata.ServerInfo = getServerInfo(connectionService, ownerUri);
let paramDetails: azdata.ScriptingParamDetails = {
filePath: undefined,
scriptCompatibilityOption: scriptCompatibilityOptionMap[serverInfo.serverMajorVersion],
targetDatabaseEngineEdition: targetDatabaseEngineEditionMap[serverInfo.engineEditionId],
targetDatabaseEngineType: serverInfo.isCloud ? 'SqlAzure' : 'SingleInstance'
};
return paramDetails;
function getScriptingParamDetails(connectionService: IConnectionManagementService, ownerUri: string, metadata: azdata.ObjectMetadata): azdata.ScriptingParamDetails | undefined {
let serverInfo: azdata.ServerInfo | undefined = getServerInfo(connectionService, ownerUri);
if (serverInfo) {
let paramDetails: azdata.ScriptingParamDetails = {
filePath: undefined,
scriptCompatibilityOption: scriptCompatibilityOptionMap[serverInfo.serverMajorVersion as keyof typeof scriptCompatibilityOptionMap],
targetDatabaseEngineEdition: targetDatabaseEngineEditionMap[serverInfo.engineEditionId as keyof typeof targetDatabaseEngineEditionMap],
targetDatabaseEngineType: serverInfo.isCloud ? 'SqlAzure' : 'SingleInstance'
};
return paramDetails;
}
return undefined;
}
function getServerInfo(connectionService: IConnectionManagementService, ownerUri: string): azdata.ServerInfo {
function getServerInfo(connectionService: IConnectionManagementService, ownerUri: string): azdata.ServerInfo | undefined {
let connection: ConnectionManagementInfo = connectionService.getConnectionInfo(ownerUri);
return connection.serverInfo;
}

View File

@@ -31,7 +31,7 @@ export class ConnectionViewletPanel extends ViewPane {
public static readonly ID = 'dataExplorer.servers';
private _root: HTMLElement;
private _root?: HTMLElement;
private _serverTreeView: ServerTreeView;
private _addServerAction: IAction;
private _addServerGroupAction: IAction;
@@ -89,7 +89,7 @@ export class ConnectionViewletPanel extends ViewPane {
layoutBody(size: number): void {
this._serverTreeView.layout(size);
DOM.toggleClass(this._root, 'narrow', this._root.clientWidth < 300);
DOM.toggleClass(this._root!, 'narrow', this._root!.clientWidth < 300);
}
show(): void {

View File

@@ -87,9 +87,9 @@ export class DataExplorerViewlet extends Viewlet {
}
export class DataExplorerViewPaneContainer extends ViewPaneContainer {
private root: HTMLElement;
private root?: HTMLElement;
private dataSourcesBox: HTMLElement;
private dataSourcesBox?: HTMLElement;
constructor(
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@@ -125,7 +125,7 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
}
layout(dimension: Dimension): void {
toggleClass(this.root, 'narrow', dimension.width <= 300);
toggleClass(this.root!, 'narrow', dimension.width <= 300);
super.layout(new Dimension(dimension.width, dimension.height));
}
@@ -135,7 +135,7 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
getSecondaryActions(): IAction[] {
let menu = this.menuService.createMenu(MenuId.DataExplorerAction, this.contextKeyService);
let actions = [];
let actions: IAction[] = [];
menu.getActions({}).forEach(group => {
if (group[0] === 'secondary') {
actions.push(...group[1]);

View File

@@ -9,7 +9,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import Severity from 'vs/base/common/severity';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { ISelectionEvent, ITree } from 'vs/base/parts/tree/browser/tree';
import { Disposable } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -29,31 +29,30 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { Button } from 'sql/base/browser/ui/button/button';
import { attachButtonStyler } from 'sql/platform/theme/common/styler';
import { TreeNode, TreeItemCollapsibleState } from 'sql/workbench/services/objectExplorer/common/treeNode';
import { SERVER_GROUP_AUTOEXPAND_CONFIG } from 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution';
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
import { ServerTreeActionProvider } from 'sql/workbench/services/objectExplorer/browser/serverTreeActionProvider';
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
import { isHidden } from 'sql/base/browser/dom';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { startsWith } from 'vs/base/common/strings';
import { SERVER_GROUP_CONFIG } from 'sql/workbench/services/serverGroup/common/interfaces';
import { horizontalScrollingKey } from 'vs/platform/list/browser/listService';
import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { ITreeContextMenuEvent, ITreeEvent } from 'vs/base/browser/ui/tree/tree';
import { ObjectExplorerActionsContext } from 'sql/workbench/services/objectExplorer/browser/objectExplorerActions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { coalesce } from 'vs/base/common/arrays';
/**
* ServerTreeview implements the dynamic tree view.
*/
export class ServerTreeView extends Disposable implements IServerTreeView {
public messages: HTMLElement;
private _buttonSection: HTMLElement;
public messages?: HTMLElement;
private _buttonSection?: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
private _activeConnectionsFilterAction: ActiveConnectionsFilterAction;
private _tree: ITree | AsyncServerTree;
private _tree?: ITree | AsyncServerTree;
private _onSelectionOrFocusChange: Emitter<void>;
private _actionProvider: ServerTreeActionProvider;
@@ -81,7 +80,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
if (this._tree instanceof AsyncServerTree) {
// Refresh the tree input now that the capabilities are registered so that we can
// get the full ConnectionProfiles with the server info updated properly
const treeInput = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
const treeInput = TreeUpdateUtils.getTreeInput(this._connectionManagementService)!;
await this._tree.setInput(treeInput);
this._treeSelectionHandler.onTreeActionStateChange(false);
} else {
@@ -113,7 +112,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
public get tree(): ITree | AsyncServerTree {
return this._tree;
return this._tree!;
}
/**
@@ -159,14 +158,14 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
const horizontalScrollEnabled: boolean = this._configurationService.getValue(horizontalScrollingKey) || false;
this._tree = this._register(TreeCreationUtils.createServersTree(container, this._instantiationService, this._configurationService, horizontalScrollEnabled));
this._register(this._tree.onDidChangeSelection((event) => this.onSelected(event)));
this._register(this._tree.onDidChangeSelection((event: ISelectionEvent | ITreeEvent<ServerTreeElement>) => this.onSelected(event)));
this._register(this._tree.onDidBlur(() => this._onSelectionOrFocusChange.fire()));
this._register(this._tree.onDidChangeFocus(() => this._onSelectionOrFocusChange.fire()));
if (this._tree instanceof AsyncServerTree) {
this._register(this._tree.onContextMenu(e => this.onContextMenu(e)));
this._register(this._tree.onMouseDblClick(e => {
// Open dashboard on double click for server and database nodes
let connectionProfile: ConnectionProfile;
let connectionProfile: ConnectionProfile | undefined;
if (e.element instanceof ConnectionProfile) {
connectionProfile = e.element;
} else if (e.element instanceof TreeNode) {
@@ -212,16 +211,16 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
return new Promise<void>(async (resolve, reject) => {
await this.refreshTree();
const root = <ConnectionProfileGroup>this._tree.getInput();
const root = <ConnectionProfileGroup>this._tree!.getInput();
const expandGroups: boolean = this._configurationService.getValue(SERVER_GROUP_CONFIG)[SERVER_GROUP_AUTOEXPAND_CONFIG];
const expandGroups = this._configurationService.getValue<{ autoExpand: boolean }>(SERVER_GROUP_CONFIG).autoExpand;
if (expandGroups) {
if (this._tree instanceof AsyncServerTree) {
await Promise.all(ConnectionProfileGroup.getSubgroups(root).map(subgroup => {
return this._tree.expand(subgroup);
return this._tree!.expand(subgroup);
}));
} else {
await this._tree.expandAll(ConnectionProfileGroup.getSubgroups(root));
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(root));
}
}
@@ -238,7 +237,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
public isObjectExplorerConnectionUri(uri: string): boolean {
let isBackupRestoreUri: boolean = uri.indexOf(ConnectionUtils.ConnectionUriBackupIdAttributeName) >= 0 ||
uri.indexOf(ConnectionUtils.ConnectionUriRestoreIdAttributeName) >= 0;
return uri && startsWith(uri, ConnectionUtils.uriPrefixes.default) && !isBackupRestoreUri;
return !!uri && uri.startsWith(ConnectionUtils.uriPrefixes.default) && !isBackupRestoreUri;
}
private async handleAddConnectionProfile(newProfile?: IConnectionProfile): Promise<void> {
@@ -277,16 +276,16 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
}
const currentSelections = this._tree.getSelection();
const currentSelections = this._tree!.getSelection();
const currentSelectedElement = currentSelections && currentSelections.length >= 1 ? currentSelections[0] : undefined;
const newProfileIsSelected = currentSelectedElement && newProfile ? currentSelectedElement.id === newProfile.id : false;
if (newProfile && currentSelectedElement && !newProfileIsSelected) {
this._tree.clearSelection();
this._tree!.clearSelection();
}
await this.refreshTree();
if (newProfile && !newProfileIsSelected) {
await this._tree.reveal(newProfile);
this._tree.select(newProfile);
await this._tree!.reveal(newProfile);
this._tree!.select(newProfile);
}
}
@@ -304,11 +303,11 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
*/
private getConnectionInTreeInput(connectionId: string): ConnectionProfile | undefined {
if (this._tree instanceof AsyncServerTree) {
const root = this._tree.getInput();
const root = this._tree.getInput()!;
const connections = ConnectionProfileGroup.getConnectionsInGroup(root);
return connections.find(conn => conn.id === connectionId);
} else {
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService)!;
const connections = ConnectionProfileGroup.getConnectionsInGroup(root);
const results = connections.filter(con => {
if (connectionId === con.id) {
@@ -330,16 +329,16 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
if (this._tree instanceof AsyncServerTree) {
this._tree.rerender(element);
} else {
await this._tree.refresh(element);
await this._tree!.refresh(element);
}
await this._tree.expand(element);
await this._tree.reveal(element, 0.5);
await this._tree!.expand(element);
await this._tree!.reveal(element, 0.5);
this._treeSelectionHandler.onTreeActionStateChange(false);
}
}
public addObjectExplorerNodeAndRefreshTree(connection: IConnectionProfile): void {
hide(this.messages);
hide(this.messages!);
if (!this._objectExplorerService.getObjectExplorerNode(connection)) {
this._objectExplorerService.updateObjectExplorerNodes(connection).catch(e => errors.onUnexpectedError(e));
}
@@ -356,35 +355,35 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this._tree.collapse(conn);
await this.refreshTree();
} else {
await this._tree.collapse(conn);
return this._tree.refresh(conn);
await this._tree!.collapse(conn);
return this._tree!.refresh(conn);
}
}
}
}
public async refreshTree(): Promise<void> {
hide(this.messages);
hide(this.messages!);
this.clearOtherActions();
return TreeUpdateUtils.registeredServerUpdate(this._tree, this._connectionManagementService);
return TreeUpdateUtils.registeredServerUpdate(this._tree!, this._connectionManagementService);
}
public async refreshElement(element: ServerTreeElement): Promise<void> {
if (this._tree instanceof AsyncServerTree) {
return this._tree.updateChildren(element);
} else {
return this._tree.refresh(element);
return this._tree!.refresh(element);
}
}
/**
* Filter connections based on view (recent/active)
*/
private filterConnections(treeInput: ConnectionProfileGroup[], view: string): ConnectionProfileGroup[] {
private filterConnections(treeInput: ConnectionProfileGroup[] | undefined, view: string): ConnectionProfileGroup[] | undefined {
if (!treeInput || treeInput.length === 0) {
return undefined;
}
const result = treeInput.map(group => {
const result = coalesce(treeInput.map(group => {
// Keep active/recent connections and remove the rest
if (group.connections) {
group.connections = group.connections.filter(con => {
@@ -408,7 +407,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
return group;
}
return undefined;
});
}));
return result;
}
@@ -416,35 +415,35 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
* Set tree elements based on the view (recent/active)
*/
public showFilteredTree(view: string): void {
hide(this.messages);
hide(this.messages!);
// Clear other action views if user switched between two views
this.clearOtherActions(view);
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
let treeInput: ConnectionProfileGroup = null;
let treeInput: ConnectionProfileGroup | undefined = undefined;
if (root) {
// Filter results based on view
const filteredResults = this.filterConnections([root], view);
if (!filteredResults || !filteredResults[0]) {
show(this.messages);
this.messages.focus();
show(this.messages!);
this.messages!.focus();
} else {
treeInput = filteredResults[0];
}
this._tree.setInput(treeInput).then(async () => {
if (isHidden(this.messages)) {
this._tree.getFocus();
this._tree!.setInput(treeInput!).then(async () => {
if (isHidden(this.messages!)) {
this._tree!.getFocus();
if (this._tree instanceof AsyncServerTree) {
await Promise.all(ConnectionProfileGroup.getSubgroups(treeInput).map(subgroup => {
this._tree.expand(subgroup);
await Promise.all(ConnectionProfileGroup.getSubgroups(treeInput!).map(subgroup => {
this._tree!.expand(subgroup);
}));
} else {
await this._tree.expandAll(ConnectionProfileGroup.getSubgroups(treeInput));
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(treeInput!));
}
} else {
if (this._tree instanceof AsyncServerTree) {
this._tree.setFocus([]);
} else {
this._tree.clearFocus();
this._tree!.clearFocus();
}
}
}, errors.onUnexpectedError);
@@ -460,33 +459,33 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
if (!searchString) {
return;
}
hide(this.messages);
hide(this.messages!);
// Clear other actions if user searched during other views
this.clearOtherActions();
// Filter connections based on search
const filteredResults = this.searchConnections(searchString);
if (!filteredResults || filteredResults.length === 0) {
show(this.messages);
this.messages.focus();
show(this.messages!);
this.messages!.focus();
}
// Add all connections to tree root and set tree input
const treeInput = new ConnectionProfileGroup('searchroot', undefined, 'searchroot', undefined, undefined);
treeInput.addConnections(filteredResults);
this._tree.setInput(treeInput).then(async () => {
if (isHidden(this.messages)) {
this._tree.getFocus();
this._tree!.setInput(treeInput).then(async () => {
if (isHidden(this.messages!)) {
this._tree!.getFocus();
if (this._tree instanceof AsyncServerTree) {
await Promise.all(ConnectionProfileGroup.getSubgroups(treeInput).map(subgroup => {
this._tree.expand(subgroup);
this._tree!.expand(subgroup);
}));
} else {
await this._tree.expandAll(ConnectionProfileGroup.getSubgroups(treeInput));
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(treeInput));
}
} else {
if (this._tree instanceof AsyncServerTree) {
this._tree.setFocus([]);
} else {
this._tree.clearFocus();
this._tree!.clearFocus();
}
}
}, errors.onUnexpectedError);
@@ -497,7 +496,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
*/
private searchConnections(searchString: string): ConnectionProfile[] {
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService)!;
const connections = ConnectionProfileGroup.getConnectionsInGroup(root);
const results = connections.filter(con => {
if (searchString && (searchString.length > 0)) {
@@ -542,7 +541,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
private onSelected(event: any): void {
this._treeSelectionHandler.onTreeSelect(event, this._tree, this._connectionManagementService, this._objectExplorerService, () => this._onSelectionOrFocusChange.fire());
this._treeSelectionHandler.onTreeSelect(event, this._tree!, this._connectionManagementService, this._objectExplorerService, () => this._onSelectionOrFocusChange.fire());
this._onSelectionOrFocusChange.fire();
}
@@ -550,21 +549,21 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
* set the layout of the view
*/
public layout(height: number): void {
this._tree.layout(height);
this._tree!.layout(height);
}
/**
* Get the list of selected nodes in the tree
*/
public getSelection(): any[] {
return this._tree.getSelection();
return this._tree!.getSelection();
}
/**
* Get whether the tree view currently has focus
*/
public isFocused(): boolean {
return this._tree.getHTMLElement() === document.activeElement;
return this._tree!.getHTMLElement() === document.activeElement;
}
/**
@@ -572,9 +571,9 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
*/
public async setExpandedState(element: ServerTreeElement, expandedState?: TreeItemCollapsibleState): Promise<void> {
if (expandedState === TreeItemCollapsibleState.Collapsed) {
return this._tree.collapse(element);
return this._tree!.collapse(element);
} else if (expandedState === TreeItemCollapsibleState.Expanded) {
return this._tree.expand(element);
return this._tree!.expand(element);
}
}
@@ -582,7 +581,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
* Reveal the given element in the tree
*/
public async reveal(element: ServerTreeElement): Promise<void> {
return this._tree.reveal(element);
return this._tree!.reveal(element);
}
/**
@@ -593,7 +592,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
if (this._tree instanceof AsyncServerTree) {
this._tree.setSelection([]);
} else {
this._tree.clearSelection();
this._tree!.clearSelection();
}
}
@@ -602,14 +601,14 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this._tree.setSelection(this._tree.getSelection().concat(element));
this._tree.reveal(element);
} else {
this._tree.select(element);
return this._tree.reveal(element);
this._tree!.select(element);
return this._tree!.reveal(element);
}
} else {
if (this._tree instanceof AsyncServerTree) {
this._tree.setSelection(this._tree.getSelection().filter(item => item !== element));
} else {
this._tree.deselect(element);
this._tree!.deselect(element);
}
}
}
@@ -621,7 +620,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
if (this._tree instanceof AsyncServerTree) {
return !this._tree.getNode(element).collapsed;
} else {
return this._tree.isExpanded(element);
return this._tree!.isExpanded(element);
}
}
@@ -630,42 +629,45 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
* Return actions in the context menu
*/
private onContextMenu(e: ITreeContextMenuEvent<ServerTreeElement>): boolean {
e.browserEvent.preventDefault();
e.browserEvent.stopPropagation();
this._tree.setSelection([e.element]);
if (e.element) {
e.browserEvent.preventDefault();
e.browserEvent.stopPropagation();
this._tree!.setSelection([e.element]);
let actionContext: any;
if (e.element instanceof TreeNode) {
let context = new ObjectExplorerActionsContext();
context.nodeInfo = e.element.toNodeInfo();
// Note: getting DB name before, but intentionally not using treeUpdateUtils.getConnectionProfile as it replaces
// the connection ID with a new one. This breaks a number of internal tasks
context.connectionProfile = e.element.getConnectionProfile().toIConnectionProfile();
context.connectionProfile.databaseName = e.element.getDatabaseName();
actionContext = context;
} else if (e.element instanceof ConnectionProfile) {
let context = new ObjectExplorerActionsContext();
context.connectionProfile = e.element.toIConnectionProfile();
context.isConnectionNode = true;
actionContext = context;
} else {
// TODO: because the connection group is used as a context object and isn't serializable,
// the Group-level context menu is not currently extensible
actionContext = e.element;
let actionContext: any;
if (e.element instanceof TreeNode) {
let context = new ObjectExplorerActionsContext();
context.nodeInfo = e.element.toNodeInfo();
// Note: getting DB name before, but intentionally not using treeUpdateUtils.getConnectionProfile as it replaces
// the connection ID with a new one. This breaks a number of internal tasks
context.connectionProfile = e.element.getConnectionProfile()!.toIConnectionProfile();
context.connectionProfile.databaseName = e.element.getDatabaseName();
actionContext = context;
} else if (e.element instanceof ConnectionProfile) {
let context = new ObjectExplorerActionsContext();
context.connectionProfile = e.element.toIConnectionProfile();
context.isConnectionNode = true;
actionContext = context;
} else {
// TODO: because the connection group is used as a context object and isn't serializable,
// the Group-level context menu is not currently extensible
actionContext = e.element;
}
this._contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => this._actionProvider.getActions(this._tree!, e.element!),
getKeyBinding: (action) => this._keybindingService.lookupKeybinding(action.id),
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
this._tree!.domFocus();
}
},
getActionsContext: () => (actionContext)
});
return true;
}
this._contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => this._actionProvider.getActions(this._tree, e.element),
getKeyBinding: (action) => this._keybindingService.lookupKeybinding(action.id),
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
this._tree.domFocus();
}
},
getActionsContext: () => (actionContext)
});
return true;
return false;
}
}

View File

@@ -40,130 +40,148 @@ export const EDIT_DATA_COMMAND_ID = 'dataExplorer.scriptAsEdit';
// Script as Create
CommandsRegistry.registerCommand({
id: SCRIPT_AS_CREATE_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const errorMessageService = accessor.get(IErrorMessageService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const scriptCreateAction = new ScriptCreateAction(ScriptCreateAction.ID, ScriptCreateAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptCreateAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const errorMessageService = accessor.get(IErrorMessageService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const scriptCreateAction = new ScriptCreateAction(ScriptCreateAction.ID, ScriptCreateAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptCreateAction.run(baseContext));
}
return undefined;
}
});
// Script as Delete
CommandsRegistry.registerCommand({
id: SCRIPT_AS_DELETE_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const errorMessageService = accessor.get(IErrorMessageService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const scriptDeleteAction = new ScriptDeleteAction(ScriptDeleteAction.ID, ScriptDeleteAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptDeleteAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const errorMessageService = accessor.get(IErrorMessageService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const scriptDeleteAction = new ScriptDeleteAction(ScriptDeleteAction.ID, ScriptDeleteAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptDeleteAction.run(baseContext));
}
return undefined;
}
});
// Script as Select
CommandsRegistry.registerCommand({
id: SCRIPT_AS_SELECT_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const scriptSelectAction = new ScriptSelectAction(ScriptSelectAction.ID, ScriptSelectAction.LABEL,
queryEditorService, connectionManagementService, scriptingService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptSelectAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const scriptSelectAction = new ScriptSelectAction(ScriptSelectAction.ID, ScriptSelectAction.LABEL,
queryEditorService, connectionManagementService, scriptingService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptSelectAction.run(baseContext));
}
return undefined;
}
});
// Script as Execute
CommandsRegistry.registerCommand({
id: SCRIPT_AS_EXECUTE_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const errorMessageService = accessor.get(IErrorMessageService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const scriptExecuteAction = new ScriptExecuteAction(ScriptExecuteAction.ID, ScriptExecuteAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptExecuteAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const errorMessageService = accessor.get(IErrorMessageService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const scriptExecuteAction = new ScriptExecuteAction(ScriptExecuteAction.ID, ScriptExecuteAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptExecuteAction.run(baseContext));
}
return undefined;
}
});
// Script as Alter
CommandsRegistry.registerCommand({
id: SCRIPT_AS_ALTER_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const errorMessageService = accessor.get(IErrorMessageService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const scriptAlterAction = new ScriptAlterAction(ScriptAlterAction.ID, ScriptAlterAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptAlterAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const errorMessageService = accessor.get(IErrorMessageService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const scriptAlterAction = new ScriptAlterAction(ScriptAlterAction.ID, ScriptAlterAction.LABEL,
queryEditorService, connectionManagementService, scriptingService, errorMessageService);
return progressService.withProgress({ location: VIEWLET_ID }, () => scriptAlterAction.run(baseContext));
}
return undefined;
}
});
// Edit Data
CommandsRegistry.registerCommand({
id: EDIT_DATA_COMMAND_ID,
handler: async (accessor, args: TreeViewItemHandleArg) => {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem).metadata
};
const editDataAction = new EditDataAction(EditDataAction.ID, EditDataAction.LABEL,
queryEditorService, connectionManagementService, scriptingService);
return progressService.withProgress({ location: VIEWLET_ID }, () => editDataAction.run(baseContext));
handler: async (accessor, args: TreeViewItemHandleArg): Promise<boolean | undefined> => {
if (args.$treeItem?.payload) {
const capabilitiesService = accessor.get(ICapabilitiesService);
const oeShimService = accessor.get(IOEShimService);
const queryEditorService = accessor.get(IQueryEditorService);
const connectionManagementService = accessor.get(IConnectionManagementService);
const scriptingService = accessor.get(IScriptingService);
const progressService = accessor.get(IProgressService);
const profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
const baseContext: BaseActionContext = {
profile: profile,
object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata
};
const editDataAction = new EditDataAction(EditDataAction.ID, EditDataAction.LABEL,
queryEditorService, connectionManagementService, scriptingService);
return progressService.withProgress({ location: VIEWLET_ID }, () => editDataAction.run(baseContext));
}
return undefined;
}
});
//#endregion
@@ -186,9 +204,9 @@ CommandsRegistry.registerCommand({
const connectionManagementService = accessor.get(IConnectionManagementService);
const objectExplorerService = accessor.get(IObjectExplorerService);
const selectionHandler = instantiationService.createInstance(TreeSelectionHandler);
const node = await getTreeNode(args, objectExplorerService);
const node = (await getTreeNode(args, objectExplorerService))!;
selectionHandler.onTreeActionStateChange(true);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node)!;
let ownerUri = connectionManagementService.getConnectionUri(connectionProfile);
ownerUri = connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
let metadata = node.metadata;
@@ -207,7 +225,7 @@ CommandsRegistry.registerCommand({
const instantiationService = accessor.get(IInstantiationService);
const objectExplorerService = accessor.get(IObjectExplorerService);
const selectionHandler = instantiationService.createInstance(TreeSelectionHandler);
const node = await getTreeNode(args, objectExplorerService);
const node = (await getTreeNode(args, objectExplorerService))!;
selectionHandler.onTreeActionStateChange(true);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node);
let metadata = node.metadata;
@@ -227,9 +245,9 @@ CommandsRegistry.registerCommand({
const connectionManagementService = accessor.get(IConnectionManagementService);
const objectExplorerService = accessor.get(IObjectExplorerService);
const selectionHandler = instantiationService.createInstance(TreeSelectionHandler);
const node = await getTreeNode(args, objectExplorerService);
const node = (await getTreeNode(args, objectExplorerService))!;
selectionHandler.onTreeActionStateChange(true);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node)!;
let metadata = node.metadata;
let ownerUri = connectionManagementService.getConnectionUri(connectionProfile);
ownerUri = connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
@@ -249,9 +267,9 @@ CommandsRegistry.registerCommand({
const connectionManagementService = accessor.get(IConnectionManagementService);
const objectExplorerService = accessor.get(IObjectExplorerService);
const selectionHandler = instantiationService.createInstance(TreeSelectionHandler);
const node = await getTreeNode(args, objectExplorerService);
const node = (await getTreeNode(args, objectExplorerService))!;
selectionHandler.onTreeActionStateChange(true);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node)!;
let metadata = node.metadata;
let ownerUri = connectionManagementService.getConnectionUri(connectionProfile);
ownerUri = connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
@@ -271,9 +289,9 @@ CommandsRegistry.registerCommand({
const connectionManagementService = accessor.get(IConnectionManagementService);
const objectExplorerService = accessor.get(IObjectExplorerService);
const selectionHandler = instantiationService.createInstance(TreeSelectionHandler);
const node = await getTreeNode(args, objectExplorerService);
const node = (await getTreeNode(args, objectExplorerService))!;
selectionHandler.onTreeActionStateChange(true);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node);
let connectionProfile = TreeUpdateUtils.getConnectionProfile(node)!;
let metadata = node.metadata;
let ownerUri = connectionManagementService.getConnectionUri(connectionProfile);
ownerUri = connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
@@ -297,8 +315,8 @@ CommandsRegistry.registerCommand({
//set objectExplorerTreeNode for context menu clicks
const node = await getTreeNode(args, objectExplorerService);
selectionHandler.onTreeActionStateChange(true);
const connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>node);
const metadata = node.metadata;
const connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>node)!;
const metadata = node!.metadata;
let ownerUri = connectionManagementService.getConnectionUri(connectionProfile);
ownerUri = connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
@@ -320,9 +338,9 @@ export async function handleOeRefreshCommand(accessor: ServicesAccessor, args: O
const logService = accessor.get(ILogService);
const notificationService = accessor.get(INotificationService);
const treeNode = await getTreeNode(args, objectExplorerService);
const tree = objectExplorerService.getServerTreeView().tree;
const tree = objectExplorerService.getServerTreeView()!.tree;
try {
await objectExplorerService.refreshTreeNode(treeNode.getSession(), treeNode);
await objectExplorerService.refreshTreeNode(treeNode!.getSession()!, treeNode!);
if (tree instanceof AsyncServerTree) {
await tree.updateChildren(treeNode);
} else {
@@ -330,7 +348,7 @@ export async function handleOeRefreshCommand(accessor: ServicesAccessor, args: O
}
} catch (err) {
// Display message to the user but also log the entire error to the console for the stack trace
notificationService.error(localize('refreshError', "An error occurred refreshing node '{0}': {1}", args.nodeInfo.label, getErrorMessage(err)));
notificationService.error(localize('refreshError', "An error occurred refreshing node '{0}': {1}", args.nodeInfo?.label, getErrorMessage(err)));
logService.error(err);
}
}

View File

@@ -20,7 +20,6 @@ import { NodeType } from 'sql/workbench/services/objectExplorer/common/nodeType'
import { ServerTreeView } from 'sql/workbench/contrib/objectExplorer/browser/serverTreeView';
import { createObjectExplorerServiceMock } from 'sql/workbench/services/objectExplorer/test/browser/testObjectExplorerService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { TestTree } from 'sql/workbench/test/treeMock';
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
@@ -56,7 +55,7 @@ const oeActionArgs: ObjectExplorerActionsContext = { connectionProfile: connecti
let instantiationService: IInstantiationService;
let logServiceMock: TypeMoq.Mock<ILogService>;
let treeMock: TypeMoq.Mock<ITree>;
let treeMock: TypeMoq.Mock<TestTree>;
suite('Scripting Actions', () => {
@@ -68,7 +67,7 @@ suite('Scripting Actions', () => {
const serverTreeViewMock = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Loose, connectionManagementServiceMock.object, instantiationService, undefined, undefined, undefined, undefined, capabilitiesService);
treeMock = TypeMoq.Mock.ofType(TestTree);
serverTreeViewMock.setup(x => x.tree).returns(() => treeMock.object);
collection.set(IObjectExplorerService, createObjectExplorerServiceMock({ serverTreeView: serverTreeViewMock.object, treeNode: treeNode }).object);
collection.set(IObjectExplorerService, createObjectExplorerServiceMock({ serverTreeView: serverTreeViewMock.object, treeNode: treeNode }));
logServiceMock = TypeMoq.Mock.ofInstance(new NullLogService());
collection.set(ILogService, logServiceMock.object);
collection.set(INotificationService, new TestNotificationService());

View File

@@ -18,7 +18,7 @@ export class ConnectionContextKey implements IContextKey<IConnectionProfile> {
private _providerKey: IContextKey<string>;
private _serverKey: IContextKey<string>;
private _databaseKey: IContextKey<string>;
private _databaseKey: IContextKey<string | undefined>;
private _connectionKey: IContextKey<IConnectionProfile>;
private _isQueryProviderKey: IContextKey<boolean>;
private _canOpenInAzurePortal: IContextKey<boolean>;

View File

@@ -52,7 +52,7 @@ export class AsyncServerTreeDataSource implements IAsyncDataSource<ConnectionPro
if (element.children) {
return element.children;
} else {
return await this._objectExplorerService.resolveTreeNodeChildren(element.getSession(), element);
return await this._objectExplorerService.resolveTreeNodeChildren(element.getSession()!, element);
}
}
} catch (err) {

View File

@@ -37,15 +37,15 @@ export class AsyncServerTreeDragAndDrop implements ITreeDragAndDrop<ServerTreeEl
* Returns a uri if the given element should be allowed to drag.
* Returns null, otherwise.
*/
public getDragURI(element: ServerTreeElement): string {
return this._dragAndDrop.getDragURI(this._tree, element);
public getDragURI(element: ServerTreeElement): string | null {
return this._dragAndDrop.getDragURI(this._tree!, element);
}
/**
* Returns a label(name) to display when dragging the element.
*/
public getDragLabel(elements: ServerTreeElement[]): string {
return this._dragAndDrop.getDragLabel(this._tree, elements);
return this._dragAndDrop.getDragLabel(this._tree!, elements);
}
/**
@@ -54,17 +54,17 @@ export class AsyncServerTreeDragAndDrop implements ITreeDragAndDrop<ServerTreeEl
public onDragStart(dragAndDropData: IDragAndDropData, originalEvent: DragEvent): void {
// Force the event cast while in preview - we don't use any of the mouse properties on the
// implementation so this is fine for now
return this._dragAndDrop.onDragStart(this._tree, dragAndDropData, <any>originalEvent);
return this._dragAndDrop.onDragStart(this._tree!, dragAndDropData, <any>originalEvent);
}
public onDragOver(data: IDragAndDropData, targetElement: ServerTreeElement, targetIndex: number, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
public onDragOver(data: IDragAndDropData, targetElement: ServerTreeElement | undefined, targetIndex: number, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
// Dropping onto an empty space (undefined targetElement) we treat as wanting to move into the root connection group
if (!targetElement) {
targetElement = this._tree?.getInput();
}
// Force the event cast while in preview - we don't use any of the mouse properties on the
// implementation so this is fine for now
const canDragOver = this._dragAndDrop.onDragOver(this._tree, data, targetElement, <any>originalEvent);
const canDragOver = this._dragAndDrop.onDragOver(this._tree!, data, targetElement, <any>originalEvent);
if (canDragOver.accept) {
return TreeDragOverReactions.acceptBubbleDown(canDragOver.autoExpand);
@@ -76,14 +76,14 @@ export class AsyncServerTreeDragAndDrop implements ITreeDragAndDrop<ServerTreeEl
/**
* Handle a drop in the server tree.
*/
public drop(data: IDragAndDropData, targetElement: ServerTreeElement, targetIndex: number, originalEvent: DragEvent): void {
public drop(data: IDragAndDropData, targetElement: ServerTreeElement | undefined, targetIndex: number, originalEvent: DragEvent): void {
// Dropping onto an empty space (undefined targetElement) we treat as wanting to move into the root connection group
if (!targetElement) {
targetElement = this._tree?.getInput();
}
// Force the event cast while in preview - we don't use any of the mouse properties on the
// implementation so this is fine for now
this._dragAndDrop.drop(this._tree, data, targetElement, <any>originalEvent);
this._dragAndDrop.drop(this._tree!, data, targetElement, <any>originalEvent);
}
public onDragEnd(originalEvent: DragEvent): void {
@@ -102,7 +102,7 @@ export class AsyncRecentConnectionsDragAndDrop implements ITreeDragAndDrop<Serve
return (<ConnectionProfile>element).id;
}
else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).id;
return (<ConnectionProfileGroup>element).id ?? null;
}
return null;
}
@@ -117,7 +117,7 @@ export class AsyncRecentConnectionsDragAndDrop implements ITreeDragAndDrop<Serve
else if (elements[0] instanceof ConnectionProfileGroup) {
return elements[0].name;
}
return undefined;
return '';
}
/**

View File

@@ -8,6 +8,6 @@ import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser
export class AsyncServerTreeIdentityProvider implements IIdentityProvider<ServerTreeElement> {
getId(element: ServerTreeElement): { toString(): string; } {
return element.id;
return element.id!;
}
}

View File

@@ -8,7 +8,7 @@ import 'vs/css!./media/objectTypes/objecttypes';
import * as dom from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import { ConnectionProfile, IconPath } from 'sql/platform/connection/common/connectionProfile';
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
import { iconRenderer } from 'sql/workbench/services/objectExplorer/browser/iconRenderer';
@@ -22,6 +22,7 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { ServerTreeRenderer } from 'sql/workbench/services/objectExplorer/browser/serverTreeRenderer';
import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { DefaultServerGroupColor } from 'sql/workbench/services/serverGroup/common/serverGroupViewModel';
import { withNullAsUndefined } from 'vs/base/common/types';
class ConnectionProfileGroupTemplate extends Disposable {
private _root: HTMLElement;
@@ -31,7 +32,7 @@ class ConnectionProfileGroupTemplate extends Disposable {
container: HTMLElement
) {
super();
container.parentElement.classList.add('server-group');
container.parentElement!.classList.add('server-group');
container.classList.add('server-group');
this._root = dom.append(container, dom.$('.server-group'));
this._nameContainer = dom.append(this._root, dom.$('span.name'));
@@ -89,7 +90,7 @@ class ConnectionProfileTemplate extends Disposable {
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
) {
super();
container.parentElement.classList.add('connection-profile');
container.parentElement!.classList.add('connection-profile');
this._root = dom.append(container, dom.$('.connection-tile'));
this._icon = dom.append(this._root, dom.$('div.icon server-page'));
this._connectionStatusBadge = dom.append(this._icon, dom.$('div.connection-status-badge'));
@@ -98,16 +99,15 @@ class ConnectionProfileTemplate extends Disposable {
set(element: ConnectionProfile) {
if (!this._isCompact) {
let iconPath: IconPath = getIconPath(element, this._connectionManagementService);
let iconPath: IconPath | undefined = getIconPath(element, this._connectionManagementService);
if (this._connectionManagementService.isConnected(undefined, element)) {
this._connectionStatusBadge.classList.remove('disconnected');
this._connectionStatusBadge.classList.add('connected');
renderServerIcon(this._icon, iconPath);
} else {
this._connectionStatusBadge.classList.remove('connected');
this._connectionStatusBadge.classList.add('disconnected');
renderServerIcon(this._icon, iconPath);
}
renderServerIcon(this._icon, iconPath);
}
let label = element.title;
@@ -156,7 +156,7 @@ class TreeNodeTemplate extends Disposable {
set(element: TreeNode) {
// Use an explicitly defined iconType first. If not defined, fall back to using nodeType and
// other compount indicators instead.
let iconName: string = undefined;
let iconName: string | undefined = undefined;
if (element.iconType) {
iconName = (typeof element.iconType === 'string') ? element.iconType : element.iconType.id;
} else {
@@ -171,7 +171,7 @@ class TreeNodeTemplate extends Disposable {
let tokens: string[] = [];
for (let index = 1; index < this._icon.classList.length; index++) {
tokens.push(this._icon.classList.item(index));
tokens.push(this._icon.classList.item(index)!);
}
this._icon.classList.remove(...tokens);
this._icon.classList.add('icon');
@@ -229,7 +229,7 @@ export class ServerTreeAccessibilityProvider implements IListAccessibilityProvid
getAriaLabel(element: ServerTreeElement): string | null {
if (element instanceof ConnectionProfileGroup) {
return element.fullName;
return element.fullName ?? null;
} else if (element instanceof ConnectionProfile) {
return element.title;
}
@@ -240,22 +240,22 @@ export class ServerTreeAccessibilityProvider implements IListAccessibilityProvid
/**
* Returns the first parent which contains the className
*/
function findParentElement(container: HTMLElement, className: string): HTMLElement {
let currentElement = container;
function findParentElement(container: HTMLElement, className: string): HTMLElement | undefined {
let currentElement: HTMLElement | null = container;
while (currentElement) {
if (currentElement.className.indexOf(className) > -1) {
break;
}
currentElement = currentElement.parentElement;
}
return currentElement;
return withNullAsUndefined(currentElement);
}
function getIconPath(connection: ConnectionProfile, connectionManagementService: IConnectionManagementService): IconPath {
function getIconPath(connection: ConnectionProfile, connectionManagementService: IConnectionManagementService): IconPath | undefined {
if (!connection) { return undefined; }
if (connection['iconPath']) {
return connection['iconPath'];
if (connection.iconPath) {
return connection.iconPath;
}
let iconId = connectionManagementService.getConnectionIconId(connection.id);
@@ -264,8 +264,8 @@ function getIconPath(connection: ConnectionProfile, connectionManagementService:
let providerProperties = connectionManagementService.getProviderProperties(connection.providerName);
if (!providerProperties) { return undefined; }
let iconPath: IconPath = undefined;
let pathConfig: URI | IconPath | { id: string, path: IconPath }[] = providerProperties['iconPath'];
let iconPath: IconPath | undefined = undefined;
let pathConfig: URI | IconPath | { id: string, path: IconPath }[] | undefined = providerProperties['iconPath'];
if (Array.isArray(pathConfig)) {
for (const e of pathConfig) {
if (!e.id || e.id === iconId) {
@@ -274,25 +274,18 @@ function getIconPath(connection: ConnectionProfile, connectionManagementService:
break;
}
}
} else if (pathConfig['light']) {
iconPath = pathConfig as IconPath;
connection['iconPath'] = iconPath;
} else if (URI.isUri(pathConfig)) {
iconPath = { light: pathConfig, dark: pathConfig };
connection.iconPath = iconPath;
} else {
let singlePath = pathConfig as URI;
iconPath = { light: singlePath, dark: singlePath };
connection['iconPath'] = iconPath;
connection.iconPath = pathConfig;
}
return iconPath;
}
function renderServerIcon(element: HTMLElement, iconPath: IconPath): void {
function renderServerIcon(element: HTMLElement, iconPath?: IconPath): void {
if (!element) { return; }
if (iconPath) {
iconRenderer.putIcon(element, iconPath);
}
}
interface IconPath {
light: URI;
dark: URI;
}

View File

@@ -28,6 +28,8 @@ export function supportsFolderNodeNameDrop(nodeId: string, label: string): boole
return false;
}
function escapeString(input: string): string;
function escapeString(input: undefined): undefined;
function escapeString(input: string | undefined): string | undefined {
return input?.replace(/]/g, ']]');
}
@@ -46,22 +48,22 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
* Returns a uri if the given element should be allowed to drag.
* Returns null, otherwise.
*/
public getDragURI(tree: AsyncServerTree | ITree, element: any): string {
public getDragURI(tree: AsyncServerTree | ITree, element: any): string | null {
if (element) {
if (element instanceof ConnectionProfile) {
return (<ConnectionProfile>element).id;
return element.id;
} else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).id;
return element.id ?? null;
} else if (supportsNodeNameDrop(element.nodeTypeId)) {
return (<TreeNode>element).id;
} else if (supportsFolderNodeNameDrop(element.nodeTypeId, element.label) && element.children) {
return (<TreeNode>element).id;
} else {
return undefined;
return null;
}
}
else {
return undefined;
return null;
}
}
@@ -78,11 +80,11 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
return elements[0].label;
}
else {
return undefined;
return '';
}
}
else {
return undefined;
return '';
}
}
@@ -125,7 +127,7 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
return element.connection.providerName;
}
return this.getProviderNameFromElement(element.parent);
return this.getProviderNameFromElement(element.parent!);
}
@@ -133,7 +135,7 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
let canDragOver: boolean = true;
if (source instanceof ConnectionProfile) {
if (!this._connectionManagementService.canChangeConnectionConfig(source, targetConnectionProfileGroup.id)) {
if (!this._connectionManagementService.canChangeConnectionConfig(source, targetConnectionProfileGroup.id!)) {
canDragOver = false;
}
} else if (source instanceof ConnectionProfileGroup) {
@@ -158,7 +160,7 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
// Verify if the connection can be moved to the target group
const source = data.getData()[0];
if (source instanceof ConnectionProfile) {
if (!this._connectionManagementService.canChangeConnectionConfig(source, targetConnectionProfileGroup.id)) {
if (!this._connectionManagementService.canChangeConnectionConfig(source, targetConnectionProfileGroup.id!)) {
canDragOver = false;
}
} else if (source instanceof ConnectionProfileGroup) {
@@ -201,7 +203,7 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
if (source instanceof ConnectionProfile) {
// Change group id of profile
this._connectionManagementService.changeGroupIdForConnection(source, targetConnectionProfileGroup.id).then(() => {
this._connectionManagementService.changeGroupIdForConnection(source, targetConnectionProfileGroup.id!).then(() => {
if (tree) {
TreeUpdateUtils.registeredServerUpdate(tree, self._connectionManagementService, targetConnectionProfileGroup);
}
@@ -224,13 +226,13 @@ export class ServerTreeDragAndDrop implements IDragAndDrop {
TreeUpdateUtils.isInDragAndDrop = false;
}
private getTargetGroup(targetElement: any): ConnectionProfileGroup {
private getTargetGroup(targetElement: ConnectionProfileGroup | ConnectionProfile): ConnectionProfileGroup {
let targetConnectionProfileGroup: ConnectionProfileGroup;
if (targetElement instanceof ConnectionProfile) {
targetConnectionProfileGroup = (<ConnectionProfile>targetElement).getParent();
targetConnectionProfileGroup = targetElement.getParent()!;
}
else {
targetConnectionProfileGroup = <ConnectionProfileGroup>targetElement;
targetConnectionProfileGroup = targetElement;
}
return targetConnectionProfileGroup;
@@ -256,12 +258,12 @@ export class RecentConnectionsDragAndDrop implements IDragAndDrop {
* Returns a uri if the given element should be allowed to drag.
* Returns null, otherwise.
*/
public getDragURI(tree: ITree, element: any): string {
public getDragURI(tree: ITree, element: any): string | null {
if (element instanceof ConnectionProfile) {
return (<ConnectionProfile>element).id;
}
else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).id;
return (<ConnectionProfileGroup>element).id ?? null;
}
return null;
}
@@ -276,7 +278,7 @@ export class RecentConnectionsDragAndDrop implements IDragAndDrop {
else if (elements[0] instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>elements[0]).name;
}
return undefined;
return '';
}
/**

View File

@@ -10,11 +10,11 @@ import { URI } from 'vs/base/common/uri';
class IconRenderer {
private iconRegistered: Set<string> = new Set<string>();
public registerIcon(path: URI | IconPath): string {
public registerIcon(path: URI | IconPath): string | undefined {
if (!path) { return undefined; }
let iconPath: IconPath = this.toIconPath(path);
let iconUid: string = this.getIconUid(iconPath);
if (!this.iconRegistered.has(iconUid)) {
let iconUid: string | undefined = this.getIconUid(iconPath);
if (iconUid && !this.iconRegistered.has(iconUid)) {
createCSSRule(`.icon#${iconUid}`, `background: ${asCSSUrl(iconPath.light || iconPath.dark)} center center no-repeat`);
createCSSRule(`.vs-dark .icon#${iconUid}, .hc-black .icon#${iconUid}`, `background: ${asCSSUrl(iconPath.dark)} center center no-repeat`);
this.iconRegistered.add(iconUid);
@@ -22,30 +22,30 @@ class IconRenderer {
return iconUid;
}
public getIconUid(path: URI | IconPath): string {
public getIconUid(path: URI | IconPath): string | undefined {
if (!path) { return undefined; }
let iconPath: IconPath = this.toIconPath(path);
return `icon${hash(iconPath.light.toString() + iconPath.dark.toString())}`;
}
private toIconPath(path: URI | IconPath): IconPath {
if (path['light']) {
return path as IconPath;
} else {
let singlePath = path as URI;
if (URI.isUri(path)) {
let singlePath = path;
return { light: singlePath, dark: singlePath };
} else {
return path;
}
}
public putIcon(element: HTMLElement, path: URI | IconPath): void {
if (!element || !path) { return undefined; }
let iconUid: string = this.registerIcon(path);
element.id = iconUid;
let iconUid: string | undefined = this.registerIcon(path);
element.id = iconUid ?? '';
}
public removeIcon(element: HTMLElement): void {
if (!element) { return undefined; }
element.id = undefined;
element.id = '';
}
}
@@ -117,9 +117,9 @@ class BadgeRenderer {
public removeBadge(element: HTMLElement, badgeClass: string): void {
let children: HTMLCollection = element.children;
let current = children[0];
let current: Element | null = children[0];
while (current) {
let next = current.nextElementSibling;
let next: Element | null = current.nextElementSibling;
if (current.classList.contains(badgeClass)) {
current.remove();
break;

View File

@@ -19,10 +19,8 @@ export class RecentConnectionDataSource implements IDataSource {
public getId(tree: ITree, element: any): string {
if (element instanceof ConnectionProfile) {
return (<ConnectionProfile>element).id;
} else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).id;
} else {
return undefined;
return (<ConnectionProfileGroup>element).id!;
}
}
@@ -63,4 +61,4 @@ export class RecentConnectionDataSource implements IDataSource {
return Promise.resolve(null);
}
}
}
}

View File

@@ -74,7 +74,7 @@ export class ServerTreeController extends treedefaults.DefaultController {
context.nodeInfo = element.toNodeInfo();
// Note: getting DB name before, but intentionally not using treeUpdateUtils.getConnectionProfile as it replaces
// the connection ID with a new one. This breaks a number of internal tasks
context.connectionProfile = element.getConnectionProfile().toIConnectionProfile();
context.connectionProfile = element.getConnectionProfile()!.toIConnectionProfile();
context.connectionProfile.databaseName = element.getDatabaseName();
actionContext = context;
} else if (element instanceof ConnectionProfile) {

View File

@@ -30,13 +30,7 @@ export class ServerTreeDataSource implements IDataSource {
* No more than one element may use a given identifier.
*/
public getId(tree: ITree, element: any): string {
if (element instanceof ConnectionProfile
|| element instanceof ConnectionProfileGroup
|| element instanceof TreeNode) {
return element.id;
} else {
return undefined;
}
return element.id;
}
/**
@@ -67,7 +61,7 @@ export class ServerTreeDataSource implements IDataSource {
return node.children;
} else {
try {
return this._objectExplorerService.resolveTreeNodeChildren(node.getSession(), node);
return this._objectExplorerService.resolveTreeNodeChildren(node.getSession()!, node);
} catch (expandError) {
await node.setExpandedState(TreeItemCollapsibleState.Collapsed);
node.errorStateMessage = expandError;

View File

@@ -16,6 +16,7 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { badgeRenderer, iconRenderer } from 'sql/workbench/services/objectExplorer/browser/iconRenderer';
import { URI } from 'vs/base/common/uri';
import { DefaultServerGroupColor } from 'sql/workbench/services/serverGroup/common/serverGroupViewModel';
import { withNullAsUndefined } from 'vs/base/common/types';
export interface IConnectionTemplateData {
root: HTMLElement;
@@ -132,7 +133,7 @@ export class ServerTreeRenderer implements IRenderer {
private renderObjectExplorer(treeNode: TreeNode, templateData: IObjectExplorerTemplateData): void {
// Use an explicitly defined iconType first. If not defined, fall back to using nodeType and
// other compount indicators instead.
let iconName: string = undefined;
let iconName: string | undefined = undefined;
if (treeNode.iconType) {
iconName = (typeof treeNode.iconType === 'string') ? treeNode.iconType : treeNode.iconType.id;
} else {
@@ -147,7 +148,7 @@ export class ServerTreeRenderer implements IRenderer {
let tokens: string[] = [];
for (let index = 1; index < templateData.icon.classList.length; index++) {
tokens.push(templateData.icon.classList.item(index));
tokens.push(templateData.icon.classList.item(index)!);
}
templateData.icon.classList.remove(...tokens);
templateData.icon.classList.add('icon');
@@ -162,11 +163,11 @@ export class ServerTreeRenderer implements IRenderer {
templateData.root.title = treeNode.label;
}
private getIconPath(connection: ConnectionProfile): IconPath {
private getIconPath(connection: ConnectionProfile): IconPath | undefined {
if (!connection) { return undefined; }
if (connection['iconPath']) {
return connection['iconPath'];
if (connection.iconPath) {
return connection.iconPath;
}
let iconId = this._connectionManagementService.getConnectionIconId(connection.id);
@@ -175,8 +176,8 @@ export class ServerTreeRenderer implements IRenderer {
let providerProperties = this._connectionManagementService.getProviderProperties(connection.providerName);
if (!providerProperties) { return undefined; }
let iconPath: IconPath = undefined;
let pathConfig: URI | IconPath | { id: string, path: IconPath }[] = providerProperties['iconPath'];
let iconPath: IconPath | undefined = undefined;
let pathConfig: URI | IconPath | { id: string, path: IconPath }[] | undefined = providerProperties.iconPath;
if (Array.isArray(pathConfig)) {
for (const e of pathConfig) {
if (!e.id || e.id === iconId) {
@@ -185,18 +186,18 @@ export class ServerTreeRenderer implements IRenderer {
break;
}
}
} else if (pathConfig['light']) {
iconPath = pathConfig as IconPath;
connection['iconPath'] = iconPath;
} else {
} else if (URI.isUri(pathConfig)) {
let singlePath = pathConfig as URI;
iconPath = { light: singlePath, dark: singlePath };
connection['iconPath'] = iconPath;
connection.iconPath = iconPath;
} else {
iconPath = pathConfig as IconPath;
connection.iconPath = iconPath;
}
return iconPath;
}
private renderServerIcon(element: HTMLElement, iconPath: IconPath, isConnected: boolean): void {
private renderServerIcon(element: HTMLElement, iconPath: IconPath | undefined, isConnected: boolean): void {
if (!element) { return; }
if (iconPath) {
iconRenderer.putIcon(element, iconPath);
@@ -209,7 +210,7 @@ export class ServerTreeRenderer implements IRenderer {
private renderConnection(connection: ConnectionProfile, templateData: IConnectionTemplateData): void {
if (!this._isCompact) {
let iconPath: IconPath = this.getIconPath(connection);
let iconPath = this.getIconPath(connection);
if (this._connectionManagementService.isConnected(undefined, connection)) {
templateData.icon.classList.remove('disconnected');
templateData.icon.classList.add('connected');
@@ -252,15 +253,15 @@ export class ServerTreeRenderer implements IRenderer {
/**
* Returns the first parent which contains the className
*/
private findParentElement(container: HTMLElement, className: string): HTMLElement {
let currentElement = container;
private findParentElement(container: HTMLElement, className: string): HTMLElement | undefined {
let currentElement: HTMLElement | null = container;
while (currentElement) {
if (currentElement.className.indexOf(className) > -1) {
break;
}
currentElement = currentElement.parentElement;
}
return currentElement;
return withNullAsUndefined(currentElement);
}
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {

View File

@@ -142,5 +142,5 @@ export class TreeCreationUtils {
}
function useAsyncServerTree(configurationService: IConfigurationService): boolean {
return configurationService.getValue('workbench.enablePreviewFeatures') && configurationService.getValue('serverTree.useAsyncServerTree');
return configurationService.getValue<boolean>('workbench.enablePreviewFeatures') && configurationService.getValue<boolean>('serverTree.useAsyncServerTree');
}

View File

@@ -98,7 +98,7 @@ suite('AsyncServerTreeDragAndDrop', () => {
assert.equal(treeNodeArray[0].label, labelTreeNode);
let labelUndefined = serverTreeDragAndDrop.getDragLabel(undefined);
assert.equal(undefined, labelUndefined);
assert.equal('', labelUndefined);
});

View File

@@ -103,7 +103,7 @@ suite('SQL Drag And Drop Controller tests', () => {
assert.equal(treeNodeArray[0].label, labelTreeNode);
let labelUndefined = serverTreeDragAndDrop.getDragLabel(testTree, null);
assert.equal(undefined, labelUndefined);
assert.equal('', labelUndefined);
});

View File

@@ -26,18 +26,18 @@ export type ObjectExplorerServiceMockOptions = {
*
* @param options Options to use for setting up functions on the mock to return various values
*/
export function createObjectExplorerServiceMock(options: ObjectExplorerServiceMockOptions): TypeMoq.Mock<IObjectExplorerService> {
export function createObjectExplorerServiceMock(options: ObjectExplorerServiceMockOptions): IObjectExplorerService {
const objectExplorerService = TypeMoq.Mock.ofType(TestObjectExplorerService);
if (options.treeNode) {
objectExplorerService.setup(x => x.getTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(options.treeNode));
objectExplorerService.setup(x => x.getTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(options.treeNode!));
}
if (options.serverTreeView) {
objectExplorerService.setup(x => x.getServerTreeView()).returns(() => options.serverTreeView);
objectExplorerService.setup(x => x.getServerTreeView()).returns(() => options.serverTreeView!);
}
return objectExplorerService;
return objectExplorerService.object;
}
/**
@@ -49,13 +49,13 @@ export class TestObjectExplorerService implements IObjectExplorerService {
constructor() { }
public getSession(sessionId: string): azdata.ObjectExplorerSession { return undefined; }
public getSession(sessionId: string): azdata.ObjectExplorerSession { throw new Error('Method not implemented'); }
public providerRegistered(providerId: string): boolean { return true; }
public get onUpdateObjectExplorerNodes(): Event<ObjectExplorerNodeEventArgs> { return undefined; }
public get onUpdateObjectExplorerNodes(): Event<ObjectExplorerNodeEventArgs> { throw new Error('Method not implemented'); }
public get onSelectionOrFocusChange(): Event<void> { return undefined; }
public get onSelectionOrFocusChange(): Event<void> { throw new Error('Method not implemented'); }
public async updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> { }
@@ -67,41 +67,41 @@ export class TestObjectExplorerService implements IObjectExplorerService {
public async onSessionDisconnected(handle: number, session: azdata.ObjectExplorerSession): Promise<void> { }
public getObjectExplorerNode(connection: IConnectionProfile): TreeNode { return undefined; }
public getObjectExplorerNode(connection: IConnectionProfile): TreeNode { throw new Error('Method not implemented'); }
public async createNewSession(providerId: string, connection: ConnectionProfile): Promise<azdata.ObjectExplorerSessionResponse> { return undefined; }
public async createNewSession(providerId: string, connection: ConnectionProfile): Promise<azdata.ObjectExplorerSessionResponse> { throw new Error('Method not implemented'); }
public async expandNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo> { return undefined; }
public async expandNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo> { throw new Error('Method not implemented'); }
public async refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo> { return undefined; }
public async refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo> { throw new Error('Method not implemented'); }
public async closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise<azdata.ObjectExplorerCloseSessionResponse> { return undefined; }
public async closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise<azdata.ObjectExplorerCloseSessionResponse> { throw new Error('Method not implemented'); }
public registerProvider(providerId: string, provider: azdata.ObjectExplorerProvider): void { }
public registerNodeProvider(nodeProvider: azdata.ObjectExplorerNodeProvider): void { }
public async resolveTreeNodeChildren(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise<TreeNode[]> { return undefined; }
public async resolveTreeNodeChildren(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise<TreeNode[]> { throw new Error('Method not implemented'); }
public async refreshTreeNode(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise<TreeNode[]> { return undefined; }
public async refreshTreeNode(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise<TreeNode[]> { throw new Error('Method not implemented'); }
public registerServerTreeView(view: IServerTreeView): void { }
public getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string } { return undefined; }
public getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string } | undefined { return undefined; }
public isFocused(): boolean { return true; }
public getServerTreeView(): IServerTreeView { return undefined; }
public getServerTreeView(): IServerTreeView { throw new Error('Method not implemented'); }
public async findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Promise<azdata.NodeInfo[]> { return undefined; }
public async findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Promise<azdata.NodeInfo[]> { throw new Error('Method not implemented'); }
public getActiveConnectionNodes(): TreeNode[] { return undefined; }
public getActiveConnectionNodes(): TreeNode[] { throw new Error('Method not implemented'); }
public async getNodeActions(connectionId: string, nodePath: string): Promise<string[]> { return undefined; }
public async getNodeActions(connectionId: string, nodePath: string): Promise<string[]> { throw new Error('Method not implemented'); }
public async refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode> { return undefined; }
public async refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode> { throw new Error('Method not implemented'); }
public getSessionConnectionProfile(sessionId: string): azdata.IConnectionProfile { return undefined; }
public getSessionConnectionProfile(sessionId: string): azdata.IConnectionProfile { throw new Error('Method not implemented'); }
public async getTreeNode(connectionId: string, nodePath: string): Promise<TreeNode> { return undefined; }
public async getTreeNode(connectionId: string, nodePath: string): Promise<TreeNode> { throw new Error('Method not implemented'); }
}

View File

@@ -28,7 +28,7 @@ export class QueryHistoryInfo {
public connectionProfile: IConnectionProfile,
public startTime: Date,
status?: QueryStatus) {
this.database = connectionProfile ? connectionProfile.databaseName : '';
this.database = connectionProfile?.databaseName ?? '';
this.status = status;
}
}

View File

@@ -319,7 +319,7 @@ export class RestoreDialogController implements IRestoreDialogController {
if (this._currentProvider === ConnectionConstants.mssqlProviderName) {
let restoreDialog = this._restoreDialogs[this._currentProvider] as RestoreDialog;
restoreDialog.viewModel.resetRestoreOptions(connection.databaseName);
restoreDialog.viewModel.resetRestoreOptions(connection.databaseName!);
this.getMssqlRestoreConfigInfo().then(() => {
restoreDialog.open(connection.serverName, this._ownerUri!);
restoreDialog.validateRestore();

View File

@@ -77,7 +77,7 @@ export class TaskService implements ITaskService {
}
public createNewTask(taskInfo: azdata.TaskInfo) {
let databaseName: string = taskInfo.databaseName;
let databaseName: string | undefined = taskInfo.databaseName;
let serverName: string = taskInfo.serverName;
if (taskInfo && taskInfo.connection) {
let connectionProfile = this.connectionManagementService.getConnectionProfile(taskInfo.connection.connectionId);

View File

@@ -12,24 +12,24 @@ import { IItemExpandEvent, IItemCollapseEvent } from 'vs/base/parts/tree/browser
*/
export class TestTree implements ITree {
readonly onDidChangeFocus: Event<IFocusEvent>;
readonly onDidChangeSelection: Event<ISelectionEvent>;
readonly onDidChangeHighlight: Event<IHighlightEvent>;
readonly onDidExpandItem: Event<IItemExpandEvent>;
readonly onDidCollapseItem: Event<IItemCollapseEvent>;
readonly onDidDispose: Event<void>;
readonly onDidChangeFocus: Event<IFocusEvent> = Event.None;
readonly onDidChangeSelection: Event<ISelectionEvent> = Event.None;
readonly onDidChangeHighlight: Event<IHighlightEvent> = Event.None;
readonly onDidExpandItem: Event<IItemExpandEvent> = Event.None;
readonly onDidCollapseItem: Event<IItemCollapseEvent> = Event.None;
readonly onDidDispose: Event<void> = Event.None;
constructor() { }
public style(styles: ITreeStyles): void { }
get onDidFocus(): Event<void> { return undefined; }
get onDidFocus(): Event<void> { return Event.None; }
get onDidBlur(): Event<void> { return undefined; }
get onDidBlur(): Event<void> { return Event.None; }
get onDidScroll(): Event<void> { return undefined; }
get onDidScroll(): Event<void> { return Event.None; }
public getHTMLElement(): HTMLElement { return undefined; }
public getHTMLElement(): HTMLElement { throw new Error('Method not implemented'); }
public layout(height?: number, width?: number): void { }
@@ -113,7 +113,7 @@ export class TestTree implements ITree {
public deselect(element: any, eventPayload?: any): void { }
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> { return undefined; }
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> { throw new Error('Method not implemented'); }
public dispose(): void { }
}

View File

@@ -72,7 +72,6 @@
"./sql/workbench/contrib/profiler/**/*.ts", // 100 errors
"./sql/workbench/contrib/query/**/*.ts", // 3077 errors
"./sql/workbench/contrib/queryHistory/**/*.ts", // 290 errors
"./sql/workbench/contrib/scripting/**/*.ts", // 179 errors
"./sql/workbench/contrib/welcome/**/*.ts", // 66 errors
"./sql/workbench/services/connection/**/*.ts", // 3130 errors
"./sql/workbench/services/dialog/**/*.ts", // 2995 errors