Skip to content

Develop#296

Draft
namedgraph wants to merge 21 commits into
masterfrom
develop
Draft

Develop#296
namedgraph wants to merge 21 commits into
masterfrom
develop

Conversation

@namedgraph
Copy link
Copy Markdown
Member

No description provided.

namedgraph and others added 21 commits April 6, 2026 11:12
When ENABLE_LINKED_DATA_PROXY=false, facet filter requests for external
predicate URIs (e.g. schema.org) return 405, leaving the left-nav empty.
Instead of silently ignoring the error, synthesize an rdf:Description with
rdfs:label derived from the predicate's local name so bs2:FilterIn renders
facet headers in both cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Serve namespace ontology terms from ProxyRequestFilter

After the DataManager cache check, run a DESCRIBE query against the
app's in-memory OntModel (full imports closure) before falling through
to the external proxy or 405. Covers both slash-based term URIs (e.g.
schema:category) and hash-based namespaces (e.g. sioc:ns → describes
all sioc:ns#* terms via the WHERE clause). This allows facet headers
and other term lookups to resolve from imported ontologies without
requiring ENABLE_LINKED_DATA_PROXY=true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add proxy test for OntModel namespace term lookup

Creates two OWL classes in a made-up hash-based namespace, clears
the in-memory ontology, then retrieves the namespace document via
?uri= and verifies both class descriptions are returned. The namespace
is not DataManager-mapped and not a registered app, so the request
exercises the new OntModel DESCRIBE path in ProxyRequestFilter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ProxyRequestFilterTest after ontology injection added

Set filter.ontology = Optional.empty() in setUp() so existing tests
reach the proxy/NotAllowed paths they were designed to test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Injection fixes

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Move CORS headers from Java filters to nginx

Varnish caches responses without varying on Origin, so whether CORS
headers appear in cached responses depends on which request first
populated the cache. Moving CORS to nginx ensures the headers are
always present on every response regardless of cache state.

Removes JAX-RS CORSFilter and Tomcat CorsFilter (web.xml /static/*);
adds Access-Control-* headers and OPTIONS preflight (204) to nginx
location / blocks in both docker-compose.yml and nginx.conf.template.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add CORS header to /static/ nginx location blocks

The cors-static.sh test was failing because Access-Control-Allow-Origin
was only added to location / but not location ^~ /static/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Enable gzip compression in nginx for RDF and JSON content types

Adds gzip_types covering application/json, SPARQL results, RDF serializations
(Turtle, RDF/XML, LD+JSON, TriG, N-Quads, N-Triples), XML, CSS, JS, and SVG.
Primarily reduces client.xsl.sef.json transfer size from ~11.8MB to ~2-3MB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add gzip HTTP tests for SEF file and RDF/XML response

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix gzip HTTP tests: use -D - to avoid binary body, add owner cert for RDF/XML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* nginx conf fix

* Fix gzip RDF/XML test: create item and append data instead of testing root container

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add 3D force graph view mode

Integrates 3d-force-graph / Three.js as a new GraphMode view in the
container block. RDF/XML results are converted to nodes and links,
rendered in an interactive 3D canvas constrained to the .main.span7
column. Supports node click (info panel), double-click (load linked
resources via proxy), hover tooltip, and background click to dismiss.

- Add three.js, three-spritetext, 3d-force-graph UMD bundles (v0.159.0 / v1.8.2 / v1.73.3)
- Add 3d-force-graph.xsl: ForceGraph3D init template, RDF→graph data conversion, node/link mode templates
- Add graph3d.xsl: event handlers (click, dblclick, hover, background), UpdateForceGraph3D, HTTP response handler, tooltip/info panel rendering
- Add normalize-rdfxml.xsl, merge-rdfxml.xsl: RDF/XML normalization and merging pipeline
- Add bs2:Graph template, GraphMode canvas div, CSS rules for .graph-3d-canvas
- Wire graph3d.xsl into client.xsl; add $load-graph3d param to layout.xsl
- Remove obsolete graph.xsl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Initialize 3D graph on document GraphMode; fix blank node merging

- layout.xsl: server-side GraphMode outputs a .graph-3d-canvas placeholder
  div instead of the 2D SVG renderer; client initializes ForceGraph3D
- client.xsl: detect .graph-3d-canvas divs in ldh:rdf-document-response
  and call ldh:InitDocumentGraph3D (mirrors map/chart init pattern)
- graph3d.xsl: add ldh:InitDocumentGraph3D named template for document mode
- normalize-rdfxml.xsl: add 4th pass to prefix blank node IDs with a
  document-unique token, preventing ID collisions when merging multiple
  fetched RDF documents
- merge-rdfxml.xsl: include blank node descriptions from new documents in
  the merge; split rdf:Description match to [@Rdf:about] for property
  merging and [@Rdf:nodeID] for copy-as-is

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add zoom-to-fit, info panel, and filter panel to 3D graph view

- NodeClick writes to info-content panel (dl/dt/dd) instead of tooltip
- Tooltip retained only for hover (position-aware)
- Zoom-to-fit button and filter checkboxes wired via data-canvas-id
- ldh:redisplay-graph reads per-canvas filter state; used by Init and Update
- canvas-id param added to all ldh:UpdateForceGraph3D call sites
- layout.xsl and view.xsl output info/filter/zoom UI inside canvas div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Append 3D graph panels client-side after ForceGraph3D mounts

ForceGraph3D clears the container element on init, wiping any server-rendered
child elements. Mirror the pattern from 3D-Linked-Data/graph-client.xsl:
server outputs only the bare canvas div; ldh:AppendGraph3DPanels appends
tooltip, info-panel, show-panel, and zoom button via ixsl:append-content
after FG3D has mounted. Called from both ldh:InitDocumentGraph3D and the
view.xsl initial-load block. Also replaced hardcoded convert-data call in
view.xsl with ldh:redisplay-graph so filter checkboxes take effect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add CSS for 3D graph overlay panels

Panels need position:absolute to overlay the ForceGraph3D WebGL canvas
instead of stacking below it (which gets clipped by overflow:hidden).
Adds rules for tooltip, info-panel, show-panel, and zoom button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Move gzip config from http block into /static/ and /uploads/ location
blocks so dynamic RDF responses are never compressed, preserving strong
ETags for If-Match precondition checks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix connection pool exhaustion from ?uri= proxy requests (#287)

- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Server-side condition

* Server-side progress bar

* Fix external URI proxy bypass and client-side rendering

- ProxyRequestFilter: use Core-only MediaTypes (no HTML) with combined
  Model+ResultSet writable variant list; selectVariant==null is the sole
  bypass signal so Accept:*/* correctly reaches the proxy instead of
  falling through to the HTML handler
- Thread pre-computed Variant through all getResponse() overloads to
  avoid a second selectVariant call inside Core's Response constructor
- client.xsl onsubmit: skip the XHTML round-trip for external URIs and
  call PushState + RDFDocumentLoad directly, advancing the progress bar
  to 66% between the two steps; fixes the double-click issue
- client.xsl ldh:rdf-document-response: respect the #layout-modes mode
  selector for client-side rendered external resources; refactor the
  duplicate id('content-body') lookup out of both xsl:choose branches
- ProxyRequestFilterTest: stub Request.selectVariant() to return a
  non-null Variant so both tests reach the logic they exercise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ProxyRequestFilter: document HTML bypass rationale; cache MediaTypes instance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ProxyRequestFilter: clarify HTML bypass as resource exhaustion defence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Make HTTP client connectionRequestTimeout configurable

Defaults to 30000 ms (via Dockerfile ENV). Passed through the
CATALINA_OPTS path (same as allowInternalUrls) to avoid exceeding
the ~30-param libxslt limit already reached by context.xsl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ProxyRequestFilter HTML bypass: check Accept header explicitly

Replace the selectVariant==null bypass with an explicit check for
non-wildcard text/html or application/xhtml+xml in the Accept header.
Browsers list these types explicitly (q=1.0) and get bypassed to the
app shell; API clients that send only */* reach the proxy.

The old approach (Core MediaTypes, selectVariant==null) failed for
browsers because their */*;q=0.8 wildcard matched RDF variants,
causing the proxy to return RDF instead of the (X)HTML app shell.

Add testHtmlAcceptBypassesProxy to cover the bypass path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ContentMode block rendering for proxied external resources

Proxied resources' ContentMode blocks (charts, maps) were querying the
local SPARQL endpoint instead of the remote one because ProxyRequestFilter
discarded all external response headers and ResponseHeadersFilter then
injected the local sd:endpoint Link.

- ApplicationFilter: register external ?uri= target in request context
  (AC.uri property) as authoritative proxy marker
- ProxyRequestFilter: forward all Link headers from external response
- ResponseHeadersFilter: skip local sd:endpoint/ldt:ontology/ac:stylesheet
  for proxy requests; removes now-unused parseLinkHeaderValues/getLinksByRel
- client.xsl (ldh:rdf-document-response): extract sd:endpoint from Link
  header and store in LinkedDataHub.endpoint, mirroring acl:mode pattern
- functions.xsl (sd:endpoint()): return LinkedDataHub.endpoint when set,
  fall back to local /sparql — no changes needed in view.xsl or chart.xsl
- CLAUDE.md: document the proxy/client-side rendering architecture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace proxy-detection heuristics with ac:uri() / $ac:uri throughout

- ApplicationFilter: store external URI as AC.uri context property; strip ?uri= from UriInfo
- ProxyRequestFilter: read proxy target from AC.uri context property; bypass HTML requests
- XsltExecutableFilter: remove SYSTEM_ID_PROPERTY; XSLTWriterBase reads AC.uri directly
- XSLTWriterBase: pass $ac:uri to server-side XSLT when proxying
- layout.xsl: declare $ac:uri param; use it for export links and search input pre-fill
- document.xsl: remove proxy spinner branch from bs2:ContentBody
- client/functions.xsl: add ac:uri() function (dynamic read of ixsl:query-params()?uri);
  ldh:base-uri() now calls ac:uri() instead of stale global $ac:uri
- client.xsl: drop global $ac:uri param; ldh:HTMLDocumentLoaded passes ldh:base-uri(.)
  to ldh:RDFDocumentLoad after pushState so URL is already updated
- ProxyRequestFilterTest: update mocks to use AC.uri context property

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add server-side ac:uri() function; refactor ActionBar templates into document.xsl

- Add ac:uri() server-side function to imports/default.xsl (mirrors acl:mode() pattern)
- Move ActionBarLeft/ActionBarMain/ActionBarRight/BreadCrumbBar/ModeList/MediaTypeList templates from layout.xsl to document.xsl
- Fix $effective-mode type error (xs:string → xs:anyURI) and simplify with [1] idiom
- Use ac:uri() instead of $ac:uri in MediaTypeList hrefs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add external document tabs and fix related CSS/XPath regressions (#293)

- Render proxied external documents in tab panes (bs2:TabBody/ldh:CreateTab/ldh:ActivateTab/ldh:RenderTabPane)
- Convert breadcrumb-nav from id to CSS class to support per-pane breadcrumbs; populate breadcrumbs in external tab panes; extract ldh:PopulateBreadcrumbNav named template to DRY up local/external breadcrumb logic
- Fix CSS block border selectors: #content-body → .content-body, add intermediate container-fluid level
- Narrow btn-edit and btn-create-chart match patterns to require .block ancestor, preventing false matches on action-bar
- Fix drag handler match patterns: update stale direct-child path to match new two-level content-body/container-fluid/block structure
- Fix modal content-body lookup: use ancestor:: for action-bar buttons, active tab-pane for global buttons, so modals append to the visible pane for proxied documents
- Remove dead document-mode-tabs template and broken progress bar update targeting hidden #content-body
- Remove unused getModes() override from XSLTWriterBase

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix disabled edit button triggering modal and move action buttons inside auth guard

- Prevent click handler from firing on disabled edit button by adding [not(contains-token(@Class, 'disabled'))] predicate
- Move ACL and Edit buttons inside the xsl:if auth guard so they are not rendered for unauthorized users
- Wrap edit button in pull-right div and add ldh:logo icon to match ACL button structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Ignore clicks on disabled edit button in modal click handler

Add [not(contains-token(@Class, 'disabled'))] predicate to the btn-edit
match template so that clicking a disabled edit button does not open the
edit modal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Refactor external doc tabs: per-URI panes, data-* state, tab-pane-id param

- Replace LinkedDataHub.tabs/tab-counter JS registry with data-uri/data-endpoint
  attributes directly on tab <li> elements; sd:endpoint() now reads from dataset
- Give each external document its own tab pane (one per URI) instead of a shared
  external pane; tab pane visibility toggled via display:none/block
- Rename ldh:CreateTab → ldh:AddTabNavBarListItem (no longer handles rendering);
  ldh:RenderTab now accepts $tab-pane-id (xs:string) instead of $tab-pane element,
  since the element is detached after ixsl:replace-element
- ProxyRequestFilter: inject MediaTypes, throw NotAcceptableException on no variant
  match instead of silently returning; remove manual HTML Accept-header inspection
- Remove $ac:uri XSLT param and related proxy-target plumbing from XSLTWriterBase
  and layout.xsl; remove LDH.access_to vocabulary property
- Switch service document fetches from ac:build-uri() to ldh:href() throughout
- Move srx:sparql bs2:ContentBody template from layout.xsl to document.xsl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Simplified tab rendering

* (X)HTML response fix in the proxy filter

* Additional tests

HTTP test and unit test

* Restored (X)HTML workaround in the proxy filter

* Add margin-top to .content-body to restore spacing after sticky action-bar change

The action-bar moved from inside .navbar-fixed-top (120px body padding) to sticky positioning (55px body padding), eliminating the 14px gap that existed between the action-bar and content-body.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Simplify external doc tab rendering and add lapp:application Link header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove services fetch, service dropdown, and refactor navbar into separate templates

The client-side getResourceWithRetry(servicesRequestUri) fetch and ldh:apps
stylesheet parameter were unused — remove them along with the service select
dropdown and related onServiceLoad/RenderServices templates. Refactor the
navbar into bs2:NavBarLeft, bs2:NavBarMain, and bs2:NavBarRight templates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Tab activation fixes

* Hide system resources in client-side XSLT

* Fix navbar/tab-bar/action-bar spacing and move sidebar into tab panes

Update hardcoded 55px navbar height to 51px across CSS and XSLT to match
actual rendered height after search bar refactoring. Move left-sidebar from
global #left-sidebar to per-tab-pane .left-sidebar, store endpoint/base/application
as data attributes on tab panes instead of tab-bar list items, and refactor
navigation to scope sidebar operations to the active tab pane.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add document-body wrapper, introduce ldh:DocumentNavigate, fix content-body XPaths

Wraps action-bar and content-body in a document-body div (carrying @about/@typeof),
removes XHTML-based ldh:xhtml-document-loaded in favour of a new ldh:DocumentNavigate
named template that centralises local/external navigation via RDF. Fixes content-body
ancestor XPaths broken by the new document-body wrapper, pre-renders the local tab in
the tab-bar, and removes server-side SD endpoint / forShape param passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix modal document edit error by closing modal and reloading document on PATCH success

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Move abort controller and cursor into ldh:DocumentNavigate, simplify call sites

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* `bs2:DocumentBody` mode

* Render signup form client-side, implement tab close

- Move signup.xsl include from admin/layout.xsl to client.xsl so its
  templates compile into the Saxon-JS SEF; drop use-when="SAXON" gates,
  switch $ldt:base to ldt:base() and $main-doc to ldh:base-uri(.)
- Replace ldh:construct / Construct.java extension function with
  ldh:construct-forClass via the existing /ns endpoint
- Implement tab close: remove pane, activate fallback tab, hide tab-bar
  when only the base-uri tab remains; reposition .tab-close as absolute
  corner element
- Drop dead error-alert fallback in ldh:rdf-document-response

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fixed relative URL

* `ldh:NavigationUpdate` call moved into `ldh:RenderTab`

* Request URI fixes

* Pipe proxied HTTP responses as InputStream instead of parsing/re-serializing

Pre-selecting a variant from a combined Model+ResultSet writable types list
before knowing the response entity type caused a 500 when the upstream returned
RDF (read as Model) but the pre-selected variant was application/sparql-results+xml
— Jersey had no MessageBodyWriter<Model> for that type.

External HTTP responses are now forwarded verbatim (status, Content-Type, body,
Link headers). The upstream already negotiates content type via the forwarded
Accept header. Local paths (DataManager cache, ontology DESCRIBE) keep proper
Model-specific content negotiation.

Also removes the dead BadGatewayExceptionMapper that incorrectly mapped
BadGatewayException to 500.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove stale testNullVariantThrowsNotAcceptable test

The filter no longer pre-selects a variant, so 406 for unsatisfiable
Accept is delegated to the upstream. The test and its now-unused
getSupportedLanguages() stub are removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fixed client's accepted media types

* Proxied `ETag` header test

* Proxied HTML `Accept` test

* Forward end-to-end response headers from proxied upstream

* Use top-quality `Accept` value to decide HTML proxy bypass

* Wrap XSLT `document()` URIs with `ldh:href` and clean up client templates

* Rework proxy `Accept` regression tests, simplify q-rank bypass

ProxyRequestFilter:

- Drop the `quality(MediaType)` helper and the topQ/filter pipeline. Per the
  JAX-RS spec, `getAcceptableMediaTypes()` is sorted by q descending (Jersey:
  `HttpHeaderReader.readQualifiedList` → `AcceptableMediaType.COMPARATOR`), so
  the first non-wildcard type is the top-ranked one. Replace with a single
  loop that returns on (X)HTML and breaks otherwise.

Tests:

- Add `GET-proxied-accept-forwarded.sh` regressing 708edfc: send a single
  specific RDF type as `Accept` and assert the response `Content-Type` matches.
  Pre-fix, ProxyRequestFilter substituted its own readable-types list for the
  client's `Accept`, so upstream could pick any RDF format (e.g. rdf-thrift).
- Rework `GET-proxied-accept-html-not-preferred.sh` to use HTTP status as the
  bypass-vs-forward discriminator. The previous content-type assertion was
  unreachable in a symmetric admin/end-user setup — both paths negotiate the
  same media type. A UUID-named non-existent path produces 200 on bypass
  (`ApplicationFilter` strips `?uri=` → admin root) and 404 on forward.
- Silence `DEBUG:` echoes in `HEAD-proxied-etag.sh` to match the convention of
  the other proxy tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Removed debug messages

* Removed unused template

* Revert "Removed unused template"

This reverts commit ec76099.

* Wire `bs2:SignUpComplete` into signup success path

- Pass `'form-signup'` to `bs2:RowForm` via `form-id` (lands on the form
  itself) instead of `id` (wrapper div), so the new submit handler matches.
- Add `match="form[@id = 'form-signup']"` template that overrides
  `$callback` via `xsl:next-match`, plus `ldh:signup-form-response`:
  `201 + Location` calls `bs2:SignUpComplete`, otherwise delegates to
  `ldh:row-form-response`.
- Update `bs2:SignUpComplete` to target the active tab pane's
  `content-body` (post-tabs DOM no longer has a singleton `#content-body`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Static XSL resources (translations.rdf, http-statusCodes.rdf, countries.rdf)
and JS/CSS assets in the rendered XHTML shell are now resolved against
$lapp:origin instead of $ac:contextUri. On dataspace subdomains
(e.g. https://northwind-traders.demo.localhost/) this keeps fetches
same-origin and avoids CORS-blocked XHRs against the system base URI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Move ldh:view block injection client-side under Saxon-JS

The SSR-only wrapper template (resource.xsl:605) injected view blocks
synchronously via document() against the ?ns SPARQL endpoint, which
worked under SAXON but was compiled out of the Saxon-JS SEF. Initial
load painted the wrappers correctly, but client.xsl:537 replaced the
SSR document-body with a fresh Saxon-JS render that lacked them, and
view.xsl:62 had nothing to hydrate.

- resource.xsl: drop the SAXON-only wrapper template; add a Saxon-JS-only
  bs2:Row template at priority 0.7 that always wraps non-typed-block
  resources in outer div + inner div.span12 around next-match output,
  so client-side injection has a host whose @about ends in #this for
  primary topics. Excludes types handled by resource.xsl:463 to avoid
  injecting spurious nesting into View/Object/Query/Chart chains.

- layout.xsl: drop unused $forward-view-query and $inverse-view-query.

- client/block.xsl: add combined $view-query (forward + inverse via
  UNION); amend default mode='ldh:RenderRow' template to fan out per
  wrapper (xsl:for-each over the inner typed-block selector); add
  ldh:view-blocks-{self,query,fetch,render}-thunk mirroring the
  view.xsl:107-147 pattern. Render step calls apply-templates
  mode='bs2:Row' on the loaded View resource - same call the deleted
  SSR code used - so the injected HTML matches resource.xsl:463 output
  byte-for-byte.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Comment

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ring

Align the client-side rdf:RDF default template with SSR ordering by
rendering the current document and its foaf:primaryTopic at the top,
followed by the remaining resources.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Generalise request/response keys in XSLT promise chains

Add request-key/response-key parameters to ldh:handle-response,
ldh:retry-request, ldh:rethread-response, and ldh:http-request-threaded
so multiple HTTP steps can coexist in one context map without clobbering
each other. Update block/chart, block/object, block/view, form, and
modal call sites to use named keys (chart-results-*, object-metadata-*,
view-results-*, metadata-*, type-metadata-*) and merge into the inbound
context instead of rebuilding fresh maps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Generalise object-metadata loading across XSLT chains

Move ldh:load-object-metadata and ldh:set-object-metadata into the
shared client/block.xsl so both the view-results chain and the
client.xsl document-load chain can reuse them. Split out
ldh:view-results-error-handler for the view-specific HTTP error UI,
and relocate the ac:object-label template to imports/default.xsl so
server-side rendering can also resolve cross-document object labels
via an object-metadata tunnel param.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Chore

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the layout-level ldh:send-request that fetches cross-document
object labels in xsl:try, so an unreachable or unauthorized SPARQL
endpoint degrades to no labels instead of aborting the page render
with HTTP 500. Restores the non-existent dataspace, install-package
403, and unauthenticated agent rendering tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e respects the requested format

Previously the ?accept -> Accept header override in ApplicationFilter ran after the matchApp() check,
so a NotFoundException thrown for an unrecognised dataspace was mapped using whatever Accept the client
sent (typically text/html), returning XHTML instead of the requested RDF format. Moving the override
before the app-match check mirrors the existing ?mode handling and ensures the NotFoundExceptionMapper
performs content negotiation against the correct Accept value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…or unknown dataspaces

- client.xsl: handle application/rdf+xml responses in ldh:rdf-document-response by rendering into an existing matching tab-pane or appending a new tab body
- layout.xsl: restrict bs2:Brand to origins with a matching app and add no-op fallback; parameterise bs2:DataspaceNavList with id/class and add no-op fallback; drop unused bs2:AppListItem template
- document.xsl: suppress bs2:NavBarActions for http:Response resources; drop redundant priority on the generic bs2:ModeList template
- resource.xsl: remove obsolete btn-acl class from acl:Access logo

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant