Skip to content

feat: generate viewer links dynamically for Zarr datasets#307

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

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

Conversation

@allison-truhlar
Copy link
Copy Markdown
Collaborator

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

Clickup id: 86advt10e

This PR implements dynamic viewer configuration for Zarr datasets, using the @bioimagetools/capability-manifest library for automatic dataset-viewer compatibility detection. The PR has been edited since it was first created to support both build-time (original PR) and runtime (new) configuration. The latter will allow the customization of viewers in system installs that use Fileglancer from Pypi, using a new FGC_VIEWRES_CONFIG .env variable.

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. Default configuration is bundled at build time.

  • Runtime config API endpoint - added GET /api/viewers-config that serves a YAML config file from a path set via FGC_VIEWERS_CONFIG (or viewers_config in config.yaml). Returns 404 when not configured, allowing the frontend to fall back to the bundled default.

  • 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
    • Provides getViewersCompatibleWithImage() 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 unit tests for config parsing and component tests for DataToolLinks. Added backend tests for the /api/viewers-config endpoint.

  • 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
Copy Markdown
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.

Comment thread frontend/src/config/viewerLogos.ts Outdated
Comment thread frontend/src/queries/n5Queries.ts
Comment thread frontend/src/hooks/useN5Metadata.ts
Comment thread frontend/src/config/viewersConfig.ts Outdated
Comment thread frontend/src/config/viewersConfig.ts
Comment thread frontend/src/contexts/ViewersContext.tsx Outdated
- 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
The validateViewer mock was using the old `compatible` field instead of
`dataCompatible`/`dataFeaturesSupported`, causing tests to pass for the
wrong reason. Also adds missing `getLogoUrl` mock to prevent undefined
function errors.
Use explicit OmeZarrMetadata type annotation with targeted field casts
instead of a blanket `as any`, so type mismatches with the
capability-manifest library will be caught at compile time.
Replace non-alphanumeric stripping with hyphen substitution, matching
the convention used by getLogoUrl. Prevents silent key collisions for
names like "Vol-E" vs "Vol E".
The docs showed instance_template_url and label overrides in the default
config example, but the actual committed config has bare manifest_url
entries only.
Race loadManifestsFromUrls against a timeout promise so the viewer
initialization fails fast when manifest URLs are unreachable.
Apply the same URL/absolute-path validation to instance_template_url
that manifest_url already has, catching invalid values at parse time
instead of at runtime. Updates test to expect empty strings to be
rejected.
Avoids name collision with the library's exported getCompatibleViewers from capability-mainfest
@mkitti
Copy link
Copy Markdown
Contributor

mkitti commented Apr 15, 2026

Should we scope these as "zarr-viewers"?

While I recognize that Zarr is the focus, fileglancer might allow for glancing at files other than Zarr in the future.

For example, there could be a HDF5 viewer:
https://myhdf5.hdfgroup.org/

@krokicki
Copy link
Copy Markdown
Member

While I recognize that Zarr is the focus, fileglancer might allow for glancing at files other than Zarr in the future.

It's a good point, we will need to likely support viewers in the future which will not have capability manifests. I think we can just extend the viewers.config.yaml schema for that when the time comes?

@allison-truhlar
Copy link
Copy Markdown
Collaborator Author

allison-truhlar commented Apr 15, 2026

@krokicki This is ready for you to look at again. I made notes on all your comments about the commits that addressed them. I also modified the PR description slightly to reflect the current state of the PR.

Note that it should be reviewed in conjunction with the changes to the capability-manifest library proposed in this PR.

One outstanding question I have is how to implement the rfcs_supported check (see full question here).

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