625 lines
22 KiB
JavaScript
625 lines
22 KiB
JavaScript
/**
|
|
*
|
|
*/
|
|
class ProjectFundingTechDDView extends EICDomContent {
|
|
|
|
_autoSave = null;
|
|
|
|
// save every 10s
|
|
_autoSaveDelay = 10000;
|
|
// validate every 2s
|
|
_autoValidateDelay = 2000;
|
|
// state flag avoiding saving form currently beeing loaded
|
|
_busy = false;
|
|
|
|
get autoSave() { return this._autoSave != null; }
|
|
set autoSave(value) {
|
|
if(value) {
|
|
if(!this._autoSave) {
|
|
this._autoSave = setInterval(this.onAutoSave.bind(this), this._autoSaveDelay)
|
|
}
|
|
} else {
|
|
clearInterval(this._autoSave);
|
|
this._autoSave = null;
|
|
}
|
|
}
|
|
|
|
DOMContentLoaded(options) {
|
|
this.components = ui.eicfy(this.el);
|
|
this.projectNumber = options.projectNumber
|
|
this.nodeId = options.nodeId;
|
|
this.nodeType = 'techdd';
|
|
this.mode = options.mode;
|
|
for(let model in options.models) this[model] = options.models[model];
|
|
|
|
this.container = this.components.find(o => o.el.classList.contains('funding-node'))
|
|
this.container.loading = true;
|
|
|
|
this._busy = true;
|
|
this.techdd.get(this.projectNumber,this.nodeType, this.nodeId)
|
|
.then(this.fill.bind(this))
|
|
}
|
|
|
|
DOMContentBlured() {
|
|
|
|
if(this.autoSave) { this.autoSave = false; }
|
|
|
|
if(this.validationCheck) {
|
|
clearInterval(this.validationCheck);
|
|
this.validationCheck = null;
|
|
}
|
|
}
|
|
|
|
DOMContentRemoved() {
|
|
if(this.autoSave) {
|
|
this.autoSave = false;
|
|
if((this.mode == 'edit')) this.save();
|
|
};
|
|
|
|
if(this.validationCheck) {
|
|
clearInterval(this.validationCheck);
|
|
this.validationCheck = null;
|
|
}
|
|
|
|
}
|
|
|
|
DOMContentFocused() {
|
|
if(this.mode == 'edit') {
|
|
if(this.saveToggler && this.saveToggler.value == 'true') { this.autoSave = true }
|
|
if(!this.validationCheck) {
|
|
this.validationCheck = setInterval(this.validateForm.bind(this), this._autoValidateDelay);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
setupFormActions() {
|
|
|
|
let saveControl = this.find('.autosave-control');
|
|
this.availableActions = [];
|
|
this.reviewActions = [];
|
|
|
|
ui.hide(saveControl);
|
|
|
|
if(this.techdd.hasPrivilege('read')) {
|
|
this.mode = 'read'
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('update')) {
|
|
this.mode = 'edit';
|
|
|
|
ui.show(saveControl);
|
|
|
|
|
|
this.availableActions.push({
|
|
id: 'cancel',
|
|
ctrl: new Button(null, {
|
|
severity: 'secondary',
|
|
onclick: this.cancel.bind(this),
|
|
label: 'discard changes'
|
|
})
|
|
})
|
|
|
|
this.availableActions.push({
|
|
id: 'save',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.save.bind(this),
|
|
label: 'save' })
|
|
})
|
|
|
|
this.autosave = true
|
|
this.saveToggler.onToggle("true", this.saveToggler);
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('submit')) {
|
|
this.availableActions.push({
|
|
id: 'submit',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.submit.bind(this),
|
|
label: 'submit' })
|
|
})
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('reject')) {
|
|
this.mode = 'review';
|
|
|
|
this.availableActions.push({
|
|
id: 'reject',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.reject.bind(this),
|
|
label: 'Reopen' })
|
|
})
|
|
|
|
this.reviewActions.push({
|
|
id: 'cancelReview',
|
|
ctrl: new Button(null, {
|
|
severity: 'secondary',
|
|
onclick: this.cancelReview.bind(this),
|
|
label: 'cancel' })
|
|
})
|
|
|
|
this.reviewActions.push({
|
|
id: 'commitReview',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.commitReview.bind(this),
|
|
label: 'send remarks' })
|
|
})
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('sendforreview')) {
|
|
this.mode = 'review';
|
|
|
|
this.availableActions.push({
|
|
id: 'review',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.review.bind(this),
|
|
label: 'send for consultation' })
|
|
})
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('validate')) {
|
|
this.mode = 'review';
|
|
|
|
this.availableActions.push({
|
|
id: 'validate',
|
|
ctrl: new Button(null, {
|
|
severity: 'success',
|
|
onclick: this.validate.bind(this),
|
|
label: 'validate' })
|
|
})
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('cancel')) {
|
|
this.mode = 'review';
|
|
|
|
this.availableActions.push({
|
|
id: 'abort',
|
|
ctrl: new Button(null, {
|
|
severity: 'danger',
|
|
onclick: this.abort.bind(this),
|
|
label: 'abort' })
|
|
})
|
|
}
|
|
|
|
if(this.techdd.hasPrivilege('review')) {
|
|
this.mode = 'review';
|
|
|
|
this.availableActions.push({
|
|
id: 'reject',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.reject.bind(this),
|
|
label: 'add remarks' })
|
|
})
|
|
|
|
this.availableActions.push({
|
|
id: 'approve',
|
|
ctrl: new Button(null, {
|
|
severity: 'success',
|
|
onclick: this.approve.bind(this),
|
|
label: 'approve' })
|
|
})
|
|
|
|
this.reviewActions.push({
|
|
id: 'cancelReview',
|
|
ctrl: new Button(null, {
|
|
severity: 'secondary',
|
|
onclick: this.cancelReview.bind(this),
|
|
label: 'cancel' })
|
|
})
|
|
|
|
this.reviewActions.push({
|
|
id: 'commitReview',
|
|
ctrl: new Button(null, {
|
|
severity: 'primary',
|
|
onclick: this.commitConsult.bind(this),
|
|
label: 'send remarks' })
|
|
})
|
|
}
|
|
|
|
let container = this.find('footer .actions');
|
|
container.innerHTML = '';
|
|
for(let action of this.availableActions) { container.append(action.ctrl.el) }
|
|
}
|
|
|
|
|
|
fill(data) {
|
|
|
|
|
|
let path = 'projects/icmp/project/forms/'
|
|
let view = 'ICMPFormTechddV1View';
|
|
let versionLabel = 'regular report'
|
|
|
|
switch(data.form.version) {
|
|
case 'techdd-report-v1-full':
|
|
view = 'ICMPFormTechddV1FullView';
|
|
versionLabel = 'full report'
|
|
break;
|
|
case 'techdd-report-v1-enhanced':
|
|
view = 'ICMPFormTechddV1EnhancedView'
|
|
versionLabel = 'enhanced report'
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
let tags = [];
|
|
this.find('header .version').innerHTML = `<span eicchip primary>${versionLabel}</span>`
|
|
|
|
if(data.experts.length > 0) {
|
|
tags.push(`<span eicchip info>reporting assigned to ${data.experts[0].information.name.firstName} ${data.experts[0].information.name.lastName}</span>`)
|
|
}
|
|
tags.push(`<span eicchip accent>${app.meta.getItem('icmp-techdd-status', data.statusHistory[0].value).label}</span>`)
|
|
|
|
this.find('header h2').innerHTML = tags.join('');
|
|
|
|
this.originalForm = JSON.parse(JSON.stringify(data))
|
|
|
|
this.loadContent(path + view, {})
|
|
.then(view => {
|
|
this.find('.form').append(view.el)
|
|
view.fill(data);
|
|
this.formView = view;
|
|
this.form = view.form;
|
|
this.formComponents = view.components;
|
|
this.setupForm(data)
|
|
}
|
|
)
|
|
|
|
|
|
}
|
|
|
|
setupForm(data) {
|
|
this.saveToggler = this.components.find(o => o.el.name == 'autosave');
|
|
this.saveToggler.onToggle = this.onAutoSaveToggle.bind(this)
|
|
this.setupFormActions();
|
|
switch(this.mode) {
|
|
case 'read':
|
|
this.enableEditing(false);
|
|
this.enableReviewing(false);
|
|
break;
|
|
case 'edit':
|
|
this.enableEditing(true);
|
|
this.enableReviewing(false);
|
|
if(!this.validationCheck) {
|
|
this.validationCheck = setInterval(this.validateForm.bind(this), this._autoValidateDelay);
|
|
}
|
|
break;
|
|
case 'review':
|
|
this.enableEditing(false);
|
|
this.enableReviewing(false);
|
|
break;
|
|
}
|
|
|
|
let comments = this.findAll('[data-path^="comments."]')
|
|
for(let comment of comments) {
|
|
let chunks = comment.dataset.path.split('.')
|
|
if(chunks.length > 2 && comment.value != '') {
|
|
let trigger = this.find(`li[data-target=${chunks[2]}]`)
|
|
if(trigger) trigger.setAttribute('warning', '')
|
|
}
|
|
}
|
|
|
|
if(data.documents && data.documents.length > 0) {
|
|
for(let document of data.documents[0].attachments) {
|
|
let url = app.config.api['/files'].get.uri
|
|
url = url.replace('{id}', document.id)
|
|
let alert = ui.create(`<div eicalert info><a href="${url}" noroute target="_blank">Download report as PDF</a></div>`)
|
|
this.find('.files').append(alert);
|
|
}
|
|
}
|
|
|
|
this.container.loading = false;
|
|
this._busy = false;
|
|
}
|
|
|
|
enableEditing(value) {
|
|
let fields = this.form.scan(true);
|
|
for(let field of fields) {
|
|
let component = this.form.element2component(this.formComponents, field.el.name, field.el.dataset.path)
|
|
if(component && component.el && component.el.dataset.path.search('form') == 0) {
|
|
if(value) {
|
|
component.el.dataset.type = component.el.nodeName == 'SELECT' ? 'boolean': 'text'
|
|
component.disabled = false;
|
|
} else {
|
|
component.el.dataset.type = 'ignore'
|
|
component.disabled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enableReviewing(value) {
|
|
|
|
let fields = this.form.scan(true);
|
|
|
|
this.originalComments = [];
|
|
|
|
for(let field of fields) {
|
|
let component = this.form.element2component(this.formComponents, field.el.name, field.el.dataset.path)
|
|
if(component && component.el.dataset.path.search('comment') == 0) {
|
|
if(value) {
|
|
this.originalComments.push({
|
|
component: component,
|
|
value: component.value
|
|
})
|
|
component.el.dataset.type = 'text'
|
|
component.disabled = false
|
|
component.show()
|
|
} else {
|
|
component.el.dataset.type = 'ignore'
|
|
component.disabled = true
|
|
component.hide()
|
|
let alerts = component.el.parentElement.querySelectorAll('[eicalert]');
|
|
for(let alert of alerts) {
|
|
alert.remove();
|
|
}
|
|
if(component.value != '') {
|
|
component.el.parentElement.append((new Alert(null, {message: component.value,severity: 'warning'})).el)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
validateForm() {
|
|
//let valid = true;
|
|
let valid = this.form.validate();
|
|
|
|
// init tab badges
|
|
//let triggers = [].concat( this.formView.tabTech.triggers, this.formView.tabMarket.triggers )
|
|
console.log(this.formView.getTriggers())
|
|
let triggers = this.formView.getTriggers();
|
|
for(let trigger of triggers) {
|
|
let badge = new Badge(trigger.querySelector('[eicbadge]'))
|
|
badge.value = ''
|
|
}
|
|
|
|
// mark tabs on error
|
|
if(!valid) {
|
|
let errors = this.findAll('.validation-failed textarea, .validation-failed select')
|
|
|
|
for(let error of errors) {
|
|
let path = error.dataset.path.split('.')
|
|
let trigger = triggers.find(el => el.dataset.target == path[2]);
|
|
// todo make it count
|
|
if(trigger) {
|
|
let badge = new Badge(trigger.querySelector('[eicbadge]'))
|
|
badge.value = parseInt(badge.value || 0) + 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**/
|
|
return valid;
|
|
}
|
|
|
|
autoValidate() { this.validateForm(); }
|
|
|
|
reject() {
|
|
let container = this.find('footer .actions');
|
|
container.innerHTML = '';
|
|
|
|
for(let action of this.reviewActions) container.append(action.ctrl.el)
|
|
|
|
this.enableReviewing(true);
|
|
}
|
|
|
|
cancelReview() {
|
|
|
|
let container = this.find('footer .actions');
|
|
container.innerHTML = '';
|
|
|
|
for(let comment of this.originalComments) {
|
|
comment.component.value = comment.value;
|
|
}
|
|
for(let action of this.availableActions) container.append(action.ctrl.el)
|
|
|
|
this.enableReviewing(false);
|
|
}
|
|
|
|
commitReview() {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = true;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = true;
|
|
|
|
let payload = this.form.value;
|
|
this.techdd.comment('rejecting', this.projectNumber, this.nodeType, this.nodeId, payload)
|
|
.then( () => {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.disabled = this.autoSave;
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
},
|
|
() => {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.disabled = this.autoSave;
|
|
})
|
|
}
|
|
|
|
approve() {
|
|
for(let action of this.availableActions) action.ctrl.disabled = true;
|
|
this.availableActions.find(o => o.id == 'approve').ctrl.loading = true;
|
|
|
|
let payload = this.form.value;
|
|
payload.comments = {};
|
|
this.techdd.comment('reviewing', this.projectNumber, this.nodeType, this.nodeId, payload)
|
|
.then( () => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'approve').ctrl.loading = false;
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
},
|
|
() => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'approve').ctrl.loading = false;
|
|
})
|
|
}
|
|
|
|
commitConsult() {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = true;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = true;
|
|
|
|
let payload = this.form.value;
|
|
this.techdd.comment('reviewing', this.projectNumber, this.nodeType, this.nodeId, payload)
|
|
.then( () => {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = false;
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
},
|
|
() => {
|
|
for(let action of this.reviewActions) action.ctrl.disabled = false;
|
|
this.reviewActions.find(o => o.id == 'commitReview').ctrl.loading = false;
|
|
})
|
|
}
|
|
|
|
save() {
|
|
|
|
if(!app.User.isAuthenticated || this._busy) return;
|
|
|
|
this.validateForm()
|
|
|
|
for(let action of this.availableActions) action.ctrl.disabled = true;
|
|
this.availableActions.find(o => o.id == 'save').ctrl.loading = true;
|
|
|
|
let payload = this.form.value;
|
|
this.techdd.process('saving', this.projectNumber, this.nodeType, this.nodeId, payload)
|
|
.then( payload => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'save').ctrl.loading = false;
|
|
this.availableActions.find(o => o.id == 'save').ctrl.disabled = this.autoSave;
|
|
this.availableActions.find(o => o.id == 'cancel').ctrl.disabled = this.autoSave;
|
|
this.originalForm.form = payload.form;
|
|
},
|
|
() => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'save').ctrl.loading = false;
|
|
this.availableActions.find(o => o.id == 'save').ctrl.disabled = this.autoSave;
|
|
this.availableActions.find(o => o.id == 'cancel').ctrl.disabled = this.autoSave;
|
|
})
|
|
}
|
|
|
|
submit() {
|
|
for(let action of this.availableActions) action.ctrl.disabled = true;
|
|
this.availableActions.find(o => o.id == 'submit').ctrl.loading = true;
|
|
|
|
if(this.validateForm()) {
|
|
let payload = this.form.value;
|
|
this.autoSave = false;
|
|
this.techdd.process('submitting', this.projectNumber, this.nodeType, this.nodeId, payload)
|
|
.then( () => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'submit').ctrl.loading = false;
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
},
|
|
() => {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'submit').ctrl.loading = false;
|
|
})
|
|
} else {
|
|
for(let action of this.availableActions) action.ctrl.disabled = false;
|
|
this.availableActions.find(o => o.id == 'submit').ctrl.loading = false;
|
|
ui.growl.append('The form still contains issues', 'danger')
|
|
}
|
|
}
|
|
|
|
cancel() {
|
|
this.form.fill(this.components,this.originalForm)
|
|
}
|
|
|
|
async abort() {
|
|
let success = await this.openDialog(
|
|
await this.loadContent(
|
|
'projects/icmp/project/dialogs/ICMPNodeActionConfirmDialog',
|
|
{
|
|
title: 'Dismiss expert and report',
|
|
subtitle: 'You are about to dismiss this report. Another expert will be assigned to this task.'
|
|
},
|
|
{
|
|
models: {
|
|
node: this.techdd
|
|
},
|
|
number: this.projectNumber,
|
|
type: this.nodeType,
|
|
nodeId: this.nodeId,
|
|
report: this.form.value,
|
|
action: 'aborting'
|
|
}
|
|
)
|
|
);
|
|
|
|
if(success) {
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
}
|
|
}
|
|
|
|
async validate() {
|
|
let success = await this.openDialog(
|
|
await this.loadContent(
|
|
'projects/icmp/project/dialogs/ICMPNodeActionConfirmDialog',
|
|
{
|
|
title: 'Validate this report',
|
|
subtitle: 'You are about to approve this report and complete Technical Due Diligence'
|
|
},
|
|
{
|
|
models: {
|
|
node: this.techdd
|
|
},
|
|
number: this.projectNumber,
|
|
type: this.nodeType,
|
|
nodeId: this.nodeId,
|
|
report: this.form.value,
|
|
action: 'validating'
|
|
}
|
|
)
|
|
);
|
|
|
|
if(success) {
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
}
|
|
}
|
|
|
|
async review() {
|
|
let success = await this.openDialog(
|
|
await this.loadContent(
|
|
'projects/icmp/project/dialogs/ICMPNodeActionConfirmDialog',
|
|
{ title: 'Send this report for reviewing' },
|
|
{
|
|
models: {
|
|
node: this.techdd
|
|
},
|
|
number: this.projectNumber,
|
|
type: this.nodeType,
|
|
nodeId: this.nodeId,
|
|
report: this.form.value,
|
|
action: 'reviewing'
|
|
}
|
|
)
|
|
)
|
|
|
|
if(success) {
|
|
app.events.trigger('project_node_updated', {node: this.nodeType, nodeId: this.nodeId});
|
|
}
|
|
}
|
|
|
|
onAutoSaveToggle(value, toggler) {
|
|
if(value == 'true') {
|
|
toggler.severity = 'primary'
|
|
this.autoSave = true;
|
|
} else {
|
|
toggler.severity = 'secondary'
|
|
this.autoSave = false;
|
|
}
|
|
this.availableActions.find(o => o.id == 'save').ctrl.disabled = this.autoSave;
|
|
this.availableActions.find(o => o.id == 'cancel').ctrl.disabled = this.autoSave;
|
|
}
|
|
|
|
onAutoSave() { this.save(); }
|
|
}
|
|
|
|
app.registerClass('ProjectFundingTechDDView',ProjectFundingTechDDView); |