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:
mkt
2026-06-06 16:51:02 +02:00
parent 79ea236da0
commit cebe829dcd
79 changed files with 2064 additions and 45 deletions

View File

@@ -0,0 +1,14 @@
/**
* Variable column widths for Markdown tables in text fields.
*
* EspoCRM core CSS forces `table-layout: fixed; width: 100%` on
* `.complex-text table`, which makes all columns equally wide.
* `auto` lets columns size to content instead.
*
* Registered via custom/Espo/Custom/Resources/metadata/app/client.json (cssList).
*/
.complex-text table {
table-layout: auto !important;
width: auto !important;
max-width: 100% !important;
}

View File

@@ -0,0 +1 @@
dummy

View File

@@ -0,0 +1,24 @@
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;
});
}
};
});

View File

@@ -0,0 +1,28 @@
define('custom:views/record/row-actions/tags-unlink-only',
['views/record/row-actions/relationship'], (RelationshipRowActionsView) => {
return class extends RelationshipRowActionsView {
getActionList() {
const list = [];
// Keep only the "Unlink" action (German UI: "Link entfernen").
// View / Edit / Remove are intentionally omitted.
if (!this.options.unlinkDisabled) {
list.push({
action: 'unlinkRelated',
label: 'Unlink',
data: {
id: this.model.id,
},
groupIndex: 0,
});
}
// Preserve any explicitly configured extra row actions (none by default).
this.getAdditionalActionList().forEach(item => list.push(item));
return list;
}
};
});