Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 25 additions & 18 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,30 @@
"tasks": {
"build": "deno run -A scripts/build.ts",
"dev": "deno run -A scripts/build.ts --watch",
"check": "deno check lib/widget.ts"
"check": "deno check lib/widget.ts",
"tauri": "deno run -A npm:@tauri-apps/cli@2.0.0-beta.22"
},
"fmt": {
"useTabs": true,
"exclude": [
".venv",
"src",
"examples",
"README.md",
"dist",
"tauri/dist",
"tauri/target"
]
},
"lint": {
"rules": {
"exclude": ["prefer-const"]
},
"exclude": [".venv", "src", "examples", "tauri/dist", "tauri/target"]
},
"compilerOptions": {
"verbatimModuleSyntax": true,
"allowJs": false,
"lib": [
"esnext",
"dom",
"dom.iterable"
]
"lib": ["esnext", "dom", "dom.iterable"]
},
"imports": {
"@anywidget/types": "https://esm.sh/@anywidget/types@0.1.9",
Expand All @@ -28,16 +42,9 @@
"d3-scale": "https://esm.sh/d3-scale@4.0.2",
"d3-axis": "https://esm.sh/d3-axis@3.0.0",
"d3-format": "https://esm.sh/d3-format@3.1.0",
"d3-time-format": "https://esm.sh/d3-time-format@4.1.0"
},
"fmt": {
"useTabs": true,
"exclude": [".venv", "src", "examples", "README.md"]
},
"lint": {
"rules": {
"exclude": ["prefer-const"]
},
"exclude": [".venv", "src", "examples"]
"d3-time-format": "https://esm.sh/d3-time-format@4.1.0",
"@tauri-apps/api": "https://esm.sh/@tauri-apps/api@^2.0.0-beta.15",
"@tauri-apps/api/core": "https://esm.sh/@tauri-apps/api@^2.0.0-beta.15/core",
"@tauri-apps/plugin-dialog": "https://esm.sh/@tauri-apps/plugin-dialog@^2.0.0-beta.7"
}
}
53 changes: 39 additions & 14 deletions lib/clients/DataTable.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import * as arrow from "apache-arrow";
// @deno-types="../deps/mosaic-core.d.ts"
import {
type FieldInfo,
type FieldRequest,
MosaicClient,
Selection,
} from "@uwdata/mosaic-core";
import * as mc from "@uwdata/mosaic-core";
// @deno-types="../deps/mosaic-sql.d.ts"
import { desc, Query, SQLExpression } from "@uwdata/mosaic-sql";
import * as signals from "@preact/signals-core";
Expand All @@ -30,7 +25,32 @@ interface DataTableOptions {
// TODO: more
type ColumnSummaryClient = Histogram | ValueCounts;

export class DataTable extends MosaicClient {
export async function datatable(
table: string,
options: {
coordinator?: mc.Coordinator;
height?: number;
columns?: Array<string>;
} = {},
) {
assert(options.coordinator, "Must provide a coordinator");
let empty = await options.coordinator.query(
Query
.from(table)
.select(options.columns ?? ["*"])
.limit(0)
.toString(),
);
let client = new DataTable({
table,
schema: empty.schema,
height: options.height,
});
options.coordinator.connect(client);
return client;
}

export class DataTable extends mc.MosaicClient {
/** source of the data */
#meta: { table: string; schema: arrow.Schema };
/** for the component */
Expand Down Expand Up @@ -70,7 +90,7 @@ export class DataTable extends MosaicClient {
#sql = signal(undefined as string | undefined);

constructor(source: DataTableOptions) {
super(Selection.crossfilter());
super(mc.Selection.crossfilter());
this.#format = formatof(source.schema);
this.#pendingInternalRequest = false;
this.#meta = source;
Expand All @@ -82,9 +102,8 @@ export class DataTable extends MosaicClient {
maxHeight = `${source.height}px`;
}

let root: HTMLDivElement = html`<div class="quak" style=${{
maxHeight,
}}>`;
// @deno-fmt-ignore
let root: HTMLDivElement = html`<div class="quak" style=${{ maxHeight }}>`;
// @deno-fmt-ignore
root.appendChild(
html.fragment`<table style=${{ tableLayout: "fixed" }}>${this.#thead}${this.#tbody}</table>`
Expand All @@ -104,11 +123,17 @@ export class DataTable extends MosaicClient {
});
}

resize(height: number) {
this.#rows = Math.floor(height / this.#rowHeight);
this.#tableRoot.style.maxHeight = `${height}px`;
this.#tableRoot.scrollTop = 0;
}

get sql() {
return this.#sql.value;
}

fields(): Array<FieldRequest> {
fields(): Array<mc.FieldRequest> {
return this.#columns.map((column) => ({
table: this.#meta.table,
column,
Expand Down Expand Up @@ -184,7 +209,7 @@ export class DataTable extends MosaicClient {
this.coordinator.prefetch(query.clone().offset(offset + this.#limit));
}

fieldInfo(infos: Array<FieldInfo>) {
fieldInfo(infos: Array<mc.FieldInfo>) {
let classes = classof(this.#meta.schema);

{
Expand Down Expand Up @@ -361,7 +386,7 @@ function thcol(
// @deno-fmt-ignore
let th: HTMLTableCellElement = html`<th style=${{ overflow: "hidden" }}>
<div style=${{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style=${{ marginBottom: "5px", maxWidth: "250px", ...TRUNCATE }}>${field.name}</span>
<span style=${{ userSelect: "text", marginBottom: "5px", maxWidth: "250px", ...TRUNCATE }}>${field.name}</span>
${sortButton}
</div>
${verticalResizeHandle}
Expand Down
2 changes: 1 addition & 1 deletion lib/clients/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ th {
font-weight: bold;
text-align: -internal-center;
unicode-bidi: isolate;

position: relative;
background: var(--white);
border-bottom: solid 1px var(--light-silver);
border-left: solid 1px var(--light-silver);
padding: 5px 6px;
user-select: none;
-webkit-user-select: none;
}

.number, .date {
Expand Down
39 changes: 11 additions & 28 deletions lib/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as mc from "@uwdata/mosaic-core";
import * as msql from "@uwdata/mosaic-sql";

import { DataTable } from "./clients/DataTable.ts";
import { datatable } from "./clients/DataTable.ts";

let table: keyof typeof datasets = "athletes";
let base = new URL(
Expand Down Expand Up @@ -34,41 +34,24 @@ await coordinator.exec([
msql.loadCSV(table, datasets[table]),
]);

// TODO: This should be a helper function
let empty = await coordinator.query(
msql.Query
.from(table)
.select("*")
// .select("name", "nationality", "sport", "info")
.limit(0)
.toString(),
);

let datatable = new DataTable({
table,
schema: empty.schema,
height: 500,
});
const height = () => globalThis.innerHeight - 45;
globalThis.onresize = () => client.resize(height());

coordinator.connect(datatable);
document.body.appendChild(datatable.node());
let client = await datatable(table, { coordinator, height: height() });
document.body.appendChild(client.node());

// A Vite-specific feature that allows hot-reloading of modules. This way we
// don't need to reload DuckDB or the data when we make changes to the
// DataTable client.
//
// @see https://vitejs.dev/guide/api-hmr
// @ts-expect-error - import.meta.hot not coming from Deno
import.meta.hot?.accept("./clients/DataTable.ts", (mod) => {
coordinator.disconnect(datatable);
document.body.removeChild(datatable.node());
datatable = new mod.DataTable({
table,
schema: empty.schema,
height: 500,
});
coordinator.connect(datatable);
document.body.appendChild(datatable.node());
import.meta.hot?.accept("./clients/DataTable.ts", async (mod) => {
coordinator.disconnect(client);
document.body.removeChild(client.node());
client = await mod.datatable(table, { coordinator, height: height() });
coordinator.connect(client);
document.body.appendChild(client.node());
});

function _voidLogger() {
Expand Down
6 changes: 6 additions & 0 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,11 @@ if (Deno.args.includes("--watch")) {
importMapURL: new URL("deno.json", root).href,
})];
}
if (Deno.args.includes("--tauri")) {
options.entryPoints = ["./tauri/app.js"];
options.outfile = "./tauri/dist/app.js";
}
await esbuild.build(options);
}

Deno.copyFile("./tauri/index.html", "./tauri/dist/index.html");
4 changes: 4 additions & 0 deletions tauri/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
/target/
/gen/schemas
Loading