Skip to content

Small UI polish: prettier EXPLAIN (pretty/compact, version-gated), underscore-tables-last, table-detail loading spinner #85

Description

@BorisTyshkevich

Part of #68 (Roadmap to 1.0.0).

Three small UI/UX polish items, grouped. Each is independently shippable; the per-file coverage gate (npm test) applies to all.


1. Prettier EXPLAIN output (pretty = 1 + compact = 1, version-gated)

Problem. The plan views render ClickHouse's raw indentation-based EXPLAIN. ClickHouse ≥ 26.3 added EXPLAIN … pretty = 1 (line-drawing tree, human-readable expressions, output columns, JOIN annotations; improved again in 26.4), and compact = 1 collapses noisy Expression steps — together they read far better. We just emit EXPLAIN <inner> today (src/core/explain.js:90).

Catch. pretty is unknown on servers < 26.3 (Unknown setting pretty), so it must be gated on the server version — which the app does not currently know (#74's stamp is the app build, not the server).

Scope.

  • Capture server version once — add a SELECT version() (alongside or right after loadSchema in src/net/ch-client.js), store on state (e.g. state.serverVersion).
  • src/core/: pure version helper (100% covered) — e.g. supportsExplainPretty(versionString) parsing major.minor and returning ≥ 26.3. Robust to empty/malformed version strings (→ false).
  • buildExplainQuery(inner, viewId, opts) — add an opts.pretty flag (kept pure/testable). When true, decorate:
    • plain: EXPLAIN pretty = 1, compact = 1 <inner>
    • indexes: EXPLAIN indexes = 1, pretty = 1, compact = 1 <inner>
    • projections: EXPLAIN projections = 1, pretty = 1, compact = 1 <inner>
    • pipeline (graph = 1) and estimate: unchanged.
      When false (older server), emit exactly today's queries.
  • Caller (src/ui/app.js) passes pretty: supportsExplainPretty(state.serverVersion).

Acceptance.

  • On ClickHouse ≥ 26.3, plain/indexes/projections EXPLAIN render with pretty = 1, compact = 1.
  • On older servers, EXPLAIN queries are byte-for-byte today's (no pretty/compact), no failed requests.
  • Version helper handles missing/garbage version strings without throwing; 100% covered.

Note (out of scope): since CH ≥ 25.9, EXPLAIN indexes = 1 only shows reasonable output with SETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0. Separate concern — flag as a possible follow-up.


2. Sort underscore-prefixed tables to the end of each database

Problem. Tables named _… (internal/temp/staging) clutter the top of each database's list in the schema sidebar. Ordering is purely SQL (ORDER BY database, name, src/net/ch-client.js:117); there's no client-side sort.

Scope.

  • Change the ORDER BY to push underscore-prefixed names last, alphabetised within each group:
    ORDER BY database, startsWith(name, '_'), name
    
    (Use startsWith(name, '_'), not name LIKE '_%'_ is a LIKE single-char wildcard and would match every name.)
  • Apply the same to the lineage query (src/net/ch-client.js:150).

Acceptance.

  • Non-underscore tables list first (A→Z), then underscore-prefixed tables (A→Z), per database.

3. Loading spinner for the table-detail / CREATE TABLE pane

Problem. openNodeDetail (src/ui/app.js:605) awaits loadTableDetail (columns + partitions + create_table_query) before mounting the pane, so on a slow fetch nothing appears — no feedback that the DDL is loading.

Scope. Mirror the existing columns = 'loading' sentinel and the Icon.spinner() + .placeholder.starting pattern already used for the schema graph (src/ui/results.js:108):

  • Mount the detail pane immediately in a loading state (spinner + "Loading table…").
  • Await loadTableDetail, then populate / re-render the pane with columns, partitions, and DDL.
  • Render branch in src/ui/schema-detail.js (+ its test); wiring in src/ui/app.js.

Acceptance.

  • Opening a table shows a spinner immediately, replaced by details (incl. DDL) when the fetch resolves.
  • npm test green at the per-file coverage gate (new version helper + explain + schema-detail branches at 100%).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions