Skip to content

Commit

Permalink
Merge pull request #234 from mtxr/feature/results-per-connection
Browse files Browse the repository at this point in the history
Allow to open results screen for each connection
  • Loading branch information
mtxr committed May 20, 2019
2 parents 002be50 + 811cbe6 commit e93e10c
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 77 deletions.
4 changes: 2 additions & 2 deletions packages/core/package.json
Expand Up @@ -14,8 +14,8 @@
"mysql": "^2.16.0",
"pg": "^7.8.1",
"vscode": "^1.1.30",
"vscode-languageclient": "^5.2.1",
"vscode-languageserver": "^5.3.0-next.1"
"vscode-languageclient": "5.2.1",
"vscode-languageserver": "5.2.1"
},
"devDependencies": {
"@types/command-exists": "^1.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/package.json
Expand Up @@ -900,6 +900,6 @@
"dependencies": {
"@sqltools/core": "*",
"@sqltools/plugins": "*",
"vscode-languageclient": "^5.2.1"
"vscode-languageclient": "5.2.1"
}
}
2 changes: 1 addition & 1 deletion packages/language-server/package.json
Expand Up @@ -10,7 +10,7 @@
"@sqltools/core": "*",
"@sqltools/plugins": "*",
"redux": "^4.0.1",
"vscode-languageserver": "^5.3.0-next.1"
"vscode-languageserver": "5.2.1"
},
"devDependencies": {
"@babel/core": "7.4.4",
Expand Down
44 changes: 21 additions & 23 deletions packages/plugins/connection-manager/extension.ts
Expand Up @@ -6,7 +6,7 @@ import SQLTools, { RequestHandler } from '@sqltools/core/plugin-api';
import { getConnectionDescription, getConnectionId, isEmpty } from '@sqltools/core/utils';
import { getSelectedText, quickPick, readInput } from '@sqltools/core/utils/vscode';
import { SidebarConnection, SidebarTableOrView, ConnectionExplorer } from '@sqltools/plugins/connection-manager/explorer';
import ResultsWebview from '@sqltools/plugins/connection-manager/screens/results';
import ResultsWebviewManager from '@sqltools/plugins/connection-manager/screens/results';
import SettingsWebview from '@sqltools/plugins/connection-manager/screens/settings';
import { commands, QuickPickItem, ExtensionContext, StatusBarAlignment, StatusBarItem, window, workspace, ConfigurationTarget, Uri, TextEditor } from 'vscode';
import { ConnectionDataUpdatedRequest, ConnectRequest, DisconnectRequest, GetConnectionDataRequest, GetConnectionPasswordRequest, GetConnectionsRequest, RefreshAllRequest, RunCommandRequest } from './contracts';
Expand All @@ -15,7 +15,7 @@ import CodeLensPlugin from '../codelens/extension';

export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin {
public client: SQLTools.LanguageClientInterface;
public resultsWebview: ResultsWebview;
public resultsWebview: ResultsWebviewManager;
public settingsWebview: SettingsWebview;
public statusBar: StatusBarItem;;
private context: ExtensionContext;
Expand Down Expand Up @@ -47,11 +47,9 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
let limit = 50;
if (ConfigManager.results && ConfigManager.results.limit) {
limit = ConfigManager.results.limit;
} else if ((<any>ConfigManager).previewLimit) { // @TODO: this is deprecated! Will be removed.
limit = (<any>ConfigManager).previewLimit;
}
const payload = await this._runConnectionCommandWithArgs('showRecords', table, limit);
this.resultsWebview.updateResults(payload);
this.resultsWebview.get(payload[0].connId || this.explorer.getActive().id).updateResults(payload);

} catch (e) {
this.errorHandler('Error while showing table records', e);
Expand All @@ -63,7 +61,7 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
const table = await this._getTableName(node);
this._openResultsWebview();
const payload = await this._runConnectionCommandWithArgs('describeTable', table);
this.resultsWebview.updateResults(payload);
this.resultsWebview.get(payload[0].connId || this.explorer.getActive().id).updateResults(payload);
} catch (e) {
this.errorHandler('Error while describing table records', e);
}
Expand Down Expand Up @@ -127,24 +125,24 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
}
}

