Skip to content

[IMP] dms: UX modernisation (kanban density + dashboard + side-pane preview + form heroes + portal grid + test coverage)#3

Open
dnplkndll wants to merge 184 commits into
19.0-mig-dmsfrom
19.0-imp-dms-ux
Open

[IMP] dms: UX modernisation (kanban density + dashboard + side-pane preview + form heroes + portal grid + test coverage)#3
dnplkndll wants to merge 184 commits into
19.0-mig-dmsfrom
19.0-imp-dms-ux

Conversation

@dnplkndll
Copy link
Copy Markdown

@dnplkndll dnplkndll commented May 21, 2026

Comprehensive UX modernisation of OCA dms for 19.0, stacked on top of the in-flight OCA/dms#475 MIG. Fork-only — exists for runboat preview + stakeholder review while we iterate. Subsets will be split into focused upstream PRs once OCA#475 lands and the 19.0.1.0.0 wheel publishes.

Base: 19.0-mig-dms · Head: 19.0-imp-dms-ux · Stacked under #9 (Hoot tests), #7 (CI), and #8 (libreoffice preview).

What the branch changes

  • Kanban density modes (comfortable / compact / list) with a floating toggle, per-density layout, selection persisted to localStorage.
  • Directories landing dashboard — stat tiles for Files / Storage / New today, 30-day sparklines, week-deltas. Live _read_group on indexed create_date (no snapshot table, no cron).
  • Side-pane file preview + pluggable handler registry at registry.category("dms.preview_handlers"). Built-in handlers: image, PDF, audio, video, text, markdown, office-fallback, download-fallback. Score-based dispatch — sibling modules register at higher scores to override.
  • Per-extension accent palette shared between backend kanban and portal grid (single SCSS token file).
  • Form heroes for directory + file (icon + tags + path + stats + 2-tab notebook) replacing the upstream loose-fields arch.
  • Hash-bucketed initials chip on directory cards (8 palette buckets, computed at render time — no model field). Circular avatar rule applied uniformly.
  • Animated dropzone, search-facet pill styling, side-pane action toolbar (Download / Share / Open form).
  • OWL 2.x adoption: useExternalListener replaces paired onMounted/onWillUnmount; static class fields replace OWL 1 prototype assignments; boolean t-att-* coerced to explicit 'true'/'false' strings (U5); dead file_kanban_controller deleted (U7).
  • Responsive collapse: side-pane + toggle + density buttons collapse to icon-only below Bootstrap lg (991.98px).

Architecture notes for reviewers

  • Registry contract: dms/static/src/js/components/preview/preview_registry.esm.js — each handler is {component, match, score}; catch-all download handler runs at -100 so any registered handler wins.
  • Effective mimetype fallback: when libmagic returns application/octet-stream (several MP4 variants), _effectiveMimetype() in file_preview_pane.esm.js falls back to a 25+ extension table.
  • Markdown handler: renders text/markdown in a sandboxed <iframe srcdoc>. XSS-safe via HTML escape + link-protocol allowlist.
  • Owl quirks pinned by tests in #9: regex literals don't tokenize in QWeb expressions; boolean attrs serialize as empty strings unless coerced.

Preview

  • Runboat: https://ledoent-dms-19-0-imp-dms-ux-pr3-<sha>.runboat.hz.ledoweb.com

CI

GitHub Actions on the ledoent org is currently throttled by Actions abuse-detection. Runboat preview builds pass; local --test-enable passes. See #7 for the CI-side observability work.

Mathias Markl and others added 30 commits May 12, 2026 15:52
versions of muk_dms than 12.0.2.0.0.

Tested from 1.2.4 version.
In v13, this test is programmed in such a way that the demo user is supposed to be able to copy that subdirectory: https://github.com/OCA/dms/blob/c3f802db43362127e70d8c7b4987fb71d4c1f01c/dms/tests/test_directory.py#L40

However, in OCA#7 that test was modified indicating that demo user didn't have permissions to do that: https://github.com/OCA/dms/blob/e3b6d8d24534f2a68bfb88e310cc70cefe46bb64/dms/tests/test_directory.py#L39

Rolling back that change to ensure premissions remain the same in both versions of the module.

Also changing the directory to test to ensure it contains no SVG files, whose detection seems to differ among environments, and which have some specific permission restrictions that can make the modified test fail or pass.

@Tecnativa TT25645
dnplkndll added a commit that referenced this pull request May 26, 2026
…toolbar collapse

Fork-only iteration on top of #3. Five distinct themes folded into one
squashed commit since this PR exists for runboat preview / stakeholder
review, not upstream review.

CI artifact pipeline (test-failure observability)
- `Upload screenshots from JS tests` step captures /tmp/odoo_tests/<DB>
  on failure. Forward-port from the cookiecutter; companion template PR
  at ledoent/oca-addons-repo-template#1.
- `Upload odoo server log on failure` step captures
  /var/log/odoo/*.log + workspace + runner-temp.
- `workflow_dispatch:` so we can manually re-trigger when GitHub silently
  throttles fork-PR runs after a push burst.
- checklog-odoo.cfg ignores `Killing chrome descendants` WARN
  (benign browser_js cleanup; `OCA_ENABLE_CHECKLOG_ODOO=1` was treating
  it as a build error).

Hoot test suite (tests/test_hoot.py + tests/test_backend_tours.py)
- tests/test_hoot.py wires HttpCase.browser_js with
  `/web/tests?...&filter="@DMS"` — Hoot's `?filter=` defaults to fuzzy
  character-order matching; the double-quoted exact-substring form
  isolates @dms/... test paths from the bundled web-core suite.
- 9 Hoot test files run + pass under the wiring: dms_stat_bar,
  file_preview_pane, preview_handlers, preview_registry,
  file_kanban_buttons / _density / _mount / _list_renderer routing.
- `defineMailModels()` covers the mock-server base because dms depends on
  mail; `expect.errors(N) + verifyErrors(patterns)` replaces the
  array-of-objects form Hoot rejects.

OWL 19.0 readiness audit (per oca-review U/T pattern catalog)
- U7 (HIGH): delete dead static/src/js/views/file_kanban_controller.{xml,esm.js}.
  The XML defined dms.FileKanbanView.Buttons via t-inherit="web.KanbanView.Buttons"
  — the exact pattern that crashes at OWL render against 19.0's emptied
  template. Not wired anywhere; the view uses the self-contained
  dms.KanbanButtons template.
- U5 (MEDIUM): coerce boolean t-att-* attributes to explicit 'true'/'false'
  strings. Owl serializes truthy booleans as a presence flag (<div data-loading>),
  so CSS selectors `[data-loading="true"]` and tour selectors
  `[aria-pressed="true"]` silently never matched. Applied to data-loading
  on the stat bar and to aria-pressed on both density and preview toggles.
- U2 (style): convert 10 OWL 1 prototype-assignment idioms
  (`Foo.template = "x"; Foo.props = {...}`) to OWL 2 static class fields
  across 7 component classes. Cross-file `Renderer.template = "..."`
  assignments lifted into the renderer class declarations where they belong.

View toolbar collapse (overlap fix)
- Both renderers were stacking four absolute-positioned floaters in the
  top-right corner: preview-toggle pill (kanban + list), density toggle
  (twice — once in file_kanban.scss, once shifted to right:160px inside
  the kanban-split context). On list view this put the preview pill on
  top of the column-header row immediately under Odoo's control panel.
- Replaced with `.o_dms_view_toolbar` — one in-flow strip above the
  grid/list, populated with whatever view-level controls each renderer
  needs (density btn-group + preview pill on kanban; preview pill only
  on list, right-anchored via `__spacer { flex: 1 }`). Gone: 4
  absolute-position rules, 2 `right: calc(40% + 12px)` shifts, 1
  `display: none` density hack, all z-index battles.

Backend e2e tour
- tests/test_backend_tours.py::test_kanban_density_toggle drives
  start_tour("/odoo", "dms_kanban_density_tour", login="admin"). Five
  steps verify default density → click Compact → localStorage
  persistence + data-attr propagation → restore Comfortable → cleanup.
  Toolbar chrome renders even with zero records, so the tour is safe
  under OCA CI's --without-demo=all.

Signed-off-by: Don Kendall <dkendall@ledoweb.com>
dnplkndll added a commit that referenced this pull request May 26, 2026
…toolbar collapse

Fork-only iteration on top of #3. Five distinct themes folded into one
squashed commit since this PR exists for runboat preview / stakeholder
review, not upstream review.

CI artifact pipeline (test-failure observability)
- `Upload screenshots from JS tests` step captures /tmp/odoo_tests/<DB>
  on failure. Forward-port from the cookiecutter; companion template PR
  at ledoent/oca-addons-repo-template#1.
- `Upload odoo server log on failure` step captures
  /var/log/odoo/*.log + workspace + runner-temp.
- `workflow_dispatch:` so we can manually re-trigger when GitHub silently
  throttles fork-PR runs after a push burst.
- checklog-odoo.cfg ignores `Killing chrome descendants` WARN
  (benign browser_js cleanup; `OCA_ENABLE_CHECKLOG_ODOO=1` was treating
  it as a build error).

Hoot test suite (tests/test_hoot.py + tests/test_backend_tours.py)
- tests/test_hoot.py wires HttpCase.browser_js with
  `/web/tests?...&filter="@DMS"` — Hoot's `?filter=` defaults to fuzzy
  character-order matching; the double-quoted exact-substring form
  isolates @dms/... test paths from the bundled web-core suite.
- 9 Hoot test files run + pass under the wiring: dms_stat_bar,
  file_preview_pane, preview_handlers, preview_registry,
  file_kanban_buttons / _density / _mount / _list_renderer routing.
- `defineMailModels()` covers the mock-server base because dms depends on
  mail; `expect.errors(N) + verifyErrors(patterns)` replaces the
  array-of-objects form Hoot rejects.

OWL 19.0 readiness audit (per oca-review U/T pattern catalog)
- U7 (HIGH): delete dead static/src/js/views/file_kanban_controller.{xml,esm.js}.
  The XML defined dms.FileKanbanView.Buttons via t-inherit="web.KanbanView.Buttons"
  — the exact pattern that crashes at OWL render against 19.0's emptied
  template. Not wired anywhere; the view uses the self-contained
  dms.KanbanButtons template.
- U5 (MEDIUM): coerce boolean t-att-* attributes to explicit 'true'/'false'
  strings. Owl serializes truthy booleans as a presence flag (<div data-loading>),
  so CSS selectors `[data-loading="true"]` and tour selectors
  `[aria-pressed="true"]` silently never matched. Applied to data-loading
  on the stat bar and to aria-pressed on both density and preview toggles.
- U2 (style): convert 10 OWL 1 prototype-assignment idioms
  (`Foo.template = "x"; Foo.props = {...}`) to OWL 2 static class fields
  across 7 component classes. Cross-file `Renderer.template = "..."`
  assignments lifted into the renderer class declarations where they belong.

View toolbar collapse (overlap fix)
- Both renderers were stacking four absolute-positioned floaters in the
  top-right corner: preview-toggle pill (kanban + list), density toggle
  (twice — once in file_kanban.scss, once shifted to right:160px inside
  the kanban-split context). On list view this put the preview pill on
  top of the column-header row immediately under Odoo's control panel.
- Replaced with `.o_dms_view_toolbar` — one in-flow strip above the
  grid/list, populated with whatever view-level controls each renderer
  needs (density btn-group + preview pill on kanban; preview pill only
  on list, right-anchored via `__spacer { flex: 1 }`). Gone: 4
  absolute-position rules, 2 `right: calc(40% + 12px)` shifts, 1
  `display: none` density hack, all z-index battles.

Backend e2e tour
- tests/test_backend_tours.py::test_kanban_density_toggle drives
  start_tour("/odoo", "dms_kanban_density_tour", login="admin"). Five
  steps verify default density → click Compact → localStorage
  persistence + data-attr propagation → restore Comfortable → cleanup.
  Toolbar chrome renders even with zero records, so the tour is safe
  under OCA CI's --without-demo=all.

Signed-off-by: Don Kendall <dkendall@ledoweb.com>
dnplkndll added a commit that referenced this pull request May 26, 2026
…toolbar collapse

Fork-only iteration on top of #3. Five distinct themes folded into one
squashed commit since this PR exists for runboat preview / stakeholder
review, not upstream review.

CI artifact pipeline (test-failure observability)
- `Upload screenshots from JS tests` step captures /tmp/odoo_tests/<DB>
  on failure. Forward-port from the cookiecutter; companion template PR
  at ledoent/oca-addons-repo-template#1.
- `Upload odoo server log on failure` step captures
  /var/log/odoo/*.log + workspace + runner-temp.
- `workflow_dispatch:` so we can manually re-trigger when GitHub silently
  throttles fork-PR runs after a push burst.
- checklog-odoo.cfg ignores `Killing chrome descendants` WARN
  (benign browser_js cleanup; `OCA_ENABLE_CHECKLOG_ODOO=1` was treating
  it as a build error).

Hoot test suite (tests/test_hoot.py + tests/test_backend_tours.py)
- tests/test_hoot.py wires HttpCase.browser_js with
  `/web/tests?...&filter="@DMS"` — Hoot's `?filter=` defaults to fuzzy
  character-order matching; the double-quoted exact-substring form
  isolates @dms/... test paths from the bundled web-core suite.
- 9 Hoot test files run + pass under the wiring: dms_stat_bar,
  file_preview_pane, preview_handlers, preview_registry,
  file_kanban_buttons / _density / _mount / _list_renderer routing.
- `defineMailModels()` covers the mock-server base because dms depends on
  mail; `expect.errors(N) + verifyErrors(patterns)` replaces the
  array-of-objects form Hoot rejects.

OWL 19.0 readiness audit (per oca-review U/T pattern catalog)
- U7 (HIGH): delete dead static/src/js/views/file_kanban_controller.{xml,esm.js}.
  The XML defined dms.FileKanbanView.Buttons via t-inherit="web.KanbanView.Buttons"
  — the exact pattern that crashes at OWL render against 19.0's emptied
  template. Not wired anywhere; the view uses the self-contained
  dms.KanbanButtons template.
- U5 (MEDIUM): coerce boolean t-att-* attributes to explicit 'true'/'false'
  strings. Owl serializes truthy booleans as a presence flag (<div data-loading>),
  so CSS selectors `[data-loading="true"]` and tour selectors
  `[aria-pressed="true"]` silently never matched. Applied to data-loading
  on the stat bar and to aria-pressed on both density and preview toggles.
- U2 (style): convert 10 OWL 1 prototype-assignment idioms
  (`Foo.template = "x"; Foo.props = {...}`) to OWL 2 static class fields
  across 7 component classes. Cross-file `Renderer.template = "..."`
  assignments lifted into the renderer class declarations where they belong.

View toolbar collapse (overlap fix)
- Both renderers were stacking four absolute-positioned floaters in the
  top-right corner: preview-toggle pill (kanban + list), density toggle
  (twice — once in file_kanban.scss, once shifted to right:160px inside
  the kanban-split context). On list view this put the preview pill on
  top of the column-header row immediately under Odoo's control panel.
- Replaced with `.o_dms_view_toolbar` — one in-flow strip above the
  grid/list, populated with whatever view-level controls each renderer
  needs (density btn-group + preview pill on kanban; preview pill only
  on list, right-anchored via `__spacer { flex: 1 }`). Gone: 4
  absolute-position rules, 2 `right: calc(40% + 12px)` shifts, 1
  `display: none` density hack, all z-index battles.

Backend e2e tour
- tests/test_backend_tours.py::test_kanban_density_toggle drives
  start_tour("/odoo", "dms_kanban_density_tour", login="admin"). Five
  steps verify default density → click Compact → localStorage
  persistence + data-attr propagation → restore Comfortable → cleanup.
  Toolbar chrome renders even with zero records, so the tour is safe
  under OCA CI's --without-demo=all.

Signed-off-by: Don Kendall <dkendall@ledoweb.com>
dnplkndll added a commit that referenced this pull request May 26, 2026
…toolbar collapse

Fork-only iteration on top of #3. Five distinct themes folded into one
squashed commit since this PR exists for runboat preview / stakeholder
review, not upstream review.

CI artifact pipeline (test-failure observability)
- `Upload screenshots from JS tests` step captures /tmp/odoo_tests/<DB>
  on failure. Forward-port from the cookiecutter; companion template PR
  at ledoent/oca-addons-repo-template#1.
- `Upload odoo server log on failure` step captures
  /var/log/odoo/*.log + workspace + runner-temp.
- `workflow_dispatch:` so we can manually re-trigger when GitHub silently
  throttles fork-PR runs after a push burst.
- checklog-odoo.cfg ignores `Killing chrome descendants` WARN
  (benign browser_js cleanup; `OCA_ENABLE_CHECKLOG_ODOO=1` was treating
  it as a build error).

Hoot test suite (tests/test_hoot.py + tests/test_backend_tours.py)
- tests/test_hoot.py wires HttpCase.browser_js with
  `/web/tests?...&filter="@DMS"` — Hoot's `?filter=` defaults to fuzzy
  character-order matching; the double-quoted exact-substring form
  isolates @dms/... test paths from the bundled web-core suite.
- 9 Hoot test files run + pass under the wiring: dms_stat_bar,
  file_preview_pane, preview_handlers, preview_registry,
  file_kanban_buttons / _density / _mount / _list_renderer routing.
- `defineMailModels()` covers the mock-server base because dms depends on
  mail; `expect.errors(N) + verifyErrors(patterns)` replaces the
  array-of-objects form Hoot rejects.

OWL 19.0 readiness audit (per oca-review U/T pattern catalog)
- U7 (HIGH): delete dead static/src/js/views/file_kanban_controller.{xml,esm.js}.
  The XML defined dms.FileKanbanView.Buttons via t-inherit="web.KanbanView.Buttons"
  — the exact pattern that crashes at OWL render against 19.0's emptied
  template. Not wired anywhere; the view uses the self-contained
  dms.KanbanButtons template.
- U5 (MEDIUM): coerce boolean t-att-* attributes to explicit 'true'/'false'
  strings. Owl serializes truthy booleans as a presence flag (<div data-loading>),
  so CSS selectors `[data-loading="true"]` and tour selectors
  `[aria-pressed="true"]` silently never matched. Applied to data-loading
  on the stat bar and to aria-pressed on both density and preview toggles.
- U2 (style): convert 10 OWL 1 prototype-assignment idioms
  (`Foo.template = "x"; Foo.props = {...}`) to OWL 2 static class fields
  across 7 component classes. Cross-file `Renderer.template = "..."`
  assignments lifted into the renderer class declarations where they belong.

View toolbar collapse (overlap fix)
- Both renderers were stacking four absolute-positioned floaters in the
  top-right corner: preview-toggle pill (kanban + list), density toggle
  (twice — once in file_kanban.scss, once shifted to right:160px inside
  the kanban-split context). On list view this put the preview pill on
  top of the column-header row immediately under Odoo's control panel.
- Replaced with `.o_dms_view_toolbar` — one in-flow strip above the
  grid/list, populated with whatever view-level controls each renderer
  needs (density btn-group + preview pill on kanban; preview pill only
  on list, right-anchored via `__spacer { flex: 1 }`). Gone: 4
  absolute-position rules, 2 `right: calc(40% + 12px)` shifts, 1
  `display: none` density hack, all z-index battles.

Backend e2e tour
- tests/test_backend_tours.py::test_kanban_density_toggle drives
  start_tour("/odoo", "dms_kanban_density_tour", login="admin"). Five
  steps verify default density → click Compact → localStorage
  persistence + data-attr propagation → restore Comfortable → cleanup.
  Toolbar chrome renders even with zero records, so the tour is safe
  under OCA CI's --without-demo=all.

Signed-off-by: Don Kendall <dkendall@ledoweb.com>
@dnplkndll dnplkndll force-pushed the 19.0-imp-dms-ux branch 3 times, most recently from beb9548 to cbef9f5 Compare May 29, 2026 01:08
@dnplkndll dnplkndll force-pushed the 19.0-imp-dms-ux branch 3 times, most recently from 49b0325 to 4537378 Compare May 29, 2026 19:35
dnplkndll added 2 commits May 29, 2026 19:53
…view, form heroes, portal)

Backend (web) modernisation of the DMS file + directory views, layered on
the 19.0 migration:

- File kanban: comfortable/compact/list density tiers (persisted via a
  useStoredState hook), extension-accent file-type icons, directory-path
  subtitles, rounded author avatars, and inline quick-rename (double-click
  the name → Enter/Esc).
- Directory kanban: a three-tile dashboard stat bar (files, storage,
  new-today) with inline sparklines, backed by get_dashboard_stats.
- Side-pane preview: a split list/kanban + preview layout with a
  registry-based handler dispatch (image/pdf/text/markdown/video/audio +
  download fallback, with an extension→mimetype fallback for generic
  octet-stream). The pane has Preview / Details / Activity tabs — Details
  shows file metadata + tags, Activity mounts the standard chatter
  (messages, log notes, activities) since dms.file is a mail.thread. It
  refreshes in place when the on-screen record is renamed.
- Form heroes for dms.file / dms.directory and a portal document grid.
- Shared OWL hooks (useStoredState, useDmsPreviewState) for sibling reuse.

19.0 / OWL-forward conventions observed throughout: no owl event or ref
directives in ir.ui.view arch (interactive UI lives in registered
components / a dms_file_name view widget), t-out over t-esc, and
this.-prefixed handler expressions in OWL templates.
…iles

- Kanban now marks the file open in the side-pane preview with a primary
  rail + tint (o_dms_preview_selected_card), mirroring the list view's
  selected-row accent so the card↔pane mapping stays legible across
  densities. FileKanbanRecord.getRecordClasses() reads the reactive
  selectedId exposed on the dmsKanbanPreview env.
- Directory dashboard stat tiles are now drill-downs (the native Odoo
  dashboard interaction): "Files" opens the file list, "New today" opens
  files created since local midnight; "Storage" stays display-only.
  DmsStatBar gains an onTileClick prop + clickable affordance.
@dnplkndll dnplkndll force-pushed the 19.0-imp-dms-ux branch 2 times, most recently from d45c7a9 to 41843a7 Compare May 30, 2026 03:08
dnplkndll added 2 commits May 29, 2026 23:33
…icon header, tighter comfortable cards

- List view: remove the "Type" column (the Name column's extension-colored
  icon already conveys it; mimetype stays available via the optional column
  picker), reclaiming width.
- Preview Details tab: lead with the file's icon/thumbnail (icon_url) + name
  as a visual anchor, matching Odoo's info-panel convention.
- Comfortable kanban density: trim card padding/gap + thumb size so more
  cards fit without losing the comfortable feel (compact/list untouched).
dnplkndll added 2 commits May 30, 2026 07:30
.eml files (stored as text/plain) routed to the raw-text iframe, showing
RFC822 source. Add an EmlPreview handler that parses the top-level headers
into a From/To/Subject/Date card and renders the best body part (HTML
preferred, else plain text) in a sandboxed iframe; handles single +
multipart/{mixed,alternative,related} with base64 / quoted-printable. The
pane remaps the .eml extension to message/rfc822 so the handler wins.
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.