Files
bin/espoImage-button-in-signature-editor.md
mkt cebe829dcd Add README, customization snapshot, and snapshot/restore tooling
Provisioning now restores all GUI customizations on reset+reprovision:

- create_pod_espocrm.sh: deploy the version-controlled espocrm-custom/ tree
  (CTag entity, layouts, i18n, clientDefs, custom views, custom CSS) into the
  pod, then chown www-data and rebuild. Replaces the earlier inline CSS-only
  step. Adds a live-phase cache rebuild so customizations and the client
  cacheTimestamp are refreshed on every run.
- espocrm-custom/: snapshot of custom/ and client/custom/ (source of truth).
- snapshot_espocrm_custom.sh: refresh the snapshot from a running pod.
- readme.md: usage, first-time host setup, image-update and reset workflows.
- Include the task/instruction notes and plan.md for reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:51:02 +02:00

6.0 KiB

Goal

Restore the image button (espoImage) in the EspoCRM signature editor toolbar. The signature field uses the core view views/preferences/fields/signature, whose setupToolbar() overrides the toolbar to [["style",[…]],["color",["color"]],["height",["height"]],["table",["espoLink"]],["misc",[<codeview>,"fullscreen"]]] — i.e. it drops the espoImage button that the generic wysiwyg field has. We want the image button back only for the signature field, without changing anything else.

Do not touch other fields, ACLs, the generic wysiwyg editor (email body / templates already have the image button), or any data.

Environment

  • EspoCRM 9.3.8 (Apache variant) runs as a rootless Podman pod espocrm_pod on this server. Web container is expected to be espocrm_ctr (confirm with podman ps).
  • App root inside the web container: /var/www/html, runs as user www-data.
  • Customizations live on the persisted /var/www/html bind-mount, same locations as the S47 task:
    • Backend metadata: /var/www/html/custom/Espo/Custom/Resources/metadata/…
    • Frontend custom views: /var/www/html/client/custom/src/… (referenced with the custom: prefix).

Mechanism (from 9.3.8 source — confirm against this instance before relying on it)

  • The signature field view client/src/views/preferences/fields/signature.js extends the wysiwyg field and overrides setupToolbar(). Its this.toolbar contains a group ['table', ['espoLink']] — the link button but not espoImage.
  • The generic wysiwyg field client/src/views/fields/wysiwyg.js registers the upload callback in enableWysiwygMode(): onImageUploaduploadInlineAttachment(file) → creates an Attachment (role: 'Inline Attachment') and inserts <img src="?entryPoint=attachment&id=…">. This callback is present regardless of the toolbar, so as soon as the espoImage button is in the toolbar, its upload path produces an attachment.
  • espoImage is a registered summernote plugin (client/src/helpers/misc/summernote-custom.js): its button invokes espoImage.show → modal views/wysiwyg/modals/insert-image, whose upload path runs through insertImagesOrCallback → the onImageUpload callback above. (The modal's URL path inserts a plain remote <img> instead — not what we want.)

Verify before relying on it:

podman exec espocrm_ctr sh -lc "grep -n 'setupToolbar\|espoLink\|espoImage\|table' /var/www/html/client/src/views/preferences/fields/signature.js"
podman exec espocrm_ctr sh -lc "grep -n 'onImageUpload\|uploadInlineAttachment\|entryPoint=attachment' /var/www/html/client/src/views/fields/wysiwyg.js"

You should see the reduced toolbar with ['table', ['espoLink']] and the onImageUpload→attachment path. If the structure differs in this build, adjust the toolbar-patch below to match the real group names.

Steps

  1. Confirm container. podman ps → identify the web container (expected espocrm_ctr).

  2. Create the custom signature field view on the persisted mount:

    /var/www/html/client/custom/src/views/preferences/fields/signature.js

    define('custom:views/preferences/fields/signature',
    ['views/preferences/fields/signature'], (SignatureFieldView) => {
    
        return class extends SignatureFieldView {
    
            setupToolbar() {
                // Build the reduced signature toolbar first …
                super.setupToolbar();
    
                // … then re-add the image button next to the link button.
                this.toolbar = (this.toolbar || []).map(group => {
                    if (Array.isArray(group) && group[0] === 'table') {
                        const buttons = group[1] || [];
    
                        if (!buttons.includes('espoImage')) {
                            return ['table', [...buttons, 'espoImage']];
                        }
                    }
    
                    return group;
                });
            }
        };
    });
    

    Create the directory if needed:

    podman exec espocrm_ctr sh -lc "mkdir -p /var/www/html/client/custom/src/views/preferences/fields"
    

    If the grep in the verify step shows no group whose first element is 'table', fall back to simply appending a new group instead of the .map(...): this.toolbar.push(['insert', ['espoImage']]); (place it before the final ['misc', …] group if you want it left of code-view/fullscreen).

  3. Point the signature field at the custom view via an entityDefs override. Merge into (create if absent):

    /var/www/html/custom/Espo/Custom/Resources/metadata/entityDefs/Preferences.json

    {
        "fields": {
            "signature": {
                "view": "custom:views/preferences/fields/signature"
            }
        }
    }
    

    MERGE — if the file already exists, preserve all other keys and only add fields.signature.view. Do not drop the field's type (it stays wysiwyg; metadata is merged on top of core). Produce valid JSON.

  4. Fix ownership (as root in the container):

    podman exec espocrm_ctr chown -R www-data:www-data /var/www/html/client/custom /var/www/html/custom/Espo/Custom/Resources/metadata
    
  5. Clear cache / rebuild (as the web user):

    podman exec -u www-data espocrm_ctr php command.php rebuild
    

    (If command.php is missing in this build, use bin/command rebuild; or Administration → Rebuild in the UI as admin.)

  6. Verify (hard reload Ctrl+Shift+R first). Open Benutzereinstellungen → the „E-Mail Signatur" editor. The toolbar must now show a Bild/Image button (picture icon) next to the link button. Click it → a „Bild einfügen" dialog opens with a file-upload option (and a URL field). Nothing else in EspoCRM should have changed.

Rollback

  1. Delete /var/www/html/client/custom/src/views/preferences/fields/signature.js.
  2. Remove the fields.signature.view key from …/metadata/entityDefs/Preferences.json (or delete the file if it now only contains that key).
  3. Rebuild (step 5) and hard-reload the browser.