Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
88f210e
chore(sync): stage OINK phase A baseline
imbajin Sep 17, 2026
e6e4393
feat(community): add OINK members and content
imbajin Sep 17, 2026
374d0c5
feat(download): unify ASF release downloads
imbajin Sep 17, 2026
12b835a
fix(site): preserve review contracts
imbajin Sep 18, 2026
fd673d2
chore(tests): clarify rendered contract guard
imbajin Sep 18, 2026
5ccc95f
fix(ai): require local consent before Kapa
imbajin Sep 18, 2026
9f35b6a
chore: remove generated Python bytecode
imbajin Sep 18, 2026
f3e6adc
test(download): verify every rendered artifact link
imbajin Sep 18, 2026
2188cf1
test(ai): cover consent before third-party load
imbajin Sep 18, 2026
e429f6f
fix(nav): restore version overflow menu
imbajin Sep 18, 2026
468b63d
fix(nav): cover overflow labels in contracts
imbajin Sep 18, 2026
4ce2f92
fix(nav): collapse mobile version overflow
imbajin Sep 18, 2026
a1f22cc
fix(download): require a latest release row
imbajin Sep 18, 2026
4ef9d9c
test(ai): cover consent cancellation paths
imbajin Sep 18, 2026
c4b3340
fix(workflow): build staging from candidate shell
imbajin Sep 18, 2026
82af5ee
chore(workflow): retain validation workflow
imbajin Sep 18, 2026
0fe275d
fix(workflow): run staging planner on candidate ref
imbajin Sep 18, 2026
3b7610d
fix(site): close review and workflow gaps
imbajin Sep 18, 2026
9389ce6
fix(docs): render accessible table captions
imbajin Sep 18, 2026
974c52a
fix(ui): collapse sidebar after pointer exit
imbajin Sep 18, 2026
27da636
fix(docs): preserve oink table rendering
imbajin Sep 18, 2026
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
19 changes: 14 additions & 5 deletions .github/workflows/hugo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
artifact_prefix: ${{ steps.plan.outputs.artifact_prefix }}
publish_branch: ${{ steps.plan.outputs.publish_branch }}
latest_sha: ${{ steps.plan.outputs.latest_sha }}
source_sha: ${{ steps.plan.outputs.source_sha }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
Expand Down Expand Up @@ -103,7 +104,6 @@ jobs:
latest_sha="$EVENT_SHA"

if [[ "$EVENT_NAME" == workflow_dispatch ]]; then
test "$GITHUB_REF" = refs/heads/master
candidate="$CANDIDATE_BRANCH"
test -n "$candidate"
[[ "$candidate" =~ ^[A-Za-z0-9][A-Za-z0-9._/-]*$ ]]
Expand All @@ -119,6 +119,9 @@ jobs:

case "$OPERATION" in
staging-next)
# Dispatches must load this privileged workflow from master;
# the candidate is data resolved to an immutable commit below.
test "$GITHUB_REF" = "refs/heads/master"
test "$CONFIRMATION" = "publish asf-staging-oink"
site_origin="$STAGING_ORIGIN"
artifact_prefix="staging"
Expand All @@ -131,6 +134,7 @@ jobs:
fi
;;
production-history-refresh)
test "$GITHUB_REF" = refs/heads/master
test "$CONFIRMATION" = "publish asf-site"
test "$candidate" = "$latest_ref"
test "$SCOPE" = full
Expand All @@ -152,6 +156,7 @@ jobs:
echo "artifact_prefix=$artifact_prefix"
echo "publish_branch=$publish_branch"
echo "latest_sha=$latest_sha"
echo "source_sha=$latest_sha"
} >> "$GITHUB_OUTPUT"

- name: Validate source and version tooling
Expand Down Expand Up @@ -193,7 +198,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
ref: ${{ needs.prepare.outputs.source_sha }}
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
Expand Down Expand Up @@ -259,7 +264,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
ref: ${{ needs.prepare.outputs.source_sha }}
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
Expand Down Expand Up @@ -290,6 +295,10 @@ jobs:
--site-origin "$SITE_ORIGIN" --historical-origin "$HISTORICAL_ORIGIN" \
--select "$SELECTION" \
--output "${RUNNER_TEMP}/public-site" "${extra[@]}"
- name: Verify rendered download contracts
env:
DOWNLOAD_PUBLIC_DIR: ${{ runner.temp }}/public-site
run: python3 -m unittest scripts.test_download_data.DownloadDataTest.test_rendered_download_pages_have_verified_rows -v
- name: Upload publishable aggregate
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
Expand All @@ -309,7 +318,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
ref: ${{ needs.prepare.outputs.source_sha }}
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
Expand Down Expand Up @@ -372,7 +381,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
ref: ${{ needs.prepare.outputs.source_sha }}
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ GEMINI.md
.gemini/
WARP.md
/.goal-task

__pycache__/
*.pyc
119 changes: 116 additions & 3 deletions assets/js/hugegraph-shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,83 @@
var restore = documentObject.querySelector('.hg-sidebar-restore');
var desktop = windowObject.matchMedia('(min-width: 768px)');

var panel = sidebar.querySelector('.td-shell-sidebar__panel');
// The native 16px panel edge cannot receive pointers while the sidebar is
// inert. Keep an equivalent pointer-only strip outside the inert subtree;
// the labelled navbar button remains the keyboard/touch equivalent.
var edge = documentObject.createElement('div');
edge.className = 'hg-sidebar-edge d-print-none';
edge.setAttribute('aria-hidden', 'true');
documentObject.body.appendChild(edge);
var closeTimer;
var pointerLockUntil = 0;
function dynamic() {
return desktop.matches &&
html.getAttribute('data-td-shell-sidebar') === 'collapsed';
}
function preview() {
if (!dynamic()) return;
windowObject.clearTimeout(closeTimer);
sidebar.classList.add('td-shell-sidebar--overlay');
sync();
}
function closePreview() {
windowObject.clearTimeout(closeTimer);
closeTimer = windowObject.setTimeout(function () {
if (!sidebar.contains(documentObject.activeElement)) {
sidebar.classList.remove('td-shell-sidebar--overlay');
sync();
}
}, 350);
}
edge.addEventListener('pointerenter', function (event) {
if (event.pointerType !== 'touch' && Date.now() >= pointerLockUntil) preview();
});
edge.addEventListener('pointerleave', closePreview);
if (restore) {
restore.addEventListener('pointerenter', function (event) {
if (event.pointerType !== 'touch' && Date.now() >= pointerLockUntil) preview();
});
restore.addEventListener('pointerleave', closePreview);
restore.addEventListener('keydown', function (event) {
if (event.key !== 'ArrowRight' || !dynamic()) return;
event.preventDefault();
preview();
var first = sidebar.querySelector('a[href], button');
if (first) first.focus();
});
}
if (panel) {
panel.addEventListener('pointerenter', function () {
windowObject.clearTimeout(closeTimer);
});
panel.addEventListener('pointerleave', closePreview);
panel.addEventListener('focusout', closePreview);
panel.addEventListener('keydown', function (event) {
if (event.key !== 'Escape' || !dynamic()) return;
event.preventDefault();
if (restore) restore.focus();
sidebar.classList.remove('td-shell-sidebar--overlay');
sync();
});
}

function sync() {
var collapsed =
html.getAttribute('data-td-shell-sidebar') === 'collapsed';
var drawerOpen =
html.getAttribute('data-td-shell-drawer') === 'open';
var isolated = desktop.matches ? collapsed : !drawerOpen;
// OINK owns the persistent collapsed mode and pointer overlay. Keep
// focus inside an open preview safe when its native pointerleave fires.
if (desktop.matches && collapsed &&
!sidebar.classList.contains('td-shell-sidebar--overlay') &&
sidebar.contains(documentObject.activeElement)) {
sidebar.classList.add('td-shell-sidebar--overlay');
}
var overlay = sidebar.classList.contains('td-shell-sidebar--overlay');
var isolated = desktop.matches ? collapsed && !overlay : !drawerOpen;
edge.hidden = !desktop.matches || !collapsed;
if (restore) restore.setAttribute('aria-expanded', String(!isolated));
if (restore) restore.hidden = !desktop.matches || !collapsed;
sidebar.inert = isolated;
if (isolated) sidebar.setAttribute('aria-hidden', 'true');
Expand All @@ -150,17 +221,58 @@
attributes: true,
attributeFilter: ['data-td-shell-sidebar', 'data-td-shell-drawer'],
});
new MutationObserver(sync).observe(sidebar, { attributes: true, attributeFilter: ['class'] });
desktop.addEventListener('change', sync);
documentObject
.querySelectorAll('[data-td-shell-sidebar-toggle], [data-td-shell-drawer-close]')
.forEach(function (button) {
button.addEventListener('click', function () {
global.queueMicrotask(sync);
});
var hadFocus = documentObject.activeElement === button;
// Match OINK's cooldown so a newly visible trigger under the pointer
// does not immediately undo an explicit keyboard collapse.
pointerLockUntil = Date.now() + 150;
// Run after OINK's native click listener regardless of chunk order.
global.setTimeout(function () {
if (dynamic() && sidebar.contains(button) && restore) {
restore.hidden = false;
restore.focus();
sidebar.classList.remove('td-shell-sidebar--overlay');
}
sync();
// Both external restore controls disappear when pinned. Transfer
// their focus after making the sidebar operable; hover and clicks
// that did not focus a trigger must not steal unrelated focus.
if (hadFocus && desktop.matches && !dynamic() &&
!sidebar.contains(button) && button.offsetParent === null) {
var collapse = sidebar.querySelector('.td-shell-sidebar__collapse');
if (collapse) collapse.focus();
}
}, 0);
}, true);
});
sync();
}

function initScrollableTables(documentObject) {
documentObject.querySelectorAll('[data-td-asset-table-scroll]').forEach(function (region) {
if (region.dataset.hgTableScrollBound !== undefined) return;
region.dataset.hgTableScrollBound = '';
region.addEventListener('keydown', function (event) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Keep native keyboard behavior for links and other descendants in the table.
if (event.target !== region) return;
if (region.scrollWidth <= region.clientWidth) return;
var delta = 0;
if (event.key === 'ArrowRight') delta = 80;
else if (event.key === 'ArrowLeft') delta = -80;
else if (event.key === 'Home') delta = -region.scrollLeft;
else if (event.key === 'End') delta = region.scrollWidth - region.clientWidth - region.scrollLeft;
else return;
event.preventDefault();
region.scrollBy({ left: delta, behavior: 'smooth' });
});
});
}

function initSearchRetry(windowObject, documentObject) {
var root = documentObject.getElementById('td-shell-search');
if (!root) return;
Expand Down Expand Up @@ -324,6 +436,7 @@
initVersionSwitching(windowObject, documentObject);
initTreePersistence(windowObject, documentObject, config);
initSidebarIsolation(windowObject, documentObject);
initScrollableTables(documentObject);
initSearchRetry(windowObject, documentObject);
}

Expand Down
58 changes: 53 additions & 5 deletions assets/js/kapa-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@

function createController(windowObject, documentObject, config) {
var state = 'idle';
var consented = false;
var pending = null;
var consent = documentObject.querySelector('[data-hg-ai-consent]');
var attempt = 0;
var timer = 0;
var lastTrigger = null;
Expand Down Expand Up @@ -220,9 +223,8 @@
documentObject.head.appendChild(script);
}

function activate(query, submit, trigger) {
function load(query, submit) {
query = trimmedQuery(query);
lastTrigger = trigger || documentObject.activeElement;
if (state === 'loading') return;
if (state === 'ready') {
openWidget(query, Boolean(submit && query));
Expand All @@ -237,6 +239,54 @@
ensureScript(serial, query, Boolean(submit && query), retrying);
}

function cancelConsent() {
pending = null;
renderState('idle', '');
if (consent && consent.open) consent.close();
restoreFocus();
}

function activate(query, submit, trigger) {
if (state === 'loading' || state === 'consent') return;
lastTrigger = trigger || documentObject.activeElement;
if (consented) {
load(query, submit);
return;
}
// Fail closed if the local consent panel is unavailable.
if (!consent || typeof consent.showModal !== 'function') {
renderState('error', config.labels.error);
return;
}
pending = { query: trimmedQuery(query), submit: submit };
renderState('consent', '');
consent.showModal();
}

if (consent) {
// Keep the underlying search palette from consuming modal keyboard events.
consent.addEventListener('keydown', function (event) {
event.stopPropagation();
if (event.key === 'Escape') {
event.preventDefault();
cancelConsent();
}
});
consent.querySelector('[data-hg-ai-continue]').addEventListener('click', function () {
if (!pending) return;
var request = pending;
pending = null;
consented = true;
consent.close();
load(request.query, request.submit);
});
consent.querySelector('[data-hg-ai-cancel]').addEventListener('click', cancelConsent);
consent.addEventListener('cancel', function (event) {
event.preventDefault();
cancelConsent();
});
}

function restoreFocus() {
if (lastTrigger && typeof lastTrigger.focus === 'function') {
lastTrigger.focus();
Expand Down Expand Up @@ -333,9 +383,7 @@
title.textContent = config.labels.ask + ': “' + query + '”';
var detail = documentObject.createElement('span');
detail.className = 'td-shell-search__item-ref';
detail.textContent =
config.labels.description +
(config.historical ? ' ' + config.labels.latest + '.' : '');
detail.textContent = config.historical ? config.labels.latest + '.' : '';
meta.appendChild(title);
meta.appendChild(detail);
row.appendChild(icon);
Expand Down
Loading
Loading