Skip to content

feat: generate viewer links dynamically for Zarr datasets#307

Open
allison-truhlar wants to merge 59 commits intomainfrom
viewers-config
Open

feat: generate viewer links dynamically for Zarr datasets#307
allison-truhlar wants to merge 59 commits intomainfrom
viewers-config

Conversation

@allison-truhlar
Copy link
Collaborator

@allison-truhlar allison-truhlar commented Feb 2, 2026

Clickup id: 86advt10e

This PR implements dynamic viewer configuration for Zarr datasets via a build-time viewers.config.yaml file and integration of the @bioimagetools/capability-manifest library for automatic dataset-viewer compatibility detection.

Changes

  • Created viewers.config.yaml with documentation for customizing viewer configuration. This file specifies available viewers for a Fileglancer deployment. The default configuration is our current viewers: Neuroglancer, Avivator, Vol-E, and OME-Zarr Validator. Configuration is bundled at build time.

  • Added ViewersContext for managing viewer configuration. This context:

    • Loads and validates viewer configuration from YAML at initialization
    • Fetches capability manifests using @bioimagetools/capability-manifest library, or load from the /public folder bundled into the application during the build (this is currently the case since the manifests are not present on our main branch, only in this PR branch)
    • Provides getCompatibleViewers() function to determine dataset-viewer compatibility using the capability-manifest library for compatibility detection
  • Refactored useZarrMetadata to dynamically generate openWithToolUrls using ViewersContext. URLs are generated only for compatible viewers based on the getCompatibleViewers function.

  • Updated DataToolLinks to render viewer buttons dynamically by mapping over valid viewers from ViewersContext. The "Copy URL" tool is always available when a data link is available.

  • Added logo management system with convention-based naming ({name}.png), custom logo override support, and fallback logo for missing assets.

  • Added unit tests for config parsing and component tests for DataToolLinks.

  • Updated documentation with a ViewersConfiguration.md guide and updated CLAUDE.md with viewer configuration instructions.

- Custom viewers (validator, vol-e) now check for multiscales
- Ensures viewers only display for OME-Zarr datasets, not plain Zarr arrays
- Update DataToolLinks alt text to use displayName for E2E test compatibility
Add useCallback to memoize the getCompatibleViewers function in
ViewersContext to prevent unnecessary recalculations and improve
performance when filtering compatible viewers based on metadata.
Add more detailed error logging and ensure graceful degradation when:
- Capability manifests fail to load
- Viewer configuration parsing fails
- No valid viewers are configured

The application will continue with an empty viewer list and clear
console messages to help users troubleshoot configuration issues.
Copy link
Member

@neomorphic neomorphic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I was able to enable and disable a viewer using the viewers.config.yaml. I added a few comments about some the code I wasn't sure on.

- previously, if a logo path wasn't found, a 404 URL was still created, so it was never falling through to the fallback_logo.
- includes checking that a fallback_logo is used when no logo is found for a viewer
if (url) {
// Extract base URL from template (everything before #!)
const neuroglancerBaseUrl =
viewer.urlTemplate.split('#!')[0] + '#!';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above - this is a temporary fix

test: refine error message expectations in viewersConfig tests
test: fix mock hoisting in DataToolLinks test

test: simplify capability manifest mock structure

test: update tests for new capability-manifest API

test fix

test fix

**Quick Setup:**

1. Edit the configuration file at `frontend/src/config/viewers.config.yaml` to enable/disable viewers or customize URLs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best not to edit committed source code to change configuration. If users change version controlled code then they will have problems staying up to date with upstream changes. One alternative pattern for this would be to allow users to copy this file into the main directory with their own changes, and then during the build use it to override the default config.

} catch (manifestError) {
log.error('Failed to load capability manifests:', manifestError);
throw new Error(
`Failed to load viewer manifests: ${manifestError instanceof Error ? manifestError.message : 'Unknown error'}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another case where we likely want to pick where this error should get logged, and not propagate errors that were already handled.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 59d64ac

openWithToolUrls.avivator = null;
// Convert our metadata to OmeZarrMetadata format for capability checking
const omeZarrMetadata = {
version: effectiveZarrVersion === 3 ? '0.5' : '0.4',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is extremely fragile code from my original vibe-coded prototype. We need a better way to get the NGFF version.

Starting in NGFF 0.5, there is an attribute that specifies the version (https://ngff.openmicroscopy.org/specifications/0.5/index.html#ome-zarr-metadata).

I'm not sure if there's a reliable way to tell for versions prior to 0.5. @mkitti do you know? We could take a look at the OME-NGFF Validator, which somehow prints the version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

4 participants