Skip to content

[19.0][MIG+IMP] dms: Migration to 19.0 with kanban/form/portal UI enhancements#1

Open
dnplkndll wants to merge 195 commits into
19.0from
19.0-imp-dms
Open

[19.0][MIG+IMP] dms: Migration to 19.0 with kanban/form/portal UI enhancements#1
dnplkndll wants to merge 195 commits into
19.0from
19.0-imp-dms

Conversation

@dnplkndll
Copy link
Copy Markdown

@dnplkndll dnplkndll commented May 16, 2026

What changed

Migrates the dms module from 18.0 → 19.0 and layers a refreshed visual design on top. Targets ledoent's 19.0 fork branch so we can pilot the redesigned DMS experience on Runboat before any upstream OCA contribution.

The visual direction is "editorial / data-density / archival": every kanban card, form hero, and portal tile carries a single --dms-accent CSS variable driven by data attributes on the markup. File cards key off the extension (data-ext); directory cards key off a hash of the directory name (data-initial). The same palette tints the card spine, the accent tile, and the metadata chips, so each identity reads as one visual unit across surfaces.

Migration

  • [19.0][MIG] dms: Migration to 19.0 — base port of the OCA 18.0 module to Odoo 19.0 (manifest version, deprecated API replacements, removal of dropped fields, view syntax updates).

UI overhaul

Backend kanban — directory cards

Previously: a generic folder.svg icon + name + tags + a <i class="fa fa-folder" /><span>&nbsp;</span>5Directories footer that rendered the count and label without spacing because the &nbsp; was a literal markup token.

Now: a 56px tinted tile, a clean name + tag row, a relative date, and a proper chip row showing subdirectory count, file count, human size, and the last-writer initials chip. The whole card uses the unified .o_dms_card chrome with an accent spine and a 1px hover lift.

Directories kanban — before
Directories kanban — after

Backend kanban — file cards

File cards already had chips in the prior iteration. This pass:

  • Adopts the same .o_dms_card chrome (accent spine + hover lift) so directory and file kanbans feel like one component family.
  • Replaces the fixed primary tint on the extension chip with var(--dms-accent) driven by data-ext, so each file family (docs / code / images / media / archives …) reads as its own color.
  • Image-mimetype previews use .o_dms_card_tile_preview to drop the tinted treatment so photos read as photos.
  • Strips the leading dot on the extension chip (PDF, not .PDF).

Files kanban — after

Form-view hero

The directory and file form heros share the same tinted 28px hero icon (.o_dms_hero_icon). Directory hero is pinned to the "paper / amber" accent that the directory kanban defaults to; file hero stays neutral gray. Chip row collapses extension, size, lock state, and root state into a single line under the title.

Directory form hero — before
Directory form hero — after

Portal /my/dms

Portal cards consume the same shared accent system. Directory cards get the amber stripe; file cards get the per-extension stripe. Both cards lift on hover and the badge gets the same 135° highlight gradient the backend kanban tile uses.

Portal — directory grid
Portal — mixed view (directories + file)

Architecture

  • _dms_tokens.scss (NEW) — single source of truth for the palette, the per-extension accents, and the bucket-hash helpers. It's prepended into both web.assets_backend and web.assets_frontend in __manifest__.py so the maps and mixins are visible to every consumer SCSS file in the bundle. Odoo's asset bundler rejects relative @import for security, so the prepend-via-manifest pattern is the load mechanism.
  • kanban.scss — unified .o_dms_card chrome (spine + hover lift + tinted tile) shared between directory and file cards. The 26-letter $dms-initial-palette is gone; the hash-bucket helper from the partial generates the same selectors from an 8-entry map.
  • portal.scss — drops its inline 26-entry extension palette and reuses the partial's dms-extension-vars($selector) mixin. Card hover and badge gradient now match the backend.

