Skip to content

feat: scope file-list icons to .elp/.elpx and give legacy files the old logo#25

Merged
erseco merged 4 commits into
mainfrom
feat/scope-elp-icons-21
May 14, 2026
Merged

feat: scope file-list icons to .elp/.elpx and give legacy files the old logo#25
erseco merged 4 commits into
mainfrom
feat/scope-elp-icons-21

Conversation

@erseco
Copy link
Copy Markdown
Contributor

@erseco erseco commented May 14, 2026

Closes #21.

Two-part fix:

1. Stop leaking the eXeLearning thumbnail onto every .zip

Root cause was in PermissionService::isElpxFile() (lib/Service/PermissionService.php:36): it accepted application/zip and application/octet-stream as standalone MIME signals. That meant ElpxPreviewProvider::isAvailable() returned true for any plain ZIP in the user's Files, so the provider's fallback PNG (the eXeLearning doc outline) was rendered as the thumbnail — exactly what the issue reported.

Split Application::ALLOWED_MIME_TYPES into two named lists:

  • ALLOWED_MIME_TYPES (broad — still includes application/zip / application/octet-stream). Used by routing code that already knows the request is for an .elpx.
  • VENDOR_MIME_TYPES (narrow). Only application/vnd.exelearning.elpx, application/x-exelearning, and the new application/x-exelearning-legacy.

isElpxFile() now uses the narrow list for the MIME branch. The extension branch (.elpx / .elp) is unchanged, so files we know are ours are still recognised even when Nextcloud reports them as plain ZIP.

2. Visually distinguish .elp from .elpx

New MIME application/x-exelearning-legacy is registered for .elp via make up's mimetypemapping.json. A new mimetypealiases.json (also written by make up) maps the two vendor MIMEs to their respective icons:

  • application/vnd.exelearning.elpxexelearning (existing modern teal doc-with-brand-mark icon)
  • application/x-exelearning-legacyexelearning-legacy (new asset, see below)

application/zip stays out of the alias file on purpose — aliasing it was what caused the original symptom on installs that had once done so.

Legacy icon asset

