Skip to content

Show file extension icons for non-image files in the FileUpload widget - #1045

Open
AIC-BV wants to merge 3 commits into
wintercms:developfrom
AIC-BV:patch-20
Open

AIC-BV wants to merge 3 commits into
wintercms:developfrom
AIC-BV:patch-20

Conversation

@AIC-BV

@AIC-BV AIC-BV commented Jan 24, 2024 •

Copy link
Copy Markdown
Contributor

Replaces the original iframe approach in this PR with the direction discussed above: reuse the file extension icon from the MediaManager (#1061) in the FileUpload FormWidget.

Problem

In image mode, the FileUpload widget always renders <img src="thumbUrl">. For files that aren't images (e.g. a PDF when fileTypes allows it), getThumb() returns the file path itself, so the widget shows a broken image, both for existing files and right after upload.

Changes

  • Shared icon markup: moved the SVG from mediamanager/partials/_item-icon.php into modules/backend/partials/_file_icon.php, which takes an extension variable. The MediaManager now renders it via makePartial('~/modules/backend/partials/_file_icon.php'). The extension is now escaped, since FileUpload file names are user-supplied.
  • Shared icon styles: moved the .file-icon rules out of mediamanager.less into modules/backend/assets/less/controls/file-icon.less. Both mediamanager.less and fileupload.less import it, so the icon renders outside the [data-control="media-manager"] scope.
  • FileUpload:
    • New makeFileIcon($file) helper: returns the icon markup for files browsers can't display in an <img>, null otherwise.
    • _image_single.php and _image_multi.php render the icon instead of the <img> for those files.
    • onUpload() returns the icon markup as icon. fileupload.js swaps it in for the thumbnail on success.
    • Icon sizing for both image modes (100×100 single, 44×44 multi).

Notes

  • "Displayable" is a fixed list on the widget ($displayableImageExtensions: avif, bmp, gif, ico, jpeg, jpg, png, svg, webp), not FileDefinitions::get('imageExtensions'). That definition is configurable via cms.fileDefinitions, and some installs widen it to allow e.g. PDFs in image fields, which is exactly the case this PR fixes.
  • Only fileupload.css and mediamanager.css were recompiled.

Testing

Tested in a Winter 1.2 backend with an attachMany field (image-multi) and an attachOne field (image-single):

  • Uploading a PDF / DOCX shows the extension icon; uploading a PNG still shows its thumbnail.
  • After a reload, existing files render the same way.
  • MediaManager tile view renders its file icons as before.
Before After
Before: PDF and DOCX show an empty thumbnail After: PDF and DOCX show a file extension icon

🤖 Generated with Claude Code

@AIC-BV
AIC-BV marked this pull request as draft January 24, 2024 10:28
@AIC-BV

AIC-BV commented Jan 24, 2024

Copy link
Copy Markdown
Contributor Author

Well I guess its the same as https://github.com/wintercms/winter/pull/990/files 😆

@AIC-BV

AIC-BV commented Jan 24, 2024

Copy link
Copy Markdown
Contributor Author

Kind of worked around it using a partial

<?php
if ($model->drawing) {
    $src = $model->drawing->getPath();
?>
    <iframe src="<?= e($src) ?>#toolbar=0" width="50%" height="420px"></iframe>
<?php } ?>

@damsfx

damsfx commented Jan 24, 2024 •

Copy link
Copy Markdown
Contributor

It might be interesting to use a generic icon in SVG format, using a <text /> node to display the file extension.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" viewBox="0 0 250 250" version="1.1"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
    xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
    <path d="M62.5,0c-8.594,0 -15.625,7.031 -15.625,15.625l0,218.75c0,8.594 7.031,15.625 15.625,15.625l156.25,0c8.594,0 15.625,-7.031 15.625,-15.625l0,-171.875l-62.5,-62.5l-109.375,0Z" style="fill:#e2e5e7;fill-rule:nonzero;"/>
    <path d="M187.5,62.5l46.875,0l-62.5,-62.5l0,46.875c0,8.594 7.031,15.625 15.625,15.625Z" style="fill:#b0b7bd;fill-rule:nonzero;"/>
    <path d="M234.375,109.375l-46.875,-46.875l46.875,0l0,46.875Z" style="fill:#cad1d8;fill-rule:nonzero;"/>
    <path d="M195.313,210.938l-148.438,-0.001l0,7.813l148.438,0c4.296,0 7.812,-3.516 7.812,-7.813l-0,-7.812c-0,4.297 -3.516,7.813 -7.813,7.813Z" style="fill:#cad1d8;fill-rule:nonzero;"/>
    <!-- Colour label -->
    <path d="M203.125,203.125c0,4.297 -3.516,7.813 -7.813,7.813l-171.875,-0c-4.296,-0 -7.812,-3.516 -7.812,-7.813l-0,-78.125c-0,-4.297 3.516,-7.813 7.812,-7.813l171.875,0.001c4.297,-0.001 7.813,3.515 7.813,7.812l0,78.125Z" style="fill:#576d7e;fill-rule:nonzero;"/>
    <!-- Extension text node -->
    <text x="47.965px" y="188.125px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:61.512px;fill:#fff;">EXT</text>
</svg>

In this case EXT in text node may be replaced by the file extension.
The color can also be changed.

Some examples :

Render
Generic file-icon
PSD file-icon
PDF file-icon

@LukeTowers

Copy link
Copy Markdown
Member

I like that @damsfx, @AIC-BV are you interested in making that change?

@AIC-BV

AIC-BV commented Feb 21, 2024

Copy link
Copy Markdown
Contributor Author

That looks awesome and will work for 'all' file types.
However, I don't have time to do try this straight away

@AIC-BV

AIC-BV commented Feb 23, 2024

Copy link
Copy Markdown
Contributor Author

@damsfx too fast
#1061

@AIC-BV AIC-BV closed this Feb 23, 2024
@AIC-BV

AIC-BV commented Feb 23, 2024

Copy link
Copy Markdown
Contributor Author

Hmm or is that only in the mediafinder and not in form widget? Might need to extend it. Need to test it first.

@damsfx

damsfx commented Feb 23, 2024 •

Copy link
Copy Markdown
Contributor

Hmm or is that only in the mediafinder and not in form widget? Might need to extend it. Need to test it first.

@AIC-BV It's only related to the mediamanager! ⚠

Your use case is a little more specific ... I think you are using a fileupload field in image mode BUT allow it to accept other file types.
This is cool, because it allows you to have the same GUI to manage all file types.

If it became possible to carry over dynamic icon support to the fileupload formwidget, I think it wouldn't even be necessary to have two different modes of behavior (unless you wanted a more compact interface).

@AIC-BV AIC-BV reopened this Feb 23, 2024
@LukeTowers

Copy link
Copy Markdown
Member

@damsfx perhaps we should take the logic for generating the SVG and put it in a helper class so that the mediamanager and the fileupload field can use it?

@damsfx

damsfx commented Mar 5, 2024

Copy link
Copy Markdown
Contributor

@LukeTowers Yes, that would be perfect, but I'm not sure how to get started with that change.

@LukeTowers

Copy link
Copy Markdown
Member

@bennothommo do you have any thoughts on a desired API / direction to go in for the proposal of making it easier to reuse the work that was just added for generating icons based on file extension in the media manager?

@bennothommo

Copy link
Copy Markdown
Member

Sure, we could use the PHP SVG library. Would be very simple to have it generate text on the fly from what I can see.

@damsfx

damsfx commented Mar 6, 2024

Copy link
Copy Markdown
Contributor

@LukeTowers @bennothommo Isn't using a library to generate an SVG image (a simple string of characters) a bit over-dimmed?
What's needed is just displaying the image where it's needed, wouldn't a simple partial containing the image code be enough?

@AIC-BV

AIC-BV commented Mar 6, 2024

Copy link
Copy Markdown
Contributor Author

Yes the SVG is already made by @damsfx

@LukeTowers

Copy link
Copy Markdown
Member

@damsfx are you still interested in porting your work in #1061 to the FileUpload FormWidget?

@damsfx

damsfx commented Jul 31, 2024

Copy link
Copy Markdown
Contributor

@LukeTowers Yes, of course.
But I still don't know the best way to share a partial representing the structure of the SVG icon and the associated stylesheet between the mediamanager widget and the fileupload formwidget.

@LukeTowers

Copy link
Copy Markdown
Member

@bennothommo bennothommo added the enhancement PRs that implement a new feature or substantial change label Oct 11, 2024
AIC-BV and others added 2 commits September 25, 2026 15:29
Move the MediaManager's file extension SVG icon and its styles into a
shared backend partial and LESS file, and use them in the FileUpload
image modes for files browsers can't display in an <img>, instead of
rendering a broken thumbnail. Replaces the earlier PDF iframe approach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 32b6793c-68f3-4718-a542-fc8b276f121f

📥 Commits

Reviewing files that changed from the base of the PR and between 44e9d68 and 0f7b623.

📒 Files selected for processing (13)
  • modules/backend/assets/less/controls/file-icon.less
  • modules/backend/formwidgets/FileUpload.php
  • modules/backend/formwidgets/fileupload/assets/css/fileupload.css
  • modules/backend/formwidgets/fileupload/assets/js/fileupload.js
  • modules/backend/formwidgets/fileupload/assets/less/fileupload.imagemulti.less
  • modules/backend/formwidgets/fileupload/assets/less/fileupload.imagesingle.less
  • modules/backend/formwidgets/fileupload/assets/less/fileupload.less
  • modules/backend/formwidgets/fileupload/partials/_image_multi.php
  • modules/backend/formwidgets/fileupload/partials/_image_single.php
  • modules/backend/partials/_file_icon.php
  • modules/backend/widgets/mediamanager/assets/css/mediamanager.css
  • modules/backend/widgets/mediamanager/assets/less/mediamanager.less
  • modules/backend/widgets/mediamanager/partials/_item-icon.php

Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review.


Walkthrough

The change adds shared SVG file-icon rendering and styles. The media manager and file-upload previews use the shared icon for non-image files. File-upload responses include an icon value, and preview code falls back to thumbnails when no icon is provided.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~12 minutes

Merge Risk: ⚪ Minimal · up to 0f7b6

The reviewed icon and upload-preview changes show no concrete failure or specific merge blocker.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 0f7b6

The new icon is escaped before display, and the upload’s existing validation and attachment flow is unchanged. A failure while rendering an icon could nevertheless leave a saved file behind while reporting that the upload failed.

Retained concerns

  • Low · reliability · inferred: If icon rendering fails after a non-image file is saved and attached, the handler returns an error without visible rollback or a file ID for client cleanup. A repeated upload could create another attachment. This is a conditional failure-containment concern, not an observed runtime failure.
Security review details

Security Blast Radius

  • inferred — The new post-write rendering path applies to FileUpload widgets accepting extensions outside the displayable-image list. Any resulting stranded files would affect their backing file storage or relations; cross-tenant reachability is not established.

Security Findings and Attack Paths

  • inferred — No markup-injection path is established through the new icon field: the client inserts server-rendered markup, but the extension interpolated into that markup is escaped. No runtime exploit of the post-write failure path is established.

Trust Boundaries and Controls

  • observed — The upload method retains file validity, size, configured extension, and optional MIME checks before saving. The inspected method does not establish the external route or permission policy; its public visibility and upload flow predate the icon response.

Resilience and Maintainability Implications

  • inferred — Returning an error after attachment without returning its ID weakens failure containment for an affected upload; rollback or deduplication outside the inspected handler remains unknown.

Hardening Proposals

  • proposed — Ensure icon generation cannot turn a completed write into a failed upload response, or pair post-write rendering failures with explicit compensation or idempotent recovery.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 6 files. (7 skipped: 7 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding file extension icons for non-image files in the FileUpload widget.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AIC-BV AIC-BV changed the title [add] support for displaying PDF file Show file extension icons for non-image files in the FileUpload widget Sep 25, 2026
@AIC-BV
AIC-BV marked this pull request as ready for review September 25, 2026 14:01
@AIC-BV

AIC-BV commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

See 1st message in conversation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement PRs that implement a new feature or substantial change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants