diff --git a/tooling/pipeline-results-viewer/index.html b/tooling/pipeline-results-viewer/index.html
index fedae0d..52a4ba9 100644
--- a/tooling/pipeline-results-viewer/index.html
+++ b/tooling/pipeline-results-viewer/index.html
@@ -11,13 +11,62 @@
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
-
-
diff --git a/tooling/pipeline-results-viewer/package-lock.json b/tooling/pipeline-results-viewer/package-lock.json
index 69d6ce6..c29c296 100644
--- a/tooling/pipeline-results-viewer/package-lock.json
+++ b/tooling/pipeline-results-viewer/package-lock.json
@@ -8,11 +8,11 @@
"name": "pipeline-results-viewer",
"version": "0.0.0",
"dependencies": {
- "95css": "^0.4.2",
"sql.js": "^1.14.1"
},
"devDependencies": {
"@types/sql.js": "^1.4.11",
+ "sass": "^1.101.0",
"typescript": "^6.0.3",
"vite": "^8.0.12"
}
@@ -80,6 +80,316 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+ "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.3",
+ "is-glob": "^4.0.3",
+ "node-addon-api": "^7.0.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.6",
+ "@parcel/watcher-darwin-arm64": "2.5.6",
+ "@parcel/watcher-darwin-x64": "2.5.6",
+ "@parcel/watcher-freebsd-x64": "2.5.6",
+ "@parcel/watcher-linux-arm-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm-musl": "2.5.6",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm64-musl": "2.5.6",
+ "@parcel/watcher-linux-x64-glibc": "2.5.6",
+ "@parcel/watcher-linux-x64-musl": "2.5.6",
+ "@parcel/watcher-win32-arm64": "2.5.6",
+ "@parcel/watcher-win32-ia32": "2.5.6",
+ "@parcel/watcher-win32-x64": "2.5.6"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+ "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+ "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+ "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+ "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+ "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+ "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+ "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+ "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+ "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+ "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+ "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+ "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+ "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
@@ -383,11 +693,21 @@
"@types/node": "*"
}
},
- "node_modules/95css": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/95css/-/95css-0.4.2.tgz",
- "integrity": "sha512-lzlM1rTgaGCxQL66qZTTzH7H+fHOMwwOZQsry3FcgoeUTrPp3mFReY4LUFPiTywC+Qeve0OH2VxrjDhHgRyu5A==",
- "license": "MIT"
+ "node_modules/chokidar": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
},
"node_modules/detect-libc": {
"version": "2.1.2",
@@ -432,6 +752,38 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/immutable": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.8.tgz",
+ "integrity": "sha512-TM5YqrGeTsVIPPpILzeqZ8D2Zc2TvNgSDi88zPF2a4cyqQdWV/wVWBDRDbNzzrLeRWScrFcOX9lW2iX6GOtUDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/lightningcss": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
@@ -712,6 +1064,14 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -761,6 +1121,20 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/readdirp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/rolldown": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
@@ -795,6 +1169,27 @@
"@rolldown/binding-win32-x64-msvc": "1.0.3"
}
},
+ "node_modules/sass": {
+ "version": "1.101.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz",
+ "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^5.0.0",
+ "immutable": "^5.1.5",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
diff --git a/tooling/pipeline-results-viewer/package.json b/tooling/pipeline-results-viewer/package.json
index 9b8d92b..251ba18 100644
--- a/tooling/pipeline-results-viewer/package.json
+++ b/tooling/pipeline-results-viewer/package.json
@@ -10,11 +10,11 @@
},
"devDependencies": {
"@types/sql.js": "^1.4.11",
+ "sass": "^1.101.0",
"typescript": "^6.0.3",
"vite": "^8.0.12"
},
"dependencies": {
- "95css": "^0.4.2",
"sql.js": "^1.14.1"
}
}
diff --git a/tooling/pipeline-results-viewer/src/main.ts b/tooling/pipeline-results-viewer/src/main.ts
index 75e70cd..90242e8 100644
--- a/tooling/pipeline-results-viewer/src/main.ts
+++ b/tooling/pipeline-results-viewer/src/main.ts
@@ -1,27 +1,41 @@
-import "95css/css/95css.css";
-import initSqlJs, { type Database } from "sql.js";
+import initSqlJs, { type Database, type SqlValue } from "sql.js";
import sqlWasmUrl from "sql.js/dist/sql-wasm.wasm?url";
-import "./style.css";
+import "./style.scss";
const DB_URL = "/biergarten.sqlite";
+const tabs = document.querySelectorAll("[role='tab']");
+const panels = document.querySelectorAll("[role='tabpanel']");
+
const tableSelect = document.querySelector("#table-select")!;
const tableContainer =
document.querySelector("#table-container")!;
const status = document.querySelector("#status")!;
-const renderTable = (db: Database, name: string) => {
- const result = db.exec(`SELECT * FROM "${name}"`);
- tableContainer.replaceChildren();
+const queryInput = document.querySelector("#query-input")!;
+const queryRun = document.querySelector("#query-run")!;
+const queryStatus = document.querySelector("#query-status")!;
+const queryContainer =
+ document.querySelector("#query-container")!;
- if (result.length === 0) {
- tableContainer.append(
- Object.assign(document.createElement("p"), { textContent: "No rows." }),
- );
- return;
- }
+for (const tab of tabs) {
+ tab.addEventListener("click", () => {
+ for (const otherTab of tabs) {
+ const isActive = otherTab === tab;
+ otherTab.classList.toggle("is-active", isActive);
+ otherTab.setAttribute("aria-selected", String(isActive));
+ }
+ for (const panel of panels) {
+ panel.hidden = panel.id !== tab.getAttribute("aria-controls");
+ }
+ });
+}
- const { columns, values } = result[0];
+const renderResultTable = (
+ container: HTMLDivElement,
+ columns: string[],
+ values: SqlValue[][],
+) => {
const table = document.createElement("table");
const head = table.createTHead().insertRow();
@@ -41,7 +55,47 @@ const renderTable = (db: Database, name: string) => {
}
}
- tableContainer.append(table);
+ container.append(table);
+};
+
+const renderTable = (db: Database, name: string) => {
+ const result = db.exec(`SELECT * FROM "${name}"`);
+ tableContainer.replaceChildren();
+
+ if (result.length === 0) {
+ tableContainer.append(
+ Object.assign(document.createElement("p"), { textContent: "No rows." }),
+ );
+ return;
+ }
+
+ const { columns, values } = result[0];
+ renderResultTable(tableContainer, columns, values);
+};
+
+const runQuery = (db: Database) => {
+ const sql = queryInput.value.trim();
+ queryContainer.replaceChildren();
+
+ if (!sql) {
+ queryStatus.textContent = "Enter a query to run.";
+ return;
+ }
+
+ try {
+ const results = db.exec(sql);
+
+ if (results.length === 0) {
+ queryStatus.textContent = "Query executed. No rows returned.";
+ return;
+ }
+
+ const { columns, values } = results[results.length - 1];
+ renderResultTable(queryContainer, columns, values);
+ queryStatus.textContent = `${values.length} row${values.length === 1 ? "" : "s"} returned.`;
+ } catch (error) {
+ queryStatus.textContent = `Error: ${error instanceof Error ? error.message : String(error)}`;
+ }
};
async function main(): Promise {
@@ -78,6 +132,14 @@ async function main(): Promise {
}
status.textContent = "";
+
+ queryRun.addEventListener("click", () => runQuery(db));
+ queryInput.addEventListener("keydown", (event) => {
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
+ event.preventDefault();
+ runQuery(db);
+ }
+ });
}
main().catch((error: unknown) => {
diff --git a/tooling/pipeline-results-viewer/src/style.css b/tooling/pipeline-results-viewer/src/style.css
deleted file mode 100644
index 850191d..0000000
--- a/tooling/pipeline-results-viewer/src/style.css
+++ /dev/null
@@ -1,28 +0,0 @@
-body {
- margin: 0;
- padding: 24px;
-}
-
-#window {
- width: 100%;
- max-width: 1600px;
- margin: 0 auto;
-}
-
-#table-container {
- overflow-x: auto;
- margin-top: 8px;
-}
-
-table {
- border-collapse: collapse;
-}
-
-th,
-td {
- border: 1px solid #808080;
- padding: 4px 8px;
- text-align: left;
- font-size: 14px;
- white-space: nowrap;
-}
diff --git a/tooling/pipeline-results-viewer/src/style.scss b/tooling/pipeline-results-viewer/src/style.scss
new file mode 100644
index 0000000..abbba7f
--- /dev/null
+++ b/tooling/pipeline-results-viewer/src/style.scss
@@ -0,0 +1,267 @@
+$gray-100: #dedede;
+$gray-300: #c3c3c3;
+$gray-500: #808080;
+$white: #ffffff;
+$black: #000000;
+$navy: #000080;
+$blue: #1084d0;
+$teal: #008080;
+
+$color-surface: $gray-300;
+$color-surface-alt: $gray-100;
+$color-surface-sunken: $white;
+$color-border-highlight: $gray-100;
+$color-border-lowlight: $gray-500;
+$color-border-light: $white;
+$color-border-dark: $black;
+$color-text: $black;
+$color-text-on-accent: $white;
+$color-text-status: $navy;
+$color-accent-start: $navy;
+$color-accent-end: $blue;
+$color-desktop-bg: $teal;
+$color-row-stripe: $gray-100;
+$color-shadow: rgba($black, 0.4);
+$color-focus-ring: $black;
+
+$bevel-size: 2px;
+$font-stack: Tahoma, "MS Sans Serif", Verdana, sans-serif;
+
+@mixin bevel-raised($size: $bevel-size) {
+ border-style: solid;
+ border-width: $size;
+ border-top-color: $color-border-highlight;
+ border-left-color: $color-border-highlight;
+ border-right-color: $color-border-dark;
+ border-bottom-color: $color-border-dark;
+ box-shadow:
+ inset $size $size 0 0 $color-border-light,
+ inset (-$size) (-$size) 0 0 $color-border-lowlight;
+}
+
+@mixin bevel-sunken($size: $bevel-size) {
+ border-style: solid;
+ border-width: $size;
+ border-top-color: $color-border-lowlight;
+ border-left-color: $color-border-lowlight;
+ border-right-color: $color-border-light;
+ border-bottom-color: $color-border-light;
+ box-shadow:
+ inset $size $size 0 0 $color-border-dark,
+ inset (-$size) (-$size) 0 0 $color-surface-alt;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ padding: 24px;
+ background: $color-desktop-bg;
+ font-family: $font-stack;
+ color: $color-text;
+ min-height: 100vh;
+}
+
+#window {
+ width: 100%;
+ max-width: 1600px;
+ margin: 0 auto;
+ background: $color-surface;
+ padding: 6px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ @include bevel-raised(3px);
+ box-shadow: 8px 8px 0 0 $color-shadow;
+}
+
+.dialog-header {
+ background: linear-gradient(90deg, $color-accent-start, $color-accent-end);
+ color: $color-text-on-accent;
+ padding: 6px 8px;
+ display: flex;
+ align-items: center;
+
+ p {
+ margin: 0;
+ font-size: 14px;
+ font-weight: bold;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ }
+}
+
+.tab-strip {
+ display: flex;
+ gap: 4px;
+ padding: 8px 8px 0;
+}
+
+.tab {
+ position: relative;
+ top: 3px;
+ margin-bottom: -2px;
+ font-family: $font-stack;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ padding: 6px 14px;
+ background: $color-surface;
+ color: $color-text;
+ border-style: solid;
+ border-width: 2px;
+ border-top-color: $color-border-light;
+ border-left-color: $color-border-light;
+ border-right-color: $color-border-dark;
+ border-bottom-color: $color-border-dark;
+ border-radius: 0;
+ cursor: pointer;
+
+ &.is-active {
+ top: 0;
+ z-index: 1;
+ border-bottom-color: $color-surface;
+ }
+
+ &:focus {
+ outline: 1px dotted $color-focus-ring;
+ outline-offset: -4px;
+ }
+}
+
+.dialog-body {
+ border-top: 2px solid $color-border-dark;
+ padding: 12px;
+}
+
+.tab-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+
+ &[hidden] {
+ display: none;
+ }
+}
+
+.field-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ label {
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ }
+
+ &.field-group--stacked {
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+
+select#table-select {
+ font-family: $font-stack;
+ font-size: 13px;
+ padding: 3px 6px;
+ background: $color-surface-sunken;
+ color: $color-text;
+ border-radius: 0;
+ @include bevel-sunken();
+
+ &:focus {
+ outline: 1px dotted $color-focus-ring;
+ outline-offset: 2px;
+ }
+}
+
+textarea#query-input {
+ font-family: $font-stack;
+ font-size: 13px;
+ padding: 6px;
+ background: $color-surface-sunken;
+ color: $color-text;
+ border-radius: 0;
+ resize: vertical;
+ @include bevel-sunken();
+
+ &:focus {
+ outline: 1px dotted $color-focus-ring;
+ outline-offset: 2px;
+ }
+}
+
+.btn {
+ align-self: flex-start;
+ font-family: $font-stack;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ padding: 6px 16px;
+ background: $color-surface;
+ color: $color-text;
+ cursor: pointer;
+ @include bevel-raised();
+
+ &:active {
+ @include bevel-sunken();
+ }
+
+ &:focus {
+ outline: 1px dotted $color-focus-ring;
+ outline-offset: -4px;
+ }
+}
+
+#status,
+#query-status {
+ margin: 0;
+ font-size: 12px;
+ font-style: italic;
+ color: $color-text-status;
+}
+
+#table-container,
+#query-container {
+ background: $color-surface-sunken;
+ padding: 4px;
+ overflow-x: auto;
+ @include bevel-sunken();
+}
+
+table {
+ border-collapse: collapse;
+ margin: 0 auto;
+ font-family: $font-stack;
+}
+
+th,
+td {
+ border: 1px solid $color-border-lowlight;
+ padding: 4px 8px;
+ text-align: left;
+ font-size: 13px;
+}
+
+th {
+ background: $color-surface;
+ white-space: nowrap;
+ font-weight: bold;
+ text-transform: uppercase;
+ @include bevel-raised(1px);
+}
+
+td {
+ min-width: 120px;
+ max-width: 800px;
+ white-space: normal;
+ word-break: break-word;
+ background: $color-surface-sunken;
+}
+
+tbody tr:nth-child(even) td {
+ background: $color-row-stripe;
+}