Skip to content

Feature/configurable template - #93

Open
SilviaSWR wants to merge 14 commits into
rexzhang:mainfrom
SilviaSWR:feature/configurable-template
Open

SilviaSWR wants to merge 14 commits into
rexzhang:mainfrom
SilviaSWR:feature/configurable-template

Conversation

@SilviaSWR

Copy link
Copy Markdown
Contributor

Checklist

  • I have read the contribution guidelines
  • One Feature(issue) One PR
  • All commits in the PR will be merged into a single commit.
  • Add an entry in changelog.en.md if necessary
  • Add my name and GitHub profile link
  • Add / update tests if necessary
  • Add new / update outdated documentation

Description

This PR introduces support for configurable HTML templates for the directory browser page, replacing the previous hardcoded HTML generation.

The goal is to decouple presentation from backend logic and allow full UI customization without modifying core server code.

Changes

  • Introduced template-based rendering for directory listing
  • Removed hardcoded HTML generation for directory browser
  • Added support for external template file configuration
  • Exposed context variables to templates:
    • path
    • parent
    • items
    • version
    • current_time

Features enabled

This change allows deployments to fully customize the directory browser UI, including:

  • Custom CSS styling via external stylesheets
  • Use of images and logos (via static assets)
  • Full layout and branding customization
  • Custom footers and acknowledgments without code changes

fixes #91

@codecov

codecov Bot commented Apr 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.67797% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.39%. Comparing base (04e3760) to head (02932cb).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
asgi_webdav/config.py 50.00% 4 Missing ⚠️
asgi_webdav/server.py 72.72% 3 Missing ⚠️
asgi_webdav/web_page.py 62.50% 3 Missing ⚠️
asgi_webdav/cli.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #93      +/-   ##
==========================================
+ Coverage   76.00%   77.39%   +1.39%     
==========================================
  Files          26       27       +1     
  Lines        3776     3849      +73     
==========================================
+ Hits         2870     2979     +109     
+ Misses        906      870      -36     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

This contribution has received funding from the Spanish government (grant EQC2021-007479-P, funded by MCIN/AEI/10.13039/501100011033), the EU NextGeneration/PRTR (PRTR-C17.I1), and the Generalitat de Catalunya.

Comment thread asgi_webdav/static/styles.css Outdated
Comment thread docs/acknowledgements.md
@SilviaSWR
SilviaSWR force-pushed the feature/configurable-template branch from 0b8e9b0 to e6ee57a Compare May 4, 2026 09:15
@SilviaSWR

Copy link
Copy Markdown
Contributor Author

@rexzhang just following up on this PR. Whenever you have time, I’d appreciate a review or any feedback.

@rexzhang

rexzhang commented May 18, 2026 •

Copy link
Copy Markdown
Owner

I'm very sorry, I've been very busy lately...

  • It's a good idea to use templates for flexible page layouts
  • Loading the template file once on every page request is not an acceptable design
  • Is it necessary to add so many third-party dependencies for a single page?
  • How to package a lot of new template related files into the wheel?
  • If you want to use optional external template-related files, use the configuration. In addition, if you need docker versioning support, you need to support the command line argument(enn, CLI support is optional)
  • BTW:the new code needs 100% unit test coverage

@SilviaSWR
SilviaSWR force-pushed the feature/configurable-template branch from 39da949 to 04b1ef5 Compare June 2, 2026 13:31
@SilviaSWR

Copy link
Copy Markdown
Contributor Author
  • Template is already loaded once in init.
  • No new third-party deps introduced; uses stdlib string.Template (no Jinja2).
  • Template/static assets are correctly packaged via package_data / MANIFEST.in.
  • External template override is already supported via config/env/CLI, with bundled fallback.
  • Full unit tests for template-related behavior.

@rexzhang

rexzhang commented Jun 4, 2026 •

Copy link
Copy Markdown
Owner
  • could you move all template relate files into asgi_webdav/templates, as below:
asgi_webdav/templates
+ dir_browser
++ index.html(orig: asgi_webdav/templates/dir_browser.html)
++ styles.css
++ <other files>
  • fully template part support
    • move parent_html and items_html` into template system
    • extending dir_browser_template to template_dir
  • file asgi_webdav/templates/dir_browser.html contains the contents of file asgi_webdav/static/styles.css, why?
  • Is it possible to support some(part) template files to fallback to the bundled?

@SilviaSWR
SilviaSWR force-pushed the feature/configurable-template branch 2 times, most recently from 6168e25 to afb5763 Compare June 4, 2026 15:14
@rexzhang

rexzhang commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Regarding the design part; it is recommended to discuss it thoroughly before starting to write code.

BTW: in AI era, talk in the mother tongue is also welcome

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

I agree! Let's discuss the design first. I have simplified the code for now to open the discussion at this early stage before things get too complex.

For the structure, I completely agree with putting the templates under /templates/dir_browser/. This will be much cleaner, especially if the project needs more templates in the future.

Since this feature moves the HTML outside of the Python code, I would like to move all of it out. We have two options for how to structure the files inside /templates/dir_browser/:

  1. Use a single index.html and rely on the template engine's for/if constructs to render the parent and item rows.
  2. Split it into smaller partials such as index.html, row_parent.html, and row_item.html.

I am fine with either approach.

In my last two commits, I tried the second approach to explore how it would look in practice.

I also tested it on our server with an additional acknowledgment for our institution, and it works as expected.

What is your view on this? I would prefer to agree on the overall structure first, and then continue with the implementation :)

@rexzhang

Copy link
Copy Markdown
Owner
  • first, i wish this template system is a template system for whole server, not a template system for dir_browser page
  • template system support fallback
    • search order: user custom template path => built-in template
    • fallback support any one file of whole template system
  • template file load optimize
    • load template in init stage?
    • cache template in memory at first loding?
    • built-in template in code?
  • Split it into smaller partials such as index.html, row_parent.html, and row_item.html is a good design
  • one page's all template file in one dir. if needed, it can have its own subdirectory.
    • all template dir in one parent dir, like this:
templates
+ page_a
++ index.html
++ style.css
++ ...
+ page_b
+ ...

BTW: during Draft stage, no test coverage is required.

@SilviaSWR
SilviaSWR force-pushed the feature/configurable-template branch from f8a8c2e to 20c1bd8 Compare July 17, 2026 09:54
@SilviaSWR

Copy link
Copy Markdown
Contributor Author

Thank you for the thorough design feedback! Here's how each point was addressed:

  1. Whole-server template system, not dir_browser only

Done. TemplateLoader is a standalone class in asgi_webdav/template.py, used by all three consumers: WebDAV (dir browser), DAVAuth (401 page), and WebPage (admin pages). The config is now template_dir, not dir_browser_dir.

  1. Fallback: user custom path → built-in

Done. TemplateLoader.get_template(page, name) checks custom_dir/page/name first, falls back to builtin_dir/page/name. Per your suggestion, the built-in templates remain as files on disk (not embedded in code) — easier to maintain.

  1. Fallback for any individual file

Done. Each file is resolved independently. You can override just error/401.html while keeping all other templates as bundled.

  1. Load once in init, cache in memory

Done. TemplateLoader is instantiated once in DAVApp.__init__ (server.py:42), passed to all consumers. Templates are loaded on first get_template() call and cached in a dict[str, Template].

  1. Split into partials

Done. Directory browser uses: index.html, row_parent.html, row_directory.html, row_file.html. Admin pages use simple single-file templates (too simple for partials). Error page uses a single 401.html.

  1. One page per dir, all dirs under one parent

Done. Layout:

asgi_webdav/templates/
  dir_browser/
    index.html, row_parent.html, row_directory.html, row_file.html
  admin/
    index.html, logging.html
  error/
    401.html

Users provide the same structure under their template_dir.

@rexzhang

rexzhang commented Jul 19, 2026 •

Copy link
Copy Markdown
Owner

thank for you do this! The string.Template is real indeed ugly, the f-string has compatibility issues...

btw: I'll be 2-4 weeks before I have time to do a full review.

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

Agreed, string.Template syntax is not the prettiest, but it's the simplest stdlib option that works with external template files. f-strings only work in .py code, not in files loaded from disk. Alternatives like Jinja2 would add a new dependency, which we wanted to avoid.

@rexzhang

Copy link
Copy Markdown
Owner

For independent fixes, please create a separate pull request. The simpler the PR, the less review time is needed.

SilviaSWR and others added 9 commits August 25, 2026 15:35
- Remove jinja2 dependency; use string.Template, html.escape, urllib.parse.quote
- Load template once at init instead of every request
- Inline CSS into template, remove external stylesheet link
- Add dir_browser_template to Config, EnvConfig, and AppEntryParameters
- Add --dir-browser-template CLI argument
- Rewrite tests to use real DAVProperty/DAVPropertyBasicData and real template rendering (100% coverage of new code)
SilviaSWR added 5 commits August 25, 2026 15:35
- Allow --dir-browser-template to point to a directory instead of a file
- Fall back to built-in index.html when custom directory lacks one
- Prepend custom directory to static_root_paths so CSS overrides work
- Update CLI help text and log messages to reflect directory semantics
- Change href from relative  to absolute
- Applied to bundled template and acknowledgment template
- Set  in webdav.json to use acknowledgment template
…plates()

- Remove asgi_webdav/template_loader.py (51-line class with properties
  and dead get_static_root_paths method)
- Move load_templates() into web_dav.py as a 17-line module-level function
- Use _TEMPLATES dict as single source of truth for template filenames
- Update tests for new function-based API, remove dead-code tests
Replace the dir_browser-only template loading with a general-purpose
TemplateLoader class that supports any page.

- Add asgi_webdav/template.py with TemplateLoader (per-file fallback,
  in-memory caching)
- Add bundled templates: admin/index.html, admin/logging.html,
  error/401.html
- Rename config dir_browser_dir → template_dir (breaking)
- Refactor auth.py 401 page and web_page.py admin pages to use
  templates instead of hardcoded HTML
- Refactor web_dav.py: remove load_templates(), _TEMPLATES dict, and
  _BUNDLED_DIR; use TemplateLoader.get_template(page, name)
- Create shared TemplateLoader in server.py, pass to all consumers
- Remove stale asgi_webdav/static/ packaging references
- Update tests, add TemplateLoader unit tests, remove redundant
  @pytest.mark.asyncio decorators
- Add howto-customise-html-templates.en.md
- Update changelog, CLI docs, env var docs, config reference

contributed by PIC
All except blocks in webhdfs.py only caught httpx.HTTPStatusError,
which does not cover transport-level exceptions like PoolTimeout,
ConnectError, etc. This caused unhandled exceptions to propagate
as generic 500 errors when the HDFS backend was slow or unreachable.
@SilviaSWR
SilviaSWR force-pushed the feature/configurable-template branch from d47fbeb to 02932cb Compare August 25, 2026 13:35
@SilviaSWR

Copy link
Copy Markdown
Contributor Author

I've just updated the branch with the changes from main. None of the unrelated template changes have been removed.
I'm already testing this branch on a real server, and the configuration seems to be working correctly so far :)

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

Hi @rexzhang, have you had a chance to review this PR? Just wanted to check in and get up to date on its status. Thanks!

This branch has not been deployed

No deployments
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.

Feature request: support configurable templates for HTML directory listing

3 participants