diff --git a/ui/package-lock.json b/ui/package-lock.json index a3a7acf..a5bfefa 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,10 +8,10 @@ "name": "ui", "version": "0.0.0", "dependencies": { - "@perspective-dev/client": "5.2.0", - "@perspective-dev/server": "5.2.0", - "@perspective-dev/viewer": "5.2.0", - "@perspective-dev/viewer-datagrid": "5.2.0", + "@perspective-dev/client": "file:./vendor/perspective-dev-client-5.4.0.tgz", + "@perspective-dev/server": "file:./vendor/perspective-dev-server-5.4.0.tgz", + "@perspective-dev/viewer": "file:./vendor/perspective-dev-viewer-5.4.0.tgz", + "@perspective-dev/viewer-datagrid": "file:./vendor/perspective-dev-viewer-datagrid-5.4.0.tgz", "react": "^19.2.5", "react-dom": "^19.2.5" }, @@ -554,43 +554,43 @@ } }, "node_modules/@perspective-dev/client": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@perspective-dev/client/-/client-5.2.0.tgz", - "integrity": "sha512-zkJmJFwdw0wMREoJt8gUJyCsflzi7s7Yc8ZtUCOLE9XB6fdyxJmDB99cxO3Q+hno/57kLsz8VNoz8XSm6PZNrg==", + "version": "5.4.0", + "resolved": "file:vendor/perspective-dev-client-5.4.0.tgz", + "integrity": "sha512-l9xCJ0W42wm9fLlwhoU838KyTE131qQTS686uQb/VcsLs30kCVjkoermCCUs0YHCDwDTJhly1y9DfAZDbkg9Ng==", "license": "Apache-2.0", "dependencies": { - "@perspective-dev/server": "", + "@perspective-dev/server": "^5.4.0", "pro_self_extracting_wasm": "0.0.9", "stoppable": "=1.1.0", "ws": "^8.17.0" } }, "node_modules/@perspective-dev/server": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@perspective-dev/server/-/server-5.2.0.tgz", - "integrity": "sha512-WRBiokT2/BYM8Ipe7Dg1/2UYNb01Vsox79KBfFVI800VmwdId0GdqI95zufN5ZoFffeBfri1sr3S3AShBRFXKA==", + "version": "5.4.0", + "resolved": "file:vendor/perspective-dev-server-5.4.0.tgz", + "integrity": "sha512-iTseRJB6TL6D9xjaMKMhh2NEKMIi9JR881J+GyQflHIQXK43fDlsIWtByUAoyZzZ7uA9KNZJZicirvONxIpLuw==", "license": "Apache-2.0" }, "node_modules/@perspective-dev/viewer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@perspective-dev/viewer/-/viewer-5.2.0.tgz", - "integrity": "sha512-IIyqdPduofzzZ/QWrteq29IadJQR8IapTRz7U6XbrtBBm7eyiFsIBKQV0wFfcqWg4TRnhuvCAUvBRieuE0R8Eg==", + "version": "5.4.0", + "resolved": "file:vendor/perspective-dev-viewer-5.4.0.tgz", + "integrity": "sha512-7D6jNn7tDZ3W84MsydplWAJbqqpXIz5OlsHx5YG4sHvJ5q8ngZQvP+oZdxLQXL4hIbaxpskMld1gJbGltpcvUw==", "license": "Apache-2.0", "dependencies": { - "@perspective-dev/client": "", + "@perspective-dev/client": "^5.4.0", "pro_self_extracting_wasm": "0.0.9", "regular-layout": "=0.6.1" } }, "node_modules/@perspective-dev/viewer-datagrid": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@perspective-dev/viewer-datagrid/-/viewer-datagrid-5.2.0.tgz", - "integrity": "sha512-v/SR/35YfyKfivO21nglJFiyG1iE5G8vMwIwWI6fQuwjW764pmNrm/zcrNWNY70x5XHkPRM94aY6LjkLsLkO2g==", + "version": "5.4.0", + "resolved": "file:vendor/perspective-dev-viewer-datagrid-5.4.0.tgz", + "integrity": "sha512-7ITOmrIh1ZpiQbUR/KmHYck1sLA4cpNgpVMI/qJjQc9k/uypkT1vJmKYxv4MKR24TmEkOouBLNYiO+ItFKs8vg==", "license": "Apache-2.0", "dependencies": { - "@perspective-dev/client": "", - "@perspective-dev/viewer": "", - "regular-table": "=0.8.6" + "@perspective-dev/client": "^5.4.0", + "@perspective-dev/viewer": "^5.4.0", + "regular-table": "=0.9.1" } }, "node_modules/@rolldown/binding-android-arm64": { @@ -2948,9 +2948,9 @@ "license": "Apache-2.0" }, "node_modules/regular-table": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/regular-table/-/regular-table-0.8.6.tgz", - "integrity": "sha512-jzJzu9WLtqwMgbf5ak/VdNm/YLHUDnDSCHD5SOksnHrHLuDN6l5i2stYfe7BjsHbQV1Gx9369Ma40nTBCgOFvA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regular-table/-/regular-table-0.9.1.tgz", + "integrity": "sha512-3I/2I3NEhmyScCevW/r1AE9hyUkqrPRMDsgo/nDnGXhpXVZOxUddJQGBmEMLgyc7OSaQSzl9BtXllnMqw1MwCA==", "license": "Apache-2.0", "engines": { "node": ">=16" diff --git a/ui/package.json b/ui/package.json index 8d88e21..d9cbcde 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,10 +10,10 @@ "preview": "vite preview" }, "dependencies": { - "@perspective-dev/client": "5.2.0", - "@perspective-dev/server": "5.2.0", - "@perspective-dev/viewer": "5.2.0", - "@perspective-dev/viewer-datagrid": "5.2.0", + "@perspective-dev/client": "file:./vendor/perspective-dev-client-5.4.0.tgz", + "@perspective-dev/server": "file:./vendor/perspective-dev-server-5.4.0.tgz", + "@perspective-dev/viewer": "file:./vendor/perspective-dev-viewer-5.4.0.tgz", + "@perspective-dev/viewer-datagrid": "file:./vendor/perspective-dev-viewer-datagrid-5.4.0.tgz", "react": "^19.2.5", "react-dom": "^19.2.5" }, diff --git a/ui/vendor/PROVENANCE.txt b/ui/vendor/PROVENANCE.txt new file mode 100644 index 0000000..8fd32d2 --- /dev/null +++ b/ui/vendor/PROVENANCE.txt @@ -0,0 +1,7 @@ +Built from https://github.com/fleetside72/perspective + branch column-axis-expand-collapse + commit 2e3901d652650a33eaf19c2ddf049f7e525ea95b + based on v5.4.0 + built 2026-09-14T02:40:11Z on r710.hptrow.me + +Regenerate with ui/vendor/rebuild-perspective.sh diff --git a/ui/vendor/README.md b/ui/vendor/README.md new file mode 100644 index 0000000..e5901f4 --- /dev/null +++ b/ui/vendor/README.md @@ -0,0 +1,50 @@ +# Vendored Perspective + +pf_app runs a **patched build of Perspective**. Upstream's C++ engine has always +implemented column-axis expand/collapse — `t_ctx2::set_depth(HEADER_COLUMN, …)` +and `open`/`close(HEADER_COLUMN, idx)` are fully written — but nothing above C++ +could reach it: `set_column_pivot_depth()` was never called, and +`View::expand/collapse` hardcoded `HEADER_ROW`. The patch is wiring, not +new engine logic. + +It buys two things the released packages cannot do at all: + +- `split_by_depth` in `ViewConfig`, the `split_by` counterpart to `group_by_depth` +- `expand_column()` / `collapse_column()`, so one column branch can fold to its + subtotal while its siblings stay expanded — the Excel behaviour + +**Source:** https://github.com/fleetside72/perspective, branch +`column-axis-expand-collapse`. See `PROVENANCE.txt` for the exact commit these +tarballs were built from. + +## Why tarballs and not npm + +The feature is not released upstream. Until it is, the four packages are built +from the fork and committed here as npm tarballs. `npm install` expands them +exactly as it expands anything from the registry — no special tooling, and +`pf.sh deploy` works unchanged. A deploy machine needs node and nothing else: +no emscripten, no cmake, no protoc, no Rust. + +All four move together, never a subset. Perspective couples loader, package +versions, data format and `apache-arrow`; vendoring a partial set reintroduces +exactly the drift that causes trouble. + +## Changing the engine + + ./rebuild-perspective.sh # builds the fork, repacks, rewrites PROVENANCE.txt + cd .. && npm install + git add vendor && git commit + +Push the fork first — the script warns if the source tree is dirty, because a +tarball built from uncommitted code has no recoverable source. + +The build itself needs cmake >= 3.29.5, protoc >= 22 (its version silently +selects which protobuf source tree gets cloned), pnpm, and the Rust nightly the +repo pins. Roughly 40 minutes cold. Only ever on a machine changing the engine. + +## Getting rid of this + +This is a fork, with the maintenance that implies. The exit is upstream taking +the change — the patch is small and additive, and the engine work is already +theirs. When a release ships it, delete this directory and put normal version +ranges back in `ui/package.json`. diff --git a/ui/vendor/perspective-dev-client-5.4.0.tgz b/ui/vendor/perspective-dev-client-5.4.0.tgz new file mode 100644 index 0000000..2294e84 Binary files /dev/null and b/ui/vendor/perspective-dev-client-5.4.0.tgz differ diff --git a/ui/vendor/perspective-dev-server-5.4.0.tgz b/ui/vendor/perspective-dev-server-5.4.0.tgz new file mode 100644 index 0000000..656e1fb Binary files /dev/null and b/ui/vendor/perspective-dev-server-5.4.0.tgz differ diff --git a/ui/vendor/perspective-dev-viewer-5.4.0.tgz b/ui/vendor/perspective-dev-viewer-5.4.0.tgz new file mode 100644 index 0000000..bf46c09 Binary files /dev/null and b/ui/vendor/perspective-dev-viewer-5.4.0.tgz differ diff --git a/ui/vendor/perspective-dev-viewer-datagrid-5.4.0.tgz b/ui/vendor/perspective-dev-viewer-datagrid-5.4.0.tgz new file mode 100644 index 0000000..01d94af Binary files /dev/null and b/ui/vendor/perspective-dev-viewer-datagrid-5.4.0.tgz differ diff --git a/ui/vendor/rebuild-perspective.sh b/ui/vendor/rebuild-perspective.sh new file mode 100755 index 0000000..430bb9b --- /dev/null +++ b/ui/vendor/rebuild-perspective.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +set -euo pipefail + +# --------------------------------------------------------------------------- +# rebuild-perspective.sh — rebuild the patched Perspective and re-vendor it +# +# pf_app runs a patched build of Perspective that exposes the column axis +# expand/collapse the engine already implements (split_by_depth, and +# expand_column/collapse_column). Upstream does not ship this yet, so the +# built packages are vendored into this directory as npm tarballs. +# +# Source of truth: https://github.com/fleetside72/perspective +# branch column-axis-expand-collapse +# +# This script exists because vendored binaries are opaque: once the .tgz files +# are committed, nothing in the repo records how to regenerate them. Run this +# after changing the fork, then commit the resulting tarballs. +# +# Only needed on a machine that is changing the engine. Deploys just run +# `npm install`, which expands the committed tarballs - see ../README in this +# directory. +# --------------------------------------------------------------------------- + +PSP="${PSP_DIR:-$HOME/perspective}" +BRANCH="${PSP_BRANCH:-column-axis-expand-collapse}" +VENDOR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# The four packages that must move together. Perspective's own docs are +# emphatic that loader, packages, data format and apache-arrow are one unit; +# vendoring a subset would reintroduce exactly the drift that causes trouble. +PACKAGES=( + "rust/perspective-js" + "rust/perspective-server" + "rust/perspective-viewer" + "packages/viewer-datagrid" +) + +info() { echo -e "\033[0;34m==>\033[0m $*"; } +ok() { echo -e "\033[0;32m ✓\033[0m $*"; } +die() { echo -e "\033[0;31m ✗\033[0m $*" >&2; exit 1; } + +# -- preflight -------------------------------------------------------------- +[[ -d "$PSP" ]] || die "No Perspective checkout at $PSP. + git clone https://github.com/fleetside72/perspective.git $PSP + cd $PSP && git checkout $BRANCH + Set PSP_DIR to use a different path." + +command -v pnpm >/dev/null || die "pnpm not found. Perspective builds with pnpm, not npm." +command -v protoc >/dev/null || die "protoc not found. + Its VERSION selects which protobuf source tree the build clones, and a + version below 22 pulls a layout the build cannot consume. Needs >= 22 + (33.2 known good). Distro packages are usually far too old." + +cmake_ver=$(cmake --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?') || die "cmake not found" +cmake_major=${cmake_ver%%.*}; cmake_minor=$(echo "$cmake_ver" | cut -d. -f2) +if (( cmake_major < 3 || (cmake_major == 3 && cmake_minor < 29) )); then + die "cmake $cmake_ver is too old; Perspective needs >= 3.29.5. + A user-level install works: pip3 install --user 'cmake>=3.29.5'" +fi + +info "Perspective checkout: $PSP" +git -C "$PSP" rev-parse --abbrev-ref HEAD | grep -qx "$BRANCH" \ + || echo " ! on branch $(git -C "$PSP" rev-parse --abbrev-ref HEAD), expected $BRANCH" +commit=$(git -C "$PSP" rev-parse --short HEAD) +dirty=$(git -C "$PSP" status --porcelain | wc -l) +echo " commit $commit$([[ $dirty -gt 0 ]] && echo " (+$dirty uncommitted files)")" + +# -- build ------------------------------------------------------------------ +# `metadata` first: it generates docs/expression_gen.md, which perspective-client +# includes at compile time. Building a scope without it fails on the missing file. +info "Building (this takes ~40 minutes cold, a few minutes warm)…" +( cd "$PSP" && PSP_ONCE=1 PACKAGE="metadata,server,client,viewer,viewer-datagrid" pnpm run build ) +ok "build complete" + +# -- pack ------------------------------------------------------------------- +info "Packing tarballs into $VENDOR" +rm -f "$VENDOR"/*.tgz +for p in "${PACKAGES[@]}"; do + ( cd "$PSP/$p" && npm pack --pack-destination "$VENDOR" >/dev/null ) + ok "$(basename "$p")" +done + +# -- record provenance ------------------------------------------------------ +# A committed .tgz is an opaque binary; without this the tie back to source is +# only in someone's memory. +cat > "$VENDOR/PROVENANCE.txt" </dev/null || echo 'unknown') + built $(date -u +%Y-%m-%dT%H:%M:%SZ) on $(hostname) + dirty $dirty uncommitted file(s) in the source tree at build time + +Regenerate with ui/vendor/rebuild-perspective.sh +EOF + +echo +ls -la "$VENDOR"/*.tgz | awk '{printf " %-52s %5.1f MB\n", $NF, $5/1048576}' +echo +ok "Done. Now: cd ui && npm install && git add vendor && git commit" +[[ $dirty -gt 0 ]] && echo -e "\033[1;33m !\033[0m source tree had uncommitted changes — push them to the fork first" +exit 0