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