Verification

  • OCA CI green on this PR (pre-commit, test-with-Odoo, test-with-OCB, unreleased-deps).
  • Runboat builds the preview cleanly for both 19.0-imp-dms and pr1.
  • Backend directory kanban + file kanban render with the new accent system on the runboat preview.
  • Backend form hero icon tints correctly (amber for directories, neutral for files).
  • Portal /my/dms renders directories + files with per-extension stripes and hover lift.
  • All existing portal Playwright tours still pass (selectors like .tr_dms_directory_link are preserved).

Notes

  • The 195 commits on this branch include the full history from 9.0 → 19.0 because 19.0-imp-dms was seeded with the upstream history before the migration commits. Squash-merging will collapse the chain to a single commit on 19.0. The actual new work for the 19.0 series is the 13 commits prefixed [19.0][MIG|IMP|REF|DOC|FIX|CI] at the tip.
  • The base 19.0 branch on this fork is currently just OCA repo scaffolding (copier files, no modules); this PR introduces dms/ as the first 19.0 module.

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
OCA-git-bot and others added 14 commits May 12, 2026 15:52
Currently translated at 89.6% (322 of 359 strings)

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/es/
The _check_access_dms_record method uses self.search(domain) to verify
write permissions. However, search() applies active_test=True by default,
which excludes archived records (active=False).

This means when a user tries to unarchive a file via toggle_active(),
the write permission check cannot find the archived record in the search
results, causing an AccessError even when the user has full write
permissions through DMS access groups.

Fix: add active_test=False context to include archived records in the
permission check search.
- Bump manifest version to 19.0.1.0.0.
- Adopt 19.0 group privilege model: replace res.groups.category_id with
  privilege_id and the new res.groups.privilege record.
- Simplify to a 2-tier security structure (user / manager); group_dms_user
  now implies base.group_user directly. Removed group_dms_viewer.
- res.users.groups_id → group_ids (demo XML + tests).
- res.groups.users → user_ids in access_groups._compute_users dependency.
- auto_join=True/False → bypass_search_access=True/False on 10 fields
  across access_groups, directory, dms_file, storage.
- _sql_constraints → models.Constraint in dms_category, access_groups, tag.
- odoo.osv.expression → odoo.fields.Domain (all imports + AND/OR/Domain.TRUE
  /FALSE/NEGATIVE_OPERATORS aliases at module top).
- read_group → _read_group with the new aggregate-tuple return format in
  dms_security_mixin._get_domain_by_inheritance.
- @http.route(type='json') → type='jsonrpc' on the onboarding controller.
- Translation modernisation per pylint_odoo 19.0 (W8161 prefer-env-translation
  + W8301 translation-not-lazy): replace 'from odoo import _' with
  self.env._() and lazy positional/keyword formatting throughout controllers
  and models.
- DMS access filter restoration: override _search() on dms.security.mixin
  to AND the access-group + inheritance domain into all non-su searches.

  19.0 changed ir.rule._compute_domain() to use Domain.optimize (basic
  level) instead of optimize_full, which means 'search=' methods on
  computed-Boolean fields like permission_read are silently bypassed when
  rule domain_force is evaluated. Without this override the
  [('permission_read', '=', user.id)] global rules no-op and every user
  sees every record.
- _search_starred now handles both '=' and 'in' operators (19.0's basic
  optimizer normalises ('starred','=',True) to ('starred','in',{True}),
  which the old single-operator branch did not recognise).
- Demo-data test guards: tests referencing dms.file_*_demo /
  base.partner_demo_portal now skipTest() when the xmlid isn't found,
  since 19.0 defaults to with_demo=False on CI.
- index=True → index='btree' on dms_file.attachment_id.
- _get_ref_selection(): pylint: disable=no-search-all (intentional,
  enumerates all registered models for the reference selection).
