diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d006d9dd0..485998a11 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,7 +3,6 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "runem.lit-plugin", - "connor4312.esbuild-problem-matchers", "ecmel.vscode-launcher" ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5c9008fb7..33ea3abb1 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,15 +5,35 @@ "type": "npm", "script": "watch", "group": "build", - "problemMatcher": "$esbuild-watch", "isBackground": true, - "label": "npm: watch" + "label": "npm: watch", + "problemMatcher": { + "owner": "typescript", + "source": "ts", + "applyTo": "closedDocuments", + "fileLocation": ["relative", "${cwd}"], + "pattern": { + "regexp": "^Error: Build failed[^:]*:([^:]*):([^:]*):([^:]*): (ERROR:.*)$", + "file": 1, + "line": 2, + "column": 3, + "message": 4 + }, + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "^esbuild:started$" + }, + "endsPattern": { + "regexp": "^esbuild:watching$" + } + } + } }, { "type": "npm", "script": "build", "group": "build", - "problemMatcher": "$esbuild", "label": "npm: build" } ] diff --git a/esbuild.js b/esbuild.mjs similarity index 51% rename from esbuild.js rename to esbuild.mjs index 5aa09ed9d..e8da95c44 100644 --- a/esbuild.js +++ b/esbuild.mjs @@ -1,18 +1,19 @@ -const { build } = require("esbuild"); -const fs = require("fs"); -const path = require("path"); -const glob = require("glob"); +import { context, build } from "esbuild"; +import { copyFileSync, mkdirSync } from "fs"; +import { sync } from "glob"; +import { join, basename } from "path"; function copyFiles(srcPattern, destDir) { - glob.sync(srcPattern).forEach((file) => { - const destFile = path.join(destDir, path.basename(file)); - fs.copyFileSync(file, destFile); + sync(srcPattern).forEach((file) => { + const destFile = join(destDir, basename(file)); + copyFileSync(file, destFile); }); } const minify = process.argv.includes("--minify"); const sourcemap = process.argv.includes("--sourcemap"); const keepNames = process.argv.includes("--keep-names"); +const watch = process.argv.includes("--watch"); const baseConfig = { minify, @@ -50,24 +51,26 @@ const webviewConfig = { (async () => { try { - await build(extensionConfig); - console.log("extension build complete"); - await build(serverConfig); - console.log("server build complete"); - await build(webviewConfig); + mkdirSync("./out", { recursive: true }); copyFiles("src/webview/styles/*.css", "./out"); - copyFiles("node_modules/ag-grid-community/styles/ag-grid.min.css", "./out"); - copyFiles( - "node_modules/ag-grid-community/styles/ag-theme-alpine.min.css", - "./out", - ); - copyFiles( - "node_modules/ag-grid-community/dist/ag-grid-community.min.js", - "./out", - ); - console.log("build complete"); + + if (watch) { + console.log("esbuild:started"); + const contexts = await Promise.all([ + context(serverConfig), + context(webviewConfig), + context(extensionConfig), + ]); + await Promise.all(contexts.map((ctx) => ctx.rebuild())); + contexts.forEach((ctx) => ctx.watch({ delay: 500 })); + console.log("esbuild:watching"); + } else { + await build(serverConfig); + await build(webviewConfig); + await build(extensionConfig); + } } catch (err) { - process.stderr.write(err.stderr); + console.error(err); process.exit(1); } })(); diff --git a/eslint.config.mjs b/eslint.config.mjs index 99f372928..ed05b4bdd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,16 +1,3 @@ -/* - * Copyright (c) 1998-2025 KX Systems Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - import js from "@eslint/js"; import headerPlugin from "eslint-plugin-header"; import importPlugin from "eslint-plugin-import"; @@ -22,7 +9,7 @@ const currentYear = new Date().getFullYear(); export default [ { - ignores: ["**/*.d.ts", "**/*.js", "src/ipc/**"], + ignores: ["**/*.d.ts", "**/*.js", "**/*.mjs", "src/ipc/**"], }, js.configs.recommended, ...tseslint.configs.recommended, diff --git a/package-lock.json b/package-lock.json index 1ede12e54..9d1d51349 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,6 @@ "@vscode/python-extension": "1.0.6", "@vscode/test-electron": "2.5.2", "@vscode/vsce": "3.7.1", - "ag-grid-community": "34.3.1", "axios": "1.13.2", "c8": "10.1.3", "chevrotain": "10.5.0", @@ -2769,23 +2768,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/ag-charts-types": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-12.3.1.tgz", - "integrity": "sha512-5216xYoawnvMXDFI6kTpPku+mH0Csiwu/FE7lsAm8Z22HEN6ciSG/V7g+IrpLWncELqksgENebCTP75PZ3CsHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ag-grid-community": { - "version": "34.3.1", - "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-34.3.1.tgz", - "integrity": "sha512-PwlrPudsFOzGumphi2y9ihWeaUlIwKhOra/MXu2LjeV2U8DgLLcYS8CartE5Hszhn1poJHawwI9HWrxlKliwdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ag-charts-types": "12.3.1" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", diff --git a/package.json b/package.json index 11a066750..fb40a9394 100644 --- a/package.json +++ b/package.json @@ -1185,7 +1185,7 @@ "update-deps": "ncu --target patch -u", "format": "prettier --write \"**/*.+(js|ts)\"", "lint": "eslint $(git ls-files '*.ts') --fix --no-warn-ignored", - "esbuild-base": "rimraf out && node ./esbuild.js", + "esbuild-base": "rimraf out && node ./esbuild.mjs", "watch": "npm run -S esbuild-base -- --sourcemap --watch", "build": "npm run -S esbuild-base -- --sourcemap", "vscode:prepublish": "npm run -S esbuild-base -- --minify --keep-names", @@ -1216,7 +1216,6 @@ "@vscode/python-extension": "1.0.6", "@vscode/test-electron": "2.5.2", "@vscode/vsce": "3.7.1", - "ag-grid-community": "34.3.1", "axios": "1.13.2", "c8": "10.1.3", "chevrotain": "10.5.0", diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 4ab4b2342..1f4685805 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -23,7 +23,6 @@ import { window, workspace, env, - ProgressLocation, } from "vscode"; import { ext } from "../extensionVariables"; @@ -1152,9 +1151,6 @@ export async function runQuery( ); }); - if (isInsights) { - runner.location = ProgressLocation.Notification; - } runner.title = `Executing ${executorName} on ${connLabel || "active connection"}.`; return !isInsights || ((target || isSql) && !variable) diff --git a/src/services/resultsPanelProvider.ts b/src/services/resultsPanelProvider.ts index 8d708f809..a65968cdc 100644 --- a/src/services/resultsPanelProvider.ts +++ b/src/services/resultsPanelProvider.ts @@ -11,10 +11,10 @@ * specific language governing permissions and limitations under the License. */ -import { GridOptions } from "ag-grid-community"; import { ColorThemeKind, Uri, + Webview, WebviewView, WebviewViewProvider, window, @@ -61,7 +61,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { localResourceRoots: [Uri.joinPath(this._extensionUri, "out")], }; - webviewView.webview.html = this._getWebviewContent(); + webviewView.webview.html = this.getWebviewContent(webviewView.webview); ext.isResultsTabVisible = this._view?.visible || false; @@ -166,10 +166,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { this.postMessageToWebview(gridOptions, result); } - private postMessageToWebview( - gridOptions: GridOptions | undefined, - result: string, - ) { + private postMessageToWebview(gridOptions: any | undefined, result: string) { if (this._view) { if (gridOptions) { this._view.webview.postMessage({ @@ -188,169 +185,33 @@ export class KdbResultsViewProvider implements WebviewViewProvider { } } - private _getWebviewContent() { - const agGridTheme = this.defineAgGridTheme(); - if (this._view) { - const webviewUri = getUri(this._view.webview, this._extensionUri, [ - "out", - "webview.js", - ]); - const nonce = getNonce(); - return /*html*/ ` - - - - - - - - - - - Q Results - - - -
-
-
-
-
-
-
Loading data...
-
-
- -
- - - - `; - } else { - return ""; - } + private getWebviewContent(webview: Webview) { + /* c8 ignore start */ + const getResource = (resource: string) => + getUri(webview, ext.context.extensionUri, resource.split("/")); + + const getTheme = () => + window.activeColorTheme.kind === ColorThemeKind.Light || + window.activeColorTheme.kind === ColorThemeKind.HighContrastLight + ? "sl-theme-light" + : "sl-theme-dark"; + + return /* html */ ` + + + + + + + + + KDB Results + + + + + + `; + /* c8 ignore stop */ } } diff --git a/src/utils/resultsRenderer.ts b/src/utils/resultsRenderer.ts index e7c62faa0..597d58f01 100644 --- a/src/utils/resultsRenderer.ts +++ b/src/utils/resultsRenderer.ts @@ -11,8 +11,6 @@ * specific language governing permissions and limitations under the License. */ -import { GridOptions } from "ag-grid-community"; - import { ext } from "../extensionVariables"; import { isBaseVersionGreaterOrEqual } from "./core"; import { decodeQUTF } from "./decode"; @@ -23,7 +21,7 @@ export function convertToGrid( isInsights: boolean, connVersion?: number, isPython?: boolean, -): GridOptions { +): any { let rowData = []; let columnDefs = []; @@ -91,7 +89,7 @@ export function convertToGrid( ext.resultPanelCSV = convertToCsv(rowData).join("\n"); } - const gridOptions: GridOptions = { + const gridOptions: any = { rowData: rowData, columnDefs: columnDefs, }; diff --git a/src/webview/components/kdbResultsView.ts b/src/webview/components/kdbResultsView.ts new file mode 100644 index 000000000..e4528627f --- /dev/null +++ b/src/webview/components/kdbResultsView.ts @@ -0,0 +1,311 @@ +/* + * Copyright (c) 1998-2025 KX Systems Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +/* c8 ignore start */ + +import { LitElement, css, html } from "lit"; +import { customElement, property, query, state } from "lit/decorators.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { when } from "lit/directives/when.js"; + +import { shoelaceStyles } from "./styles"; + +@customElement("kdb-results-view") +export class KdbResultsView extends LitElement { + static readonly styles = [ + shoelaceStyles, + css` + table, + thead, + tbody, + tr, + th, + td, + p { + margin: 0; + padding: 0; + } + table { + border-spacing: 0; + border-collapse: separate; + min-width: 100vw; + } + thead { + position: sticky; + top: 0; + z-index: 1000; + background-color: var(--vscode-editor-background); + tr { + background-color: var(--vscode-keybindingTable-rowsBackground); + } + th:last-child { + width: 100%; + } + } + tbody { + tr:nth-child(even) { + background-color: var(--vscode-keybindingTable-rowsBackground); + } + } + th, + td { + text-align: left; + border-bottom-color: var(--vscode-editorGroup-border); + border-bottom-style: solid; + border-bottom-width: 1px; + } + th { + font-weight: 600; + line-height: 1.25; + padding: 0.25em 0.5em; + } + td { + padding: 0 0.5em; + } + .faint { + font-weight: 200; + } + .container { + width: 100vw; + height: 100vh; + overflow: auto; + } + .pager { + position: fixed; + right: 1em; + bottom: 0.75em; + opacity: 0.5; + background-color: var(--vscode-editor-background); + } + .pager:hover { + opacity: 1; + } + `, + ]; + + @property({ type: Number }) + size = 100; + + @state() + columnDefs = []; + @state() + results = []; + @state() + page = 0; + @state() + rows = []; + @state() + content = ""; + + @query(".container") + container: HTMLElement | undefined; + + private get total() { + return Math.ceil(this.results.length / this.size); + } + + readonly vscode = acquireVsCodeApi(); + + connectedCallback() { + super.connectedCallback(); + window.addEventListener("message", this.message); + } + + disconnectedCallback() { + window.removeEventListener("message", this.message); + super.disconnectedCallback(); + } + + message = (event: MessageEvent) => { + switch (event.data.command) { + case "setGridDatasource": + this.columnDefs = event.data.columnDefs; + this.results = event.data.results; + this.content = ""; + this.page = 0; + this.renderPage(); + break; + case "setResultsContent": + this.content = event.data.results; + this.columnDefs = []; + this.results = []; + this.rows = []; + this.page = 0; + break; + default: + case "loading": + break; + } + }; + + private toTop() { + if (this.container) this.container.scrollTop = 0; + } + + private renderPage() { + this.rows = this.results.slice( + this.size * this.page, + this.size * this.page + this.size, + ); + this.toTop(); + } + + private getHeader(header: string) { + const parts = header.split("["); + let type = parts[1]; + if (type) type = type.slice(0, -1); + return type + ? html`${parts[0]}
${type}` + : parts[0]; + } + + protected render() { + return html` +
+ ${this.content + ? unsafeHTML(this.content) + : html` + + + + ${this.columnDefs.map( + (col: any) => + html``, + )} + + + + ${this.rows.map( + (row: any) => html` + + ${this.columnDefs.map( + (col: any) => html``, + )} + + `, + )} + +
${this.getHeader(col.headerName)}
${row[col.field]}
+ ${when( + this.total > 1, + () => html` + + + + + + + + + + + + + ${this.page + 1} / ${this.total} + + + + + + + + + + + + + `, + )} + `} +
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "kdb-results-view": KdbResultsView; + } +} + +/* c8 ignore stop */ diff --git a/src/webview/main.ts b/src/webview/main.ts index 2712ca02a..a2f9c1aa3 100644 --- a/src/webview/main.ts +++ b/src/webview/main.ts @@ -36,3 +36,4 @@ import "./components/kdbWelcomeView"; import "./components/kdbDataSourceView"; import "./components/kdbNewConnectionView"; import "./components/kdbChartView"; +import "./components/kdbResultsView"; diff --git a/src/webview/styles/dataSourcesPanel.css b/src/webview/styles/dataSourcesPanel.css deleted file mode 100644 index 5c6b6d7ba..000000000 --- a/src/webview/styles/dataSourcesPanel.css +++ /dev/null @@ -1,136 +0,0 @@ -.datasource-view-container { - width: 100%; - height: 100%; -} - -.header-wrapper { - display: block; - width: 100%; - float: left; -} - -.btn-types-group { - display: block; - float: left; -} - -.btn-api, -.btn-qsql, -.btn-sql { - width: 100px; - margin: 0 5px; -} - -.btn-api { - margin-right: 5px; - margin-left: 0px; -} - -.btn-actions-group { - display: block; - float: right; -} - -.content-wrapper { - display: block; - width: 100%; - float: left; - margin-top: 25px; -} - -.form-wrapper { - display: block; - width: calc(100vw - 240px); - float: left; - overflow: scroll; -} -.actions-wrapper { - display: grid; - width: 150px; - min-width: 120px; - margin-top: 130px; -} - -.btn-action { - width: 100%; - margin: 0 10px 10px 10px; -} - -.btn-save, -.btn-run, -.btn-scratchpad { - width: 120px; -} - -.api-editor, -.qsql-editor, -.sql-editor { - width: 100%; - height: 100%; - border: 1px solid #ccc; - border-radius: 5px; - padding: 5px; - font-family: monospace; -} -.editor-panel { - width: 100%; - display: flex; - flex-wrap: wrap; - align-content: center; - justify-content: space-between; - align-items: center; -} - -.field-row { - width: 100%; - float: left; - margin-bottom: 10px; -} - -.dropdown-container { - width: 100%; - align-items: center; - align-content: center; - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} -.dropdown { - width: 100%; - min-width: 530px; -} - -.text-input { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - align-content: space-between; - align-items: center; - width: 100%; -} - -.text-input > .root { - width: 100%; -} - -.text-area { - width: 100%; -} - -.params-wrapper { - display: flex; - flex-wrap: wrap; - align-content: space-between; - justify-content: space-between; - align-items: center; - width: 100%; -} - -label { - min-width: 65px; - margin-bottom: 5px; -} - -.name-row { - display: grid; -} diff --git a/src/webview/styles/reset.css b/src/webview/styles/reset.css deleted file mode 100644 index 0e3b4cf5c..000000000 --- a/src/webview/styles/reset.css +++ /dev/null @@ -1,30 +0,0 @@ -html { - box-sizing: border-box; - font-size: 13px; -} - -*, -*:before, -*:after { - box-sizing: inherit; -} - -body, -h1, -h2, -h3, -h4, -h5, -h6, -p, -ol, -ul { - margin: 0; - padding: 0; - font-weight: normal; -} - -img { - max-width: 100%; - height: auto; -} diff --git a/src/webview/styles/resultsPanel.css b/src/webview/styles/resultsPanel.css deleted file mode 100644 index 19ff2511f..000000000 --- a/src/webview/styles/resultsPanel.css +++ /dev/null @@ -1,98 +0,0 @@ -html, -body { - height: 86vh; - width: 99%; - padding: 0; - box-sizing: border-box; - -webkit-overflow-scrolling: touch; -} - -body { - margin: 8px; -} - -.header-wrapper { - display: block; - width: 100%; - float: left; -} - -.results-datagrid { - background: #00000010; -} - -.results-header-datagrid { - background: #00000050; -} - -.results-txt { - font-family: monospace; - white-space: pre; -} - -/* styles.css */ - -.custom-ag-grid-header { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - width: 100%; -} - -.custom-ag-grid-header-title { - font-weight: bold; - font-size: 14px; -} - -.custom-ag-grid-header-subtitle { - font-size: 12px; - color: #666666; -} - -.overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - justify-content: center; - align-items: center; - z-index: 1000; - display: none; -} - -.loading-box { - background: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); - padding: 20px; - border-radius: 8px; - display: flex; - flex-direction: column; - align-items: center; -} - -.spinner { - border: 4px solid rgba(0, 0, 0, 0.1); - border-left-color: var(--vscode-progressBar-background); - border-radius: 50%; - width: 40px; - height: 40px; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -.loading-text { - margin-top: 10px; - font-size: 14px; -} diff --git a/src/webview/styles/vscode.css b/src/webview/styles/vscode.css deleted file mode 100644 index 4ea74bec7..000000000 --- a/src/webview/styles/vscode.css +++ /dev/null @@ -1,91 +0,0 @@ -:root { - --container-padding: 20px; - --input-padding-vertical: 6px; - --input-padding-horizontal: 4px; - --input-margin-vertical: 4px; - --input-margin-horizontal: 0; -} - -body { - padding: 0 var(--container-padding); - color: var(--vscode-foreground); - font-size: var(--vscode-font-size); - font-weight: var(--vscode-font-weight); - font-family: var(--vscode-font-family); - background-color: var(--vscode-editor-background); -} - -ol, -ul { - padding-left: var(--container-padding); -} - -body > *, -form > * { - margin-block-start: var(--input-margin-vertical); - margin-block-end: var(--input-margin-vertical); -} - -*:focus { - outline-color: var(--vscode-focusBorder) !important; -} - -a { - color: var(--vscode-textLink-foreground); -} - -a:hover, -a:active { - color: var(--vscode-textLink-activeForeground); -} - -code { - font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); -} - -button { - border: none; - padding: var(--input-padding-vertical) var(--input-padding-horizontal); - width: 100%; - text-align: center; - outline: 1px solid transparent; - outline-offset: 2px !important; - color: var(--vscode-button-foreground); - background: var(--vscode-button-background); -} - -button:hover { - cursor: pointer; - background: var(--vscode-button-hoverBackground); -} - -button:focus { - outline-color: var(--vscode-focusBorder); -} - -button.secondary { - color: var(--vscode-button-secondaryForeground); - background: var(--vscode-button-secondaryBackground); -} - -button.secondary:hover { - background: var(--vscode-button-secondaryHoverBackground); -} - -input:not([type="checkbox"]), -textarea { - display: block; - width: 100%; - border: none; - font-family: var(--vscode-font-family); - padding: var(--input-padding-vertical) var(--input-padding-horizontal); - color: var(--vscode-input-foreground); - outline-color: var(--vscode-input-border); - background-color: var(--vscode-input-background); -} - -input::placeholder, -textarea::placeholder { - color: var(--vscode-input-placeholderForeground); -} diff --git a/test/fixtures/webview.ts b/test/fixtures/webview.ts index 9733edd8b..a96846ea3 100644 --- a/test/fixtures/webview.ts +++ b/test/fixtures/webview.ts @@ -43,6 +43,7 @@ export function css(strings: any, ...values: unknown[]) { export function customElement() {} export function state() {} export function property() {} +export function query() {} export function repeat(items: Iterable, keyFn: any, template: any) { for (const item of items) { keyFn(item); diff --git a/test/suite/webPanels/resultsPanelProvider.test.ts b/test/suite/webPanels/resultsPanelProvider.test.ts index f15b8b543..bae0610b4 100644 --- a/test/suite/webPanels/resultsPanelProvider.test.ts +++ b/test/suite/webPanels/resultsPanelProvider.test.ts @@ -531,12 +531,6 @@ describe("ResultsPanelProvider", () => { resultsPanel = new KdbResultsViewProvider(uriTest); resultsPanel["_view"] = view; }); - - it("should render the results tab", () => { - const expectedOutput = ` id="results" class="results-view-container"`; - const actualOutput = resultsPanel["_getWebviewContent"](); - assert.ok(actualOutput.includes(expectedOutput)); - }); }); describe("updateResults", () => { diff --git a/test/suite/webPanels/webViews/kdbResultsView.test.ts b/test/suite/webPanels/webViews/kdbResultsView.test.ts new file mode 100644 index 000000000..fa5434cd9 --- /dev/null +++ b/test/suite/webPanels/webViews/kdbResultsView.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1998-2025 KX Systems Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +/* eslint @typescript-eslint/no-explicit-any: 0 */ + +import "../../../fixtures"; +import * as assert from "assert"; +import * as sinon from "sinon"; + +import { KdbResultsView } from "../../../../src/webview/components/kdbResultsView"; + +describe("kdbResultsView", () => { + let view: KdbResultsView; + beforeEach(() => { + view = new KdbResultsView(); + }); + afterEach(() => { + sinon.restore(); + }); + it("should exists", () => { + assert.ok(view); + }); +});