Use Case:
We have a "Tenancy" entity that is related to a "CollectionIssue" entity in a one to many relationship.
We want to display the "CollectionIssues" in a side panel when viewing a single "Tenancy" record similar to how "Tasks" are displayed.
Step 1:
Specify in the "Tenancy" clientDefs script, that we want to have a side panel that will contain a list of "CollectionIssues"
custom/Espo/Custom/Resources/metadata/clientDefs/Tenancy.json
Step 2:
Create the view class that will display the list of "CollectionIssues" in the side panel (specified in the script above)
client/custom/src/views/side-panels/collection-issues.js
Step 3:
Create the custom template to display the list of CollectionIssues as a side panel
client/custom/res/templates/record/panels/collection-issues.tpl
Step 4:
Clear cache and rebuild
We have a "Tenancy" entity that is related to a "CollectionIssue" entity in a one to many relationship.
We want to display the "CollectionIssues" in a side panel when viewing a single "Tenancy" record similar to how "Tasks" are displayed.
Step 1:
Specify in the "Tenancy" clientDefs script, that we want to have a side panel that will contain a list of "CollectionIssues"
custom/Espo/Custom/Resources/metadata/clientDefs/Tenancy.json
Code:
"sidePanels": { "detail": [ { "name": "collectionIssues", "label": "Collection Issues", "view": "custom:views/side-panels/collection-issues", "aclScope": "CollectionIssue" }, ] },
Create the view class that will display the list of "CollectionIssues" in the side panel (specified in the script above)
client/custom/src/views/side-panels/collection-issues.js
Code:
define('custom:views/side-panels/collection-issues', 'views/record/panels/relationship', function (Dep) { return Dep.extend({ name: 'collection-issues', template: 'custom:record/panels/collection-issues', tabList: ['open', 'closed'], defaultTab: 'open', sortBy: 'createdAt', asc: false, buttonList: [ { action: 'createCollectionIssue', title: 'Create Collection Notice', acl: 'create', aclScope: 'CollectionIssue', html: ' < span class="glyphicon glyphicon-plus" > < /span >' } ], listLayout: { rows: [ [ { name: 'name', link: true, } ], [ {name: 'createdAt'}, {name: 'totalAmountDemanded'}, {name: 'status'}, ] ] }, events: _.extend({ 'click button.tab-switcher': function (e) { var $target = $(e.currentTarget); this.$el.find('button.tab-switcher').removeClass('active'); $target.addClass('active'); this.currentTab = $target.data('tab'); this.collection.where = this.where = [ { type: 'primary', value: this.currentTab } ]; this.listenToOnce(this.collection, 'sync', function () { this.notify(false); }.bind(this)); this.notify('Loading...'); this.collection.fetch(); this.getStorage().set('state', this.getStorageKey(), this.currentTab); } }, Dep.prototype.events), data: function () { return { currentTab: this.currentTab, tabList: this.tabList }; }, getStorageKey: function () { return 'collectionIssues-' + this.model.name + '-' + this.name; }, setup: function () { this.scope = this.model.name; this.link = 'collectionIssues'; this.currentTab = this.getStorage().get('state', this.getStorageKey()) || this.defaultTab; this.where = [ { type: 'primary', value: this.currentTab } ]; }, afterRender: function () { var url = this.model.name + '/' + this.model.id + '/' + this.link; if (!this.getAcl().check('CollectionIssue', 'read')) { this.$el.find('.list-container').html(this.translate('No Access')); this.$el.find('.button-container').remove(); return; }; this.getCollectionFactory().create('CollectionIssue', function (collection) { this.collection = collection; collection.seeds = this.seeds; collection.url = url; collection.where = this.where; collection.sortBy = this.sortBy; collection.asc = this.asc; collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 3; var rowActionsView = ''; this.listenToOnce(this.collection, 'sync', function () { this.createView('list', 'views/record/list-expanded', { el: this.getSelector() + ' > .list-container', pagination: false, type: 'listRelationship', rowActionsView: rowActionsView, checkboxes: false, collection: collection, listLayout: this.listLayout, }, function (view) { view.render(); }); }.bind(this)); this.collection.fetch(); }, this); }, actionCreateCollectionIssue: function (data) { var self = this; var link = this.link; var scope = 'CollectionIssue'; var foreignLink = this.model.defs['links'][link].foreign; this.notify('Loading...'); var viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || 'views/modals/edit'; this.createView('quickCreate', viewName, { scope: scope, relate: { model: this.model, link: foreignLink, } }, function (newView) { newView.render(); newView.notify(false); this.listenToOnce(newView, 'after:save', function () { this.collection.fetch(); this.model.trigger('after:relate'); }, this); }); }, actionRefresh: function () { this.collection.fetch(); }, actionClose: function (data) { var id = data.id; if (!id) { return; } var model = this.collection.get(id); model.save({ status: 'Closed' }, { patch: true, success: function () { this.collection.fetch(); }.bind(this) }); }, }); });
Create the custom template to display the list of CollectionIssues as a side panel
client/custom/res/templates/record/panels/collection-issues.tpl
Code:
< div class="btn-group button-container" > {{#each tabList}} < button class="btn btn-default all{{#ifEqual ../currentTab this}} active{{/ifEqual}} tab-switcher" data-tab="{{./this}}" > {{translate this scope='CollectionIssue' category='presetFilters'}} < /button > {{/each}} < /div > < div class="list-container small" > {{{list}}} < /div >
Clear cache and rebuild
Comment