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>
This commit is contained in:
105
espoImage-button-in-signature-editor.md
Normal file
105
espoImage-button-in-signature-editor.md
Normal file
@@ -0,0 +1,105 @@
|
||||
### 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()`: `onImageUpload` → `uploadInlineAttachment(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`
|
||||
|
||||
```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`
|
||||
|
||||
```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.
|
||||
Reference in New Issue
Block a user