- View / JS cleanups (adopted from OCA#474 by @HaithamSaqr): removed
  deprecated <group expand='0' string='Group By'> attributes; removed
  unsupported target='inline' on ir.actions.act_window; fixed OWL XPath
  '//div' → '.' in empty KanbanView/ListView Buttons templates; replaced
  store.Attachment with store['ir.attachment'] in attachment JS models.
Replace the auto res.users avatar in the kanban-card footer with a
colour-coded initial chip, and surface human_size / extension / lock
state as Bootstrap-style chips. Adds a new dms/static/src/scss/kanban.scss
asset registered under web.assets_backend.
For records whose mimetype starts with image/, render a square thumbnail
from /web/image/dms.file/<id>/image_128 instead of the generic file-type
SVG icon. The image_1920 compute on dms.file already populates these for
supported PIL mimetypes (+ image/svg+xml).
Replace the stacked Locked/Locked/Archived ribbon trio with two
distinct ribbons (Locked-by-me + Archived) and fold the filename / path
row and a new metadata pill row (extension, human_size, mimetype, lock
state, updated-at) into a single oe_title hero block. The avatar image
stays unchanged for image previews.
Delete the Meta Information + Access Information notebook pages and fold
their fields into the existing settings group as two stacks: a Location
column (directory, storage, category, tags) and an Activity column
(created/updated chips, permission_write and permission_unlink toggles).
The Technical Information page remains gated behind debug.
Replace the bare /my/dms portal table with a responsive Bootstrap card
grid (col-12 / col-md-6 / col-lg-4 / col-xl-3). Directories get an orange
folder badge; files get a monospaced uppercase extension badge plus a
per-mimetype left-border accent (pdf=magenta, docs=blue, sheets=green,
etc.). Hover lifts the card with a soft shadow.
Enable hierarchize=1 on the directory_id search panel field so the
directory tree renders as a proper parent-child outline, and switch both
directory_id and category_id to select=multi so users can chip-style
filter on multiple directories/categories at once. SCSS tightens label
density and dims counters with tabular-nums.
Replace the fa-cloud-upload fa-10x icon with an animated overlay:
marching dashed border, a bobbing upload icon, a Drop files to upload
CTA and a release-to-add hint. Pure CSS keyframes, no extra JS.
Apply the same hero/inline-metadata treatment to the dms.directory form
as to dms.file: hero block with folder glyph, Root pill, human_size and
count_elements chips, and a starred toggle. Fold the Meta Information +
Access Information notebook pages into a unified Location + Activity
group with 4 boolean_toggle permission pills (read/create/write/unlink).
The inheriting view_dms_directory_new_form xpath is rebased onto the
remaining settings group.
@dnplkndll dnplkndll closed this May 16, 2026
@dnplkndll dnplkndll reopened this May 16, 2026
@dnplkndll dnplkndll closed this May 16, 2026
@dnplkndll dnplkndll reopened this May 16, 2026
dnplkndll added 9 commits May 15, 2026 22:02
Hoists the per-extension and per-initial color systems into a single
`_dms_tokens.scss` partial. The partial exposes:

- `$dms-bucket-palette` — eight semantic buckets used for anything that
  needs a stable per-identity tint
- `$dms-extension-accents` — file-family palette consumed by both
  backend kanban cards and portal cards
- `dms-bucket-index($key)` / `dms-bucket-color($key)` — pure Sass hash
  helpers, no JS hook required
- `dms-extension-vars($selector)` / `dms-initial-vars($selector)` —
  mixins that emit `--dms-accent` keyed off `data-ext` / `data-initial`

No behaviour change yet — the partial is not @import-ed by anything in
this commit. Subsequent commits replace the inline palettes in
kanban.scss and portal.scss with calls into this partial.
…gn file kanban + form heros

Introduces a shared `.o_dms_card` chrome (accent spine, hover lift,
56px tinted tile) and applies it across the directory kanban, the file
kanban, and the directory/file form heros so the whole module reads as
one visual system.

Specifically:

- **Directory kanban**: rebuilt from a `row g-0` thumbnail+text layout
  into a `flex` row with a 56px `.o_dms_card_tile` carrying the folder
  icon over a `--dms-accent` gradient. Tint is derived from a hash of
  the directory name (`data-initial`), so distinct directories read as
  distinct without any per-record color picking.
  Metadata gets surfaced as proper chips — directory count, file count,
  human size, and the last-writer initials chip — replacing the prior
  text-with-icon footer (which also rendered "5Directories" without
  spacing because the &amp;nbsp; was a literal token).
- **File kanban**: same wrapper class so spine + hover lift apply.
  `data-ext` on the card drives the per-extension `--dms-accent`; the
  extension chip then reads off `var(--dms-accent)` instead of a fixed
  primary. Image-mimetype previews use `.o_dms_card_tile_preview` to
  drop the chrome treatment so photos read as photos. The extension
  chip strips the leading dot so it shows `PDF` not `.PDF`.
- **Form heros**: `.o_dms_dir_hero_icon` is gone — the hero glyph is
  now a tinted 28px square (`.o_dms_hero_icon`) consuming the same
  `--dms-accent` variable. Directory hero pins the variable to amber
  (matching the kanban default for directories), file hero stays
  neutral gray (per-extension tint isn't available statically in form
  arch and isn't worth a dedicated widget).
- The kanban renderer's drop-zone background gets a soft radial wash
  so the marching-dash border doesn't feel detached when it appears.

Replaces the manually-enumerated 26-letter `$dms-initial-palette` with
the hash-bucket mixin from `_dms_tokens.scss`. No behaviour change for
existing initial chips — same eight buckets, same letter→bucket
mapping — but the source of truth is now a single 8-entry map.
Replaces the inline 26-entry `$dms-portal-accents` map with a single
call into the shared `_dms_tokens.scss` partial. Same per-extension
palette, same selectors generated — but the source of truth is now
shared with the backend file kanban, so adding a new extension only
requires touching one map.

Tightens the visual treatment to match the backend cards:

- The badge gets the same 135° highlight gradient the kanban tile uses
  (`linear-gradient(...) , var(--dms-accent)`), so the two surfaces feel
  like the same component at different scales
- Card hover now lifts (`translateY(-1px)`) + softens the border toward
  the accent, matching the backend `.o_dms_card` hover
- Card body picks up a faint top-edge gradient
  (`color-mix(... 6%, white)`) so the accent stripe doesn't feel
  detached from the card
- Removes the now-redundant `.o_dms_portal_badge_dir` class — the
  parent card already sets `--dms-accent: #f08c00` via
  `.o_dms_portal_card_dir`, so the badge inherits it via the variable
  cascade
Documents the accent system, card chrome, metadata chips, hero block,
portal grid, searchpanel typography, and drop-zone treatment introduced
in the 19.0 series. Points readers at `_dms_tokens.scss` as the single
source of truth for the palette + bucket-hash helpers.
…import

The previous commit chain introduced `_dms_tokens.scss` with shared
mixins/maps and tried to load it from `kanban.scss` and `portal.scss`
via `@import "./dms_tokens";`. That fails under Odoo 19's SCSS bundler
— libsass is invoked over a concatenated string of all bundle SCSS
files and is not given an include-path that resolves relative imports
inside an addon's static directory, so the @import returns nothing and
every consuming `@include` errors with "no mixin named ...".

Fix is two-fold:

1. List `_dms_tokens.scss` at the top of both `web.assets_backend` and
   `web.assets_frontend` in `__manifest__.py`. Odoo concatenates the
   listed SCSS files in order before compiling, so the partial's maps
   and mixin definitions are visible to every file that follows it in
   the bundle.
2. Drop the now-redundant `@import "./dms_tokens";` line from
   `kanban.scss` and `portal.scss`. The header comment in each file
   now points at the manifest as the load mechanism.

Regenerated `README.rst` and `static/description/index.html` from the
already-merged `readme/USAGE.md` UI section (oca-gen-addon-readme).
Re-flows long-attribute tags in the directory + file kanban XML
templates and breaks the `dms-initial-vars` letter list onto one entry
per line in `_dms_tokens.scss`. No semantic change — pure formatting
required by the OCA prettier-with-plugin-xml configuration.

(Force-pushing the earlier commits with the formatting baked in is not
authorized for this PR branch; the prettier hook produces an additive
diff that is safe to land as its own commit.)
Odoo's asset bundler scans SCSS source for `@import "..."` and emits a
WARNING-level log "Local import './dms_tokens' is forbidden for
security reasons" whenever it finds the pattern — even inside a
comment. With OCA_ENABLE_CHECKLOG_ODOO=1 those warnings fail the test
job ("Errors detected in log").

The actual `@import` directives were already removed in the previous
fix commit, but each SCSS header still mentioned the string by name
while explaining the manifest-based load mechanism. Rewords the
comments so the substring no longer appears anywhere in the bundle
inputs.
Three regressions identified during code review of the migration commit
([19.0][MIG] dms: Migration to 19.0). All restore behaviour that was
present in the 18.0 baseline and silently dropped during the port.

1. **File kanban view loses its Upload/Scan buttons.** The 18.0
   `dms.KanbanButtons` template was deleted and
   `buttonTemplate: "dms.KanbanButtons"` was removed from
   `FileKanbanView`. A replacement template
   (`dms.FileKanbanView.Buttons`) was added in
   `file_kanban_controller.xml` but never wired into the view config,
   and the template's `t-ref` + `t-on-change` names did not match the
   `createFileUploadExtension()` API
   (`fileInput` / `onChangeFileInput` / `uploadDocument`). Fix:
   - Realign `dms.FileKanbanView.Buttons` to the extension's actual
     ref/handler names, and restore the responsive mobile-Scan +
     desktop-Upload pair.
   - Add `buttonTemplate: "dms.FileKanbanView.Buttons"` to
     `FileKanbanView` so the kanban toolbar actually receives the
     buttons.

2. **`filter_domain` silently dropped from category + tag search.**
   The 18.0 views explicitly set:
   - `dms.category` → `['|', ('name', 'ilike', self), ('parent_id', 'child_of', raw_value)]`
     (searching a parent category surfaces descendants — important UX
     for hierarchical categories like `Internal / Human Resource`).
   - `dms.tag` → `[('name', 'ilike', self)]` (case-insensitive
     contains-match; locks in semantics regardless of Odoo's evolving
     default field-search behaviour).
   The migration replaced both with bare `<field name="name" />`,
   changing search semantics. Restored both explicitly with a comment
   noting why.

3. **List-renderer xpath `.` is correct but unobvious.** Odoo 19's
   `web.ListView.Buttons` is a flat list of `<button>` siblings — the
   18.0 `o_list_buttons` wrapper div is gone, so the prior class-scoped
   xpath has no anchor. Bare `.` (the implicit root) is the right
   answer in 19, but it reads as fragile. Added a comment block above
   the three `<xpath>` blocks explaining the Odoo-19-side change and
   why three separate one-node patches are preferable to a single
   multi-node patch (sibling-addon merge friendliness).
Adds a token-by-token comparison table to USAGE.md so reviewers can
see exactly which Odoo 19 `$o-*` and Bootstrap variables every
`--dms-*` value falls back to, plus the rationale for places where we
deliberately diverge (smaller 56px tile, smaller 11px chip font,
hover-lift not present in Odoo core).

Authoritative reference for the comparison is upstream
`odoo/odoo@19.0:addons/web/static/src/scss/primary_variables.scss`
and `addons/web/static/src/views/kanban/kanban.variables.scss`. Odoo
does not publish a formal design-system document for 19.0, so we
inline the relevant tokens here for review convenience.

README.rst + the static description page are regenerated from
readme/*.md by oca-gen-addon-readme.
dnplkndll added a commit to ledoent/odoo-design-system that referenced this pull request May 16, 2026
A full Before / After / Roadmap walk through every dms surface we
touched in ledoent/dms#1, packaged so a designer can import it into
the design.hz.ledoweb.com Penpot instance without rebuilding from
blank.

## What's in the bundle

- `docs/case-studies/dms/README.md` — the master document. Reads as a
  design-review brief: aesthetic direction, surface-by-surface before/
  after with embedded GCS-hosted screenshots, "why" + "next" for each,
  a 10-item ranked roadmap, and the token contract that ties the
  whole thing back to the design system.
- `docs/case-studies/dms/surfaces.json` — structured frame manifest.
  One entry per Penpot page: label, screenshot URL, annotation text,
  forward-move list. The bootstrap script consumes this.
- `docs/case-studies/dms/roadmap.json` — the 10-item roadmap as data
  (rank, surface, impact, effort, summary, dependency). Same content
  as the markdown table but consumable by the bootstrap script for
  the Roadmap page card stack.
- `docs/case-studies/dms/scripts/bootstrap-penpot.mjs` — Node script
  that hits Penpot's REST API to create the project + file + one
  page per surface from `surfaces.json`, plus a Roadmap page from
  `roadmap.json`. Designer takes over from the skeleton.
- `docs/case-studies/dms/scripts/README.md` — how to get a Penpot
  access token, run the script, and what it doesn't try to do.

## Why semi-automated for now

`infra/deployments/penpot/README.md` calls out that the Penpot MCP
server isn't wired into Claude yet. Until it is, the bootstrap script
provides the REST-API floor: it creates the project skeleton and
surfaces the screenshot URLs the designer drags onto each page. When
MCP lands this script gets replaced by a declarative translator that
is idempotent and layout-aware.

## Why a case study

This is also the first artifact in a `docs/case-studies/` series.
The same shape (README + surfaces.json + roadmap.json + bootstrap)
should work for every OCA module we migrate to a coherent visual
layer — establish the pattern here, reuse for the next module.
dnplkndll added a commit to ledoent/odoo-design-system that referenced this pull request May 16, 2026
* docs: ship the DMS migration as a design case study (penpot-ready)

A full Before / After / Roadmap walk through every dms surface we
touched in ledoent/dms#1, packaged so a designer can import it into
the design.hz.ledoweb.com Penpot instance without rebuilding from
blank.

## What's in the bundle

- `docs/case-studies/dms/README.md` — the master document. Reads as a
  design-review brief: aesthetic direction, surface-by-surface before/
  after with embedded GCS-hosted screenshots, "why" + "next" for each,
  a 10-item ranked roadmap, and the token contract that ties the
  whole thing back to the design system.
- `docs/case-studies/dms/surfaces.json` — structured frame manifest.
  One entry per Penpot page: label, screenshot URL, annotation text,
  forward-move list. The bootstrap script consumes this.
- `docs/case-studies/dms/roadmap.json` — the 10-item roadmap as data
  (rank, surface, impact, effort, summary, dependency). Same content
  as the markdown table but consumable by the bootstrap script for
  the Roadmap page card stack.
- `docs/case-studies/dms/scripts/bootstrap-penpot.mjs` — Node script
  that hits Penpot's REST API to create the project + file + one
  page per surface from `surfaces.json`, plus a Roadmap page from
  `roadmap.json`. Designer takes over from the skeleton.
- `docs/case-studies/dms/scripts/README.md` — how to get a Penpot
  access token, run the script, and what it doesn't try to do.

## Why semi-automated for now

`infra/deployments/penpot/README.md` calls out that the Penpot MCP
server isn't wired into Claude yet. Until it is, the bootstrap script
provides the REST-API floor: it creates the project skeleton and
surfaces the screenshot URLs the designer drags onto each page. When
MCP lands this script gets replaced by a declarative translator that
is idempotent and layout-aware.

## Why a case study

This is also the first artifact in a `docs/case-studies/` series.
The same shape (README + surfaces.json + roadmap.json + bootstrap)
should work for every OCA module we migrate to a coherent visual
layer — establish the pattern here, reuse for the next module.

* docs(dms): add idempotent Penpot service-account bootstrap script

Registers hello@ledoweb.com on design.hz.ledoweb.com via the REST API,
activates the profile via direct DB UPDATE (SMTP unconfigured on the
cluster so verification email goes nowhere), mints a long-lived access
token, and writes credentials to .env at the repo root. Re-runs reuse
the existing password to refresh the token without locking out the
account.

Unblocks the Penpot MCP server wiring — the access token this writes is
what design.hz.ledoweb.com/mcp authenticates against.
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.