private ext_executeQuery = async (query?: string, connName?: string) => {
private ext_executeQuery = async (query?: string, connNameOrId?: string) => {
try {
query = query || await getSelectedText('execute query');
if (!connName) {
connName = (query.match(/@conn\s*(.+)$/) || [])[1];
if (!connNameOrId) {
connNameOrId = (query.match(/@conn\s*(.+)$/) || [])[1];
}
if (connName && connName.trim()) {
connName = connName.trim();
const conn = (this.getConnectionList() || []).find(c => c.name === connName);
if (connNameOrId && connNameOrId.trim()) {
connNameOrId = connNameOrId.trim();
const conn = this.getConnectionList().find(c => getConnectionId(c) === connNameOrId || c.name === connNameOrId);
if (!conn) {
throw new Error(`Trying to run query on '${connName}' but it does not exist.`)
throw new Error(`Trying to run query on '${connNameOrId}' but it does not exist.`)
}
await this._setConnection(conn);
}
await this._connect();
this._openResultsWebview();
const payload = await this._runConnectionCommandWithArgs('query', query);
this.resultsWebview.updateResults(payload);
this.resultsWebview.get(payload[0].connId || this.explorer.getActive().id).updateResults(payload);
return payload;
} catch (e) {
this.errorHandler('Error fetching records.', e);
Expand All @@ -158,7 +156,7 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin

private ext_showOutputChannel = () => (<any>console).show();

private ext_saveResults = async (filetype: 'csv' | 'json') => {
private ext_saveResults = async (filetype: 'csv' | 'json', connId?: string) => {
filetype = typeof filetype === 'string' ? filetype : undefined;
let mode: any = filetype || ConfigManager.defaultExportType;
if (mode === 'prompt') {
Expand All @@ -172,7 +170,7 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin

if (!mode) return;

return this.resultsWebview.saveResults(mode);
return this.resultsWebview.get(connId || this.explorer.getActive().id).saveResults(mode);
}

private ext_openAddConnectionScreen = () => {
Expand Down Expand Up @@ -278,8 +276,8 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
return this._pickTable(conn, 'value');
}

private _openResultsWebview() {
this.resultsWebview.show();
private _openResultsWebview(connId?: string) {
this.resultsWebview.get(connId || this.explorer.getActive().id).show();
}
private _connect = async (force = false): Promise<ConnectionInterface> => {
if (!force && this.explorer.getActive()) {
Expand Down Expand Up @@ -401,17 +399,17 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
}

private getConnectionList(from?: ConfigurationTarget): ConnectionInterface[] {
if (!from) return workspace.getConfiguration(EXT_NAME.toLowerCase()).get('connections');
if (!from) return workspace.getConfiguration(EXT_NAME.toLowerCase()).get('connections') || [];

const config = workspace.getConfiguration(EXT_NAME.toLowerCase()).inspect('connections');
if (from === ConfigurationTarget.Global) {
return <ConnectionInterface[]>(config.globalValue || config.defaultValue);
return <ConnectionInterface[]>(config.globalValue || config.defaultValue) || [];
}
if (from === ConfigurationTarget.WorkspaceFolder) {
return <ConnectionInterface[]>(config.workspaceFolderValue || config.defaultValue);
return <ConnectionInterface[]>(config.workspaceFolderValue || config.defaultValue) || [];
}

return <ConnectionInterface[]>(config.workspaceValue || config.defaultValue);
return <ConnectionInterface[]>(config.workspaceValue || config.defaultValue) || [];
}

private ext_attachFileToConnection = async (fileUri: Uri) => {
Expand Down Expand Up @@ -453,7 +451,7 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin

// extension stuff
this.context.subscriptions.push(
(this.resultsWebview = new ResultsWebview(this.context, this.client)),
(this.resultsWebview = new ResultsWebviewManager(this.context, this.client)),
(this.settingsWebview = new SettingsWebview(this.context)),
this._updateStatusBar(),
workspace.onDidCloseTextDocument(this.ext_refreshAll),
Expand Down
28 changes: 11 additions & 17 deletions packages/plugins/connection-manager/screens/provider.ts
@@ -1,13 +1,18 @@
import path from 'path';
import { Uri, commands, Disposable, EventEmitter, ExtensionContext, ViewColumn, WebviewPanel, window } from 'vscode';

export default abstract class WebviewProvider<State = any> implements Disposable {
public disposeEvent: EventEmitter<never> = new EventEmitter();
public get onDidDispose() { return this.disposeEvent.event; }
public get onDidDispose() {
return this.disposeEvent.event;
}
public get visible() { return this.panel === undefined ? false : this.panel.visible; }
protected cssVariables: { [name: string]: string };
private get baseHtml(): string {
const cssVariables = Object.keys(this.cssVariables || {}).map(k => `--sqltools-${k}: ${this.cssVariables[k]}`).join(';');
const extRoot = Uri.file(this.context.asAbsolutePath('.'))
.with({ scheme: 'vscode-resource' })
.toString();

return `<!DOCTYPE html>
<html>
<head>
Expand All @@ -20,8 +25,8 @@ export default abstract class WebviewProvider<State = any> implements Disposable
</head>
<body>
<div id="root"></div>
<script src="{{extRoot}}/ui/vendor.js" type="text/javascript" charset="UTF-8"></script>
<script src="{{extRoot}}/ui/{{id}}.js" type="text/javascript" charset="UTF-8"></script>
<script src="${extRoot}/ui/vendor.js" type="text/javascript" charset="UTF-8"></script>
<script src="${extRoot}/ui/${this.id}.js" type="text/javascript" charset="UTF-8"></script>
</body>
</html>`;
}
Expand All @@ -31,13 +36,8 @@ export default abstract class WebviewProvider<State = any> implements Disposable
private panel: WebviewPanel;
private disposables: Disposable[] = [];
private messageCb;
private iconsPath: Uri;
private viewsPath: Uri;

public constructor(private context: ExtensionContext) {
this.iconsPath = Uri.file(path.join(context.extensionPath, 'icons')).with({ scheme: 'vscode-resource' })
this.viewsPath = Uri.file(path.join(context.extensionPath, 'ui')).with({ scheme: 'vscode-resource' })
}
public constructor(private context: ExtensionContext, private iconsPath: Uri, private viewsPath: Uri) {}
public preserveFocus = true;
public wereToShow = ViewColumn.One;
public show() {
Expand All @@ -61,13 +61,7 @@ export default abstract class WebviewProvider<State = any> implements Disposable
this.setPreviewActiveContext(webviewPanel.active);
}));
this.disposables.push(this.panel.onDidDispose(this.dispose, null, this.disposables));
this.panel.webview.html = (this.html || this.baseHtml)
.replace(/{{id}}/g, this.id)
.replace(
/{{extRoot}}/g,
Uri.file(this.context.asAbsolutePath('.'))
.with({ scheme: 'vscode-resource' })
.toString());
this.panel.webview.html = this.html || this.baseHtml;
}

this.updatePanelName();
Expand Down
35 changes: 31 additions & 4 deletions packages/plugins/connection-manager/screens/results.ts
Expand Up @@ -2,16 +2,17 @@ import SQLTools, { DatabaseInterface } from '@sqltools/core/plugin-api';
import { SaveResultsRequest } from '@sqltools/plugins/connection-manager/contracts';
import WebviewProvider from '@sqltools/plugins/connection-manager/screens/provider';
import QueryResultsState from '@sqltools/ui/screens/Results/State';
import vscode from 'vscode';
import vscode, { Uri } from 'vscode';
import ConfigManager from '@sqltools/core/config-manager';
import { getNameFromId } from '@sqltools/core/utils';
import path from 'path';

export default class ResultsWebview extends WebviewProvider<QueryResultsState> {
class ResultsWebview extends WebviewProvider<QueryResultsState> {
protected id: string = 'Results';
protected title: string = 'SQLTools Results';

constructor(context: vscode.ExtensionContext, private client: SQLTools.LanguageClientInterface) {
super(context);
constructor(context: vscode.ExtensionContext, private client: SQLTools.LanguageClientInterface, iconsPath: Uri, viewsPath: Uri) {
super(context, iconsPath, viewsPath);
}

public get cssVariables() {
Expand Down Expand Up @@ -74,3 +75,29 @@ export default class ResultsWebview extends WebviewProvider<QueryResultsState> {
wereToShow = vscode.ViewColumn.Active;
preserveFocus = false;
}

export default class ResultsWebviewManager {
private resultsMap: { [id: string]: ResultsWebview } = {};
private iconsPath: Uri;
private viewsPath: Uri;

constructor(private context: vscode.ExtensionContext, private client: SQLTools.LanguageClientInterface) {
this.iconsPath = Uri.file(path.join(this.context.extensionPath, 'icons')).with({ scheme: 'vscode-resource' });
this.viewsPath = Uri.file(path.join(this.context.extensionPath, 'ui')).with({ scheme: 'vscode-resource' });
}

dispose() {
return Promise.all(Object.keys(this.resultsMap).map(id => this.resultsMap[id].dispose()));
}

private createForId(connId: string) {
this.resultsMap[connId] = new ResultsWebview(this.context, this.client, this.iconsPath, this.viewsPath);
return this.resultsMap[connId];
}

get(connId: string) {
if (!connId) throw new Error('Missing connection id to create results view');

return this.resultsMap[connId] || this.createForId(connId);
}
}
9 changes: 7 additions & 2 deletions packages/plugins/connection-manager/screens/settings.ts
@@ -1,14 +1,19 @@
import { EXT_NAME } from '@sqltools/core/constants';
import { getConnectionId } from '@sqltools/core/utils';
import WebviewProvider from '@sqltools/plugins/connection-manager/screens/provider';
import { commands, ExtensionContext } from 'vscode';
import { commands, ExtensionContext, Uri } from 'vscode';
import path from 'path';

export default class SettingsWebview extends WebviewProvider {
protected id: string = 'Settings';
protected title: string = 'SQLTools Settings';

constructor(context: ExtensionContext) {
super(context);
super(
context,
Uri.file(path.join(context.extensionPath, 'icons')).with({ scheme: 'vscode-resource' }),
Uri.file(path.join(context.extensionPath, 'ui')).with({ scheme: 'vscode-resource' })
);
this.setMessageCallback(({ action, payload }) => {
switch (action) {
case 'createConnection':
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/screens/Results/ResultsTable.tsx
Expand Up @@ -304,7 +304,7 @@ export default class ResultsTable extends React.PureComponent<ResultsTableProps,
action: 'call',
payload: {
command: `${process.env.EXT_NAME}.executeQuery`,
args: [this.props.query]
args: [this.props.query, this.props.connId]
}
});
break;
Expand All @@ -313,7 +313,7 @@ export default class ResultsTable extends React.PureComponent<ResultsTableProps,
action: 'call',
payload: {
command: `${process.env.EXT_NAME}.saveResults`,
args: ['csv']
args: ['csv', this.props.connId]
}
});
break;
Expand All @@ -322,7 +322,7 @@ export default class ResultsTable extends React.PureComponent<ResultsTableProps,
action: 'call',
payload: {
command: `${process.env.EXT_NAME}.saveResults`,
args: ['json']
args: ['json', this.props.connId]
}
});
break;
Expand Down

0 comments on commit e93e10c

Please sign in to comment.