Browse Source

refactor view manager

pull/26/head
cweijan 5 years ago
parent
commit
88596d8e2f
  1. 2
      README.md
  2. 6
      resources/webview/pages/connect/components/option.html
  3. 5
      resources/webview/pages/connect/connect.html
  4. 4
      src/extension.ts
  5. 2
      src/model/interface/node.ts
  6. 3
      src/service/connectionManager.ts
  7. 2
      src/service/mock/mockRunner.ts
  8. 4
      src/service/serviceManager.ts
  9. 58
      src/view/result/query.ts
  10. 97
      src/view/viewManager.ts

2
README.md

@ -9,6 +9,8 @@ MySQL Client For Visual Studio Code
>
> Give [project](https://github.com/cweijan/vscode-mysql) star keep me motivated to keep updating
**Features**
- [MySQL Client](#mysql-client)
- [Connection](#connection)
- [View Table](#view-table)

6
resources/webview/pages/connect/components/option.html

@ -27,4 +27,10 @@
<b>database:</b>
<input class="field__input" placeholder="database, can be null" v-model="connectionOption.database" />
</div>
</div>
<div>
<div class="field field__input">
<b>timezone:</b>
<input class="field__input" placeholder="timezone, can be null" v-model="connectionOption.timezone" />
</div>
</div>

5
resources/webview/pages/connect/connect.html

@ -45,7 +45,8 @@
</div>
<script>
const vscode = acquireVsCodeApi();
const vscode = typeof (acquireVsCodeApi) != "undefined" ? acquireVsCodeApi() : null;
const postMessage = (message) => { if (vscode) { vscode.postMessage(message) } }
const vue = new Vue({
el: '#container',
data: {
@ -56,6 +57,7 @@
password: '',
database: null,
usingSSH: false,
timezone: null,
ssh: {
port: 22,
username: 'root'
@ -83,6 +85,7 @@
document.write("Connect success!")
}
})
postMessage({ type: 'init' })
</script>
</body>

4
src/extension.ts

@ -21,7 +21,7 @@ import { ColumnNode } from "./model/other/columnNode";
import { Console } from "./common/outputChannel";
// must be last
import { ServiceManager } from "./service/serviceManager";
import { SqlViewManager } from "./view/SqlViewManager";
import { ViewManager } from "./view/viewManager";
import { QueryUnit } from "./service/queryUnit";
import { Node } from "./model/interface/node";
@ -50,7 +50,7 @@ export function activate(context: vscode.ExtensionContext) {
serviceManager.mockRunner.runMock()
},
"mysql.addConnection": () => {
SqlViewManager.showConnectPage(serviceManager.provider);
ViewManager.showConnectPage(serviceManager.provider);
},
"mysql.addDatabase": (connectionNode: ConnectionNode) => {
connectionNode.createDatabase();

2
src/model/interface/node.ts

@ -9,6 +9,7 @@ export abstract class Node extends vscode.TreeItem {
public user: string;
public password?: string;
public database?: string;
public timezone?: string;
public certPath?: string;
public origin?: Node;
@ -33,6 +34,7 @@ export abstract class Node extends vscode.TreeItem {
this.user = source.user
this.password = source.password
this.database = source.database
this.timezone = source.timezone
this.certPath = source.certPath
this.ssh = source.ssh
this.usingSSH = source.usingSSH

3
src/service/connectionManager.ts

@ -56,6 +56,7 @@ export class ConnectionManager {
}
if (host != null && port != null && user != null) {
// TODO lost infomation
return this.getConnection({
host, port, user, database, getConnectId: () => `${host}_${port}_${user}`
} as Node, database != null)
@ -126,7 +127,7 @@ export class ConnectionManager {
return new Promise(async (resolve) => {
const ssh = connectionNode.ssh
if (!connectionNode.ssh.tunnelPort) {
connectionNode.ssh.tunnelPort = await getPort({ port: getPort.makeRange(10567, 11567) })
connectionNode.ssh.tunnelPort = await getPort({ port: 10567 })
}
const port = connectionNode.ssh.tunnelPort;
const key = `${ssh.username}_${ssh.port}_${ssh.username}`;

2
src/service/mock/mockRunner.ts

@ -93,7 +93,7 @@ export class MockRunner {
sqlList.push(tempInsertSql)
}
const connection = await ConnectionManager.getConnection({ ...mockModel, getConnectId: () => `${mockModel.host}_${mockModel.port}_${mockModel.user}` } as any as Node)
const connection = await ConnectionManager.getConnection({ ...mockModel, timezone: tableNode.timezone, getConnectId: () => `${mockModel.host}_${mockModel.port}_${mockModel.user}` } as any as Node)
const success = await QueryUnit.runBatch(connection, sqlList)
vscode.commands.executeCommand("mysql.template.sql", tableNode, true)

4
src/service/serviceManager.ts

@ -1,7 +1,7 @@
import * as vscode from "vscode";
import { MockRunner } from "./mock/mockRunner";
import { ExtensionContext } from "vscode";
import { SqlViewManager } from "../view/SqlViewManager";
import { ViewManager } from "../view/viewManager";
import { DatabaseCache } from "./databaseCache";
import { FileManager } from "../common/FileManager";
import { SqlFormatProvider } from "../provider/SqlFormatProvider";
@ -29,7 +29,7 @@ export class ServiceManager {
this.mockRunner = new MockRunner();
this.historyService = new HistoryService()
DatabaseCache.initCache(context);
SqlViewManager.initExtesnsionPath(context.extensionPath);
ViewManager.initExtesnsionPath(context.extensionPath);
FileManager.init(context)
}

58
src/view/result/query.ts

@ -1,29 +1,22 @@
import * as vscode from "vscode";
import { WebviewPanel } from "vscode";
import { MessageType, OperateType } from "../../common/Constants";
import { SqlViewManager } from "../SqlViewManager";
import { Node } from "../../model/interface/node";
import { ColumnNode } from "../../model/other/columnNode";
import { DatabaseCache } from "../../service/databaseCache";
import { QueryUnit } from "../../service/queryUnit";
import { ColumnNode } from "../../model/other/columnNode";
import { ViewManager } from "../viewManager";
import { DataResponse } from "./queryResponse";
import { Node } from "../../model/interface/node";
export class QueryParam<T> {
public type: MessageType;
/**
* using in loadColumnList
* using in loadColumnList.
*/
public connection?: Node;
public type: MessageType;
public res: T;
}
export class QueryPage {
private static resultWebviewPanel: WebviewPanel;
/**
* ensure send newest message.
*/
private static sendData: any;
private static creating = false;
public static async send(queryParam: QueryParam<any>) {
switch (queryParam.type) {
@ -39,38 +32,18 @@ export class QueryPage {
break;
}
this.sendData = queryParam;
if (this.creating) { return; }
// update result webview
if (this.resultWebviewPanel) {
if (this.resultWebviewPanel.visible) {
this.resultWebviewPanel.webview.postMessage(QueryPage.sendData);
this.resultWebviewPanel.reveal(vscode.ViewColumn.Two, true);
return;
} else {
this.resultWebviewPanel.dispose();
}
}
// init result webview
this.creating = true;
SqlViewManager.createWebviewPanel({
splitResultView: true, viewPath: "pages/result/index", viewTitle: "Query",
}).then(async (webviewPanel) => {
this.resultWebviewPanel = webviewPanel;
this.creating = false;
webviewPanel.onDidDispose(() => { this.resultWebviewPanel = undefined; this.creating = false; });
webviewPanel.webview.onDidReceiveMessage((params) => {
ViewManager.createWebviewPanel({
splitView: true, path: "pages/result/index", title: "Query",
initListener: (webviewPanel) => {
webviewPanel.webview.postMessage(queryParam);
},
receiveListener: async (_, params) => {
switch (params.type) {
case OperateType.init:
webviewPanel.webview.postMessage(QueryPage.sendData);
break;
case OperateType.execute:
QueryUnit.runQuery(params.sql);
break;
}
});
}
});
}
@ -100,9 +73,4 @@ export class QueryPage {
queryParam.connection = null;
}
}
class TableInfo {
public database: string;
public table: string;
}

97
src/view/SqlViewManager.ts → src/view/viewManager.ts

@ -7,19 +7,37 @@ import { Console } from "../common/OutputChannel";
import { MySQLTreeDataProvider } from "../provider/treeDataProvider";
export class ViewOption {
public viewPath?: string;
public viewTitle?: string;
public splitResultView: boolean = false;
public path?: string;
public title?: string;
public splitView: boolean = false;
/**
* keep single page by viewType
*/
public singlePage?: boolean;
/**
* kill exists panel
*/
public killHidden?: boolean;
/**
* receive webview send message
*/
public receiveListener?: (message: any) => {};
public receiveListener?: (viewPanel: WebviewPanel, message: any) => void;
/**
* callback when init success.
*/
public initListener?: (viewPanel: WebviewPanel) => void;
}
public disposeListener?: (message: any) => {};
interface ViewState {
instance: WebviewPanel;
creating: boolean;
initListener: (viewPanel: WebviewPanel) => void;
receiveListener: (viewPanel: WebviewPanel, message: any) => void
}
export class SqlViewManager {
export class ViewManager {
private static viewStatu: { [key: string]: ViewState } = {};
private static webviewPath: string;
public static initExtesnsionPath(extensionPath: string) {
this.webviewPath = extensionPath + "/resources/webview"
@ -28,11 +46,10 @@ export class SqlViewManager {
public static showConnectPage(provider: MySQLTreeDataProvider) {
this.createWebviewPanel({
viewPath: "pages/connect/connect",
viewTitle: "connect",
splitResultView: false,
}).then((webviewPanel) => {
webviewPanel.webview.onDidReceiveMessage((params) => {
path: "pages/connect/connect",
title: "connect",
splitView: false,
receiveListener: (webviewPanel, params) => {
if (params.type === 'CONNECT_TO_SQL_SERVER') {
const { connectionOption } = params
if (connectionOption.usingSSH) {
@ -50,16 +67,34 @@ export class SqlViewManager {
});
});
}
});
}
});
}
public static createWebviewPanel(viewOption: ViewOption): Promise<WebviewPanel> {
const columnType = viewOption.splitResultView ? vscode.ViewColumn.Two : vscode.ViewColumn.One;
const currentStatus = this.viewStatu[viewOption.title]
if (!currentStatus) { this.viewStatu[viewOption.title] = { creating: true } as ViewState }
if (typeof (viewOption.singlePage) == 'undefined') { viewOption.singlePage = true }
if (typeof (viewOption.killHidden) == 'undefined') { viewOption.killHidden = true }
if (viewOption.singlePage && currentStatus) {
if (viewOption.killHidden && currentStatus.instance.visible == false) {
currentStatus.instance.dispose()
} else {
if (currentStatus.creating) {
currentStatus.initListener = viewOption.initListener
} else if (viewOption.initListener) {
viewOption.initListener(currentStatus.instance)
}
if (viewOption.receiveListener) { currentStatus.receiveListener = viewOption.receiveListener }
return Promise.resolve(currentStatus.instance);
}
}
return new Promise((resolve, reject) => {
const targetPath = `${this.webviewPath}/${viewOption.viewPath}.html`;
const targetPath = `${this.webviewPath}/${viewOption.path}.html`;
fs.readFile(targetPath, 'utf8', async (err, data) => {
if (err) {
Console.log(err);
@ -67,15 +102,35 @@ export class SqlViewManager {
return;
}
const webviewPanel = vscode.window.createWebviewPanel(
"mysql.sql.result",
viewOption.viewTitle,
{ viewColumn: columnType, preserveFocus: true },
viewOption.title,
viewOption.title,
{
viewColumn: viewOption.splitView ? vscode.ViewColumn.Two : vscode.ViewColumn.One,
preserveFocus: true
},
{ enableScripts: true, retainContextWhenHidden: true },
);
webviewPanel.webview.html = this.buildInclude(this.buildPath(data), path.resolve(targetPath, ".."));
webviewPanel.webview.onDidReceiveMessage(viewOption.receiveListener);
webviewPanel.onDidDispose(viewOption.disposeListener);
this.viewStatu[viewOption.title] = {
creating: true,
instance: webviewPanel,
initListener: viewOption.initListener,
receiveListener: viewOption.receiveListener
}
webviewPanel.onDidDispose(() => {
this.viewStatu[viewOption.title] = null
})
const newStatus = this.viewStatu[viewOption.title]
webviewPanel.webview.onDidReceiveMessage((message) => {
if (message.type == 'init') {
newStatus.creating = false
if (newStatus.initListener) {
newStatus.initListener(webviewPanel)
}
} else if (newStatus.receiveListener) {
newStatus.receiveListener(webviewPanel, message)
}
})
resolve(webviewPanel);
});
Loading…
Cancel
Save