img/filetypes/exelearning-legacy.svg is a 32x32 SVG that embeds (as base64 PNG) the pre-.elpx upstream eXeLearning logo — the green "eXe" circles over the dark globe-X you shared as reference. The doc-shape wrapper uses a cream fill (#fdf6e3) and an olive border (#7a6b3f) instead of the modern brand-blue, so even at 16 px the modern and legacy icons are immediately distinguishable from each other:

modern .elpx legacy .elp
brand-blue doc, teal "X" mark cream / olive doc, classic "eXe" logo

Preview provider

ElpxPreviewProvider::MIME_REGEX widens to also match application/x-exelearning-legacy so the preview generator still runs on legacy archives that happen to ship a screenshot.png. The bug-fix in isElpxFile() keeps it from running on unrelated ZIPs.

Tests

  • tests/Unit/AppInfo/ApplicationConstantsTest.php gains two new assertions that pin the bug down so it cannot regress silently:
    • VENDOR_MIME_TYPES must not contain application/zip or application/octet-stream.
    • It must contain both the modern (PRIMARY_MIME_TYPE) and legacy (LEGACY_MIME_TYPE) vendor MIMEs.

10/10 PHPUnit, 51/51 vitest, typecheck / lint / build / make cs-check all green.

Manual test plan

  • make down && make up. Upload a random .zip (non-eXeLearning). The Files list shows the default archive icon, no longer the eXeLearning glyph.
  • Upload tests/fixtures/un-contenido-…elpx (PR dev: seed .elp/.elpx fixtures into admin's Files on make up #23 fixture). It shows the modern teal eXeLearning icon (or its screenshot.png thumbnail if present).
  • Upload tests/fixtures/old_elp_modelocrea.elp. It shows the legacy cream/olive icon with the classic eXe logo — clearly different from the modern one.
  • Verify on NC 31, 32, 33 (CI matrix).

Follow-ups

  • The bundled img/filetypes/exelearning.svg (modern) still has the embedded PNG in its centre too. If we ever want to slim those files down, both could be reworked as pure SVG paths.
  • The README "Custom MIME types" section needs a small update to mention the new alias step on production installs — happy to do that as a follow-up doc PR if you prefer.

erseco added 2 commits May 14, 2026 18:50
…ld logo

Closes #21.

Two-part fix:

1. The eXeLearning icon was leaking onto every `.zip` in Nextcloud
   Files. Root cause: `PermissionService::isElpxFile()` accepted
   `application/zip` and `application/octet-stream` as standalone
   MIME signals, so `ElpxPreviewProvider::isAvailable()` returned
   `true` for any plain ZIP and the provider's fallback PNG (the
   eXeLearning doc outline) was rendered as the thumbnail.

   Split `Application::ALLOWED_MIME_TYPES` into two lists: a broad
   one (still includes zip/octet-stream — used by routing code that
   already knows the request is for an `.elpx`) and a new narrow
   `VENDOR_MIME_TYPES` (only `application/vnd.exelearning.elpx`,
   `application/x-exelearning`, and the new
   `application/x-exelearning-legacy`). `isElpxFile()` now uses the
   narrow list for MIME matching, while extension matching is
   unchanged — `.elpx` and `.elp` still win without a MIME check.

2. Modern `.elpx` and legacy `.elp` are now visually distinguishable.
   New MIME `application/x-exelearning-legacy` is registered for
   `.elp` via `make up`'s `mimetypemapping.json`, and a new
   `mimetypealiases.json` aliases the two vendor MIMEs to their
   respective icons:

     - `application/vnd.exelearning.elpx` → `exelearning`
       (the existing modern teal doc-with-brand-mark icon).
     - `application/x-exelearning-legacy` → `exelearning-legacy`
       (new asset: cream/olive doc shape with the pre-`.elpx`
       upstream logo — the green "eXe" circles over the dark
       globe-X — embedded as base64 PNG so the icon is a single
       self-contained file).

   `application/zip` stays out of the alias file on purpose — that
   was the original symptom.

`ElpxPreviewProvider::MIME_REGEX` also widens to cover
`x-exelearning-legacy` so the preview generator still runs on legacy
archives that happen to contain a `screenshot.png`.

Tests: extended `ApplicationConstantsTest` with two new assertions
that pin the bug down — `VENDOR_MIME_TYPES` must not contain
`application/zip` or `application/octet-stream`, and must contain
both the modern and legacy vendor MIMEs. 10/10 PHPUnit, 51/51 JS,
typecheck/lint/build all green.
…pen as eXeLearning" kebab on plain `.zip`

Two follow-ups after manual verification on the running stack:

1. Icon discovery: `maintenance:mimetype:update-js` only scans
   `core/img/filetypes/` (see the comment at the top of the
   generated `mimetypelist.js`). Apps' `img/filetypes/*.svg` are
   never picked up automatically, so even with the alias entries in
   `mimetypealiases.json` the modern and legacy icons fell back to
   the generic file glyph. `make up` now copies both
   `exelearning.svg` and `exelearning-legacy.svg` from the staged
   `custom_apps/exelearning/img/filetypes/` into
   `core/img/filetypes/` before regenerating the JS list.
   Production installs need the equivalent admin step — README
   updated with the new install snippet (and the legacy icon
   added to the existing alias example).

2. New kebab action `Open as eXeLearning` on plain `.zip` files
   (extension or `application/zip` mime), shown only when our
   default action is NOT already claiming the file. Lets users
   open a `.elpx` that has been re-saved with the wrong extension
   (or any zip they suspect is an eXeLearning project) without
   making the viewer the default for every archive in their
   account. Navigates to the existing `view?fileId=` route, which
   surfaces the legacy / invalid branches from #20 cleanly.

Verified in browser:
- `.zip` → gray archive icon, kebab includes "Open as eXeLearning".
- `.elp` → distinct legacy icon (the green eXe + dark globe X).
- `.elpx` → modern teal mark (unchanged).
@erseco
Copy link
Copy Markdown
Contributor Author

erseco commented May 14, 2026

Follow-up after testing on the running stack — pushed in c18dc6e.

Real cause of the icon not changing: maintenance:mimetype:update-js only scans core/img/filetypes/ (literally the comment at the top of core/js/mimetypelist.js). Aliases in config/mimetypealiases.json are accepted but if the SVG isn't in core/img/filetypes/ Nextcloud falls back to the generic file glyph. App-shipped filetype icons aren't auto-discovered.

The dev make up now copies both exelearning.svg and exelearning-legacy.svg into core/img/filetypes/ before running update-js. README updated with the equivalent install snippet for production admins.

Plus a new kebab action Open as eXeLearning on plain .zip files (the answer to "permite un abrir como.. nextcloud?" — yes, via registerFileAction from @nextcloud/files). Hidden when our default already claims the file.

Verified in the browser:

  • .zip → gray archive icon, kebab now has "Open as eXeLearning".
  • .elp → legacy logo (green eXe + dark globe X) clearly different from .elpx.
  • .elpx → modern teal mark (unchanged).

…re one icon

Manual testing surfaced two facts:

  1. The `.elp` icon distinguished cleanly in list-view but not in
     grid-view, because grid-view uses the preview provider's
     fallback PNG (the modern brand mark) for both file types. A full
     fix would have meant shipping a second fallback PNG, branching
     the provider, and managing two assets in sync — extra surface for
     a feature that is more "nice to have" than load-bearing now that
     issue #20 already gives the user a clear in-app migration path.

  2. The user just wants `.elp` to look like `.elpx` (and `.zip` to
     stop looking like an eXeLearning file).

So strip the legacy-MIME branch:

  - `Application::LEGACY_MIME_TYPE` removed; `VENDOR_MIME_TYPES` is
    now just the modern + the `application/x-exelearning` alias.
  - `ElpxPreviewProvider::MIME_REGEX` no longer matches the
    `-legacy` variant, and `getThumbnail` no longer branches on
    extension.
  - `make up` writes `.elp → application/vnd.exelearning.elpx` (same
    as `.elpx`) and a single-icon alias file. Only `exelearning.svg`
    is copied into `core/img/filetypes/`.
  - `img/filetypes/exelearning-legacy.svg` deleted.
  - README and constants test updated to match.

The two parts of issue #21 that *did* land stay in place:

  - The `isElpxFile()` tightening that stops `.zip` from inheriting
    the eXeLearning preview (the original bug).
  - The "Open as eXeLearning" kebab action on plain `.zip` files.

Verified in browser (grid + list): `.elp` and `.elpx` show the
modern teal mark, plain `.zip` shows the default archive icon.
51/51 vitest, 9/9 PHPUnit, typecheck/lint/build/cs-check green.
@erseco
Copy link
Copy Markdown
Contributor Author

erseco commented May 14, 2026

Simplified per request — pushed in 1851d37:

  • Dropped the application/x-exelearning-legacy MIME, the exelearning-legacy.svg asset, and the alias entry.
  • .elp and .elpx now both register as application/vnd.exelearning.elpx so they share the modern eXeLearning icon in both list and grid views.
  • Plain .zip keeps the default archive icon (the isElpxFile tightening that fixes the original bug stays).
  • "Open as eXeLearning" kebab on .zip stays.

Verified in browser: list and grid views both show the modern teal mark for .elp / .elpx and the gray archive glyph for .zip.

…s eXeLearning" works on `.zip`

Without this, opening a plain `.zip` via the new kebab action 404'd
in the controller (`Not an eXeLearning package`), which the page
renders as "No file selected. Back to Files".

The MIME / extension check stays in `PermissionService::isElpxFile()`
because the preview provider still relies on it (we do NOT want every
ZIP in Files to inherit our preview thumbnail). The viewer / editor
flow, on the other hand, is reached only when the user explicitly
clicks an action — at that point bouncing them with a generic 404 is
worse than letting the downstream validator surface a clear "not an
eXeLearning project" message.

Auth + ownership are still enforced by Nextcloud's `getById()`
resolving against the user's home folder, and the size limit gate
stays in place. So the only thing that changes is: the controller
hands a permitted-but-non-vendor file to the frontend, which then
runs `validatePackage()` from issue #20 and shows the legacy /
invalid branches as appropriate.
@erseco erseco merged commit d8e3943 into main May 14, 2026
8 checks passed
@erseco erseco deleted the feat/scope-elp-icons-21 branch May 14, 2026 22:51
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.

File icons: only .elp and .elpx should use the eXeLearning icon, not every .zip

1 participant