edit modal helper ref
This commit is contained in:
@@ -29,9 +29,10 @@
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import AclManager from 'acl-manager';
|
||||
import Router from 'router';
|
||||
|
||||
/**
|
||||
* A record-modal helper.
|
||||
* A record-modal helper. Use to render the quick view and quick edit modals.
|
||||
*/
|
||||
class RecordModalHelper {
|
||||
|
||||
@@ -50,22 +51,34 @@ class RecordModalHelper {
|
||||
acl
|
||||
|
||||
/**
|
||||
* @param {module:view} view
|
||||
* @private
|
||||
* @type {Router}
|
||||
*/
|
||||
@inject(Router)
|
||||
router
|
||||
|
||||
/**
|
||||
* Show the 'detail' modal.
|
||||
*
|
||||
* @param {import('view').default} view
|
||||
* @param {{
|
||||
* id: string,
|
||||
* scope: string,
|
||||
* model?: module:model,
|
||||
* entityType: string,
|
||||
* model?: import('model').default,
|
||||
* editDisabled?: boolean,
|
||||
* rootUrl?: string,
|
||||
* afterSave?: function(import('model').default),
|
||||
* afterDestroy?: function(import('model').default),
|
||||
* }} params
|
||||
* @return {Promise}
|
||||
* @return {Promise<import('views/modals/detail').default>}
|
||||
*/
|
||||
showDetail(view, params) {
|
||||
async showDetail(view, params) {
|
||||
const id = params.id;
|
||||
const scope = params.scope;
|
||||
// noinspection JSUnresolvedReference
|
||||
const entityType = params.entityType || params.scope;
|
||||
const model = params.model;
|
||||
|
||||
if (!id || !scope) {
|
||||
if (!id || !entityType) {
|
||||
console.error("Bad data.");
|
||||
|
||||
return Promise.reject();
|
||||
@@ -75,27 +88,163 @@ class RecordModalHelper {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
const viewName = this.metadata.get(['clientDefs', scope, 'modalViews', 'detail']) ||
|
||||
const viewName = this.metadata.get(`clientDefs.${entityType}.modalViews.detail`) ||
|
||||
'views/modals/detail';
|
||||
|
||||
Espo.Ui.notify(' ... ');
|
||||
Espo.Ui.notifyWait()
|
||||
|
||||
const options = {
|
||||
scope: scope,
|
||||
entityType: entityType,
|
||||
model: model,
|
||||
id: id,
|
||||
quickEditDisabled: params.editDisabled,
|
||||
rootUrl: params.rootUrl,
|
||||
};
|
||||
|
||||
return view.createView('modal', viewName, options, modalView => {
|
||||
modalView.render()
|
||||
.then(() => Espo.Ui.notify(false));
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
view.listenToOnce(modalView, 'remove', () => {
|
||||
view.clearView('modal');
|
||||
});
|
||||
});
|
||||
const modalView = /** @type {import('views/modals/detail').default} */
|
||||
await view.createView('modal', viewName, options);
|
||||
|
||||
// @todo Revise.
|
||||
view.listenToOnce(modalView, 'remove', () => view.clearView('modal'));
|
||||
|
||||
if (params.afterSave) {
|
||||
modalView.listenTo(modalView, 'after:save', model => params.afterSave(model));
|
||||
}
|
||||
|
||||
if (params.afterDestroy) {
|
||||
modalView.listenToOnce(modalView, 'after:destroy', model => params.afterDestroy(model));
|
||||
}
|
||||
|
||||
await modalView.render();
|
||||
|
||||
Espo.Ui.notify();
|
||||
|
||||
return modalView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the 'edit' modal.
|
||||
*
|
||||
* @param {import('view').default} view
|
||||
* @param {{
|
||||
* entityType: string,
|
||||
* id?: string,
|
||||
* model?: import('model').default,
|
||||
* rootUrl?: string,
|
||||
* noFullForm?: boolean,
|
||||
* returnUrl?: string,
|
||||
* afterSave?: function(import('model').default),
|
||||
* returnDispatchParams?: {
|
||||
* controller: string,
|
||||
* action: string|null,
|
||||
* options: {isReturn?: boolean} & Record,
|
||||
* },
|
||||
* }} params
|
||||
* @return {Promise<import('views/modals/edit').default>}
|
||||
* @since 9.1.0
|
||||
*/
|
||||
async showEdit(view, params) {
|
||||
const id = params.id;
|
||||
const entityType = params.entityType;
|
||||
const model = params.model;
|
||||
|
||||
const viewName = this.metadata.get(`clientDefs.${entityType}.modalViews.edit`) ||
|
||||
'views/modals/edit';
|
||||
|
||||
/** @type {module:views/modals/detail~options} */
|
||||
const options = {
|
||||
entityType: entityType,
|
||||
id: id,
|
||||
model: model,
|
||||
fullFormDisabled: params.noFullForm,
|
||||
returnUrl: params.returnUrl || this.router.getCurrentUrl(),
|
||||
returnDispatchParams: params.returnDispatchParams,
|
||||
};
|
||||
|
||||
if (params.rootUrl) {
|
||||
options.rootUrl = params.rootUrl;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
const modalView = /** @type {import('views/modals/edit').default} */
|
||||
await view.createView('modal', viewName, options)
|
||||
|
||||
// @todo Revise.
|
||||
modalView.listenToOnce(modalView, 'remove', () => view.clearView('modal'));
|
||||
|
||||
if (params.afterSave) {
|
||||
modalView.listenTo(modalView, 'after:save', model => params.afterSave(model));
|
||||
}
|
||||
|
||||
await modalView.render();
|
||||
|
||||
Espo.Ui.notify();
|
||||
|
||||
return modalView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the 'create' modal.
|
||||
*
|
||||
* @param {import('view').default} view
|
||||
* @param {{
|
||||
* entityType: string,
|
||||
* rootUrl?: string,
|
||||
* noFullForm?: boolean,
|
||||
* returnUrl?: string,
|
||||
* relate?: model:model~setRelateItem | model:model~setRelateItem[],
|
||||
* attributes?: Record.<string, *>,
|
||||
* afterSave?: function(import('model').default),
|
||||
* returnDispatchParams?: {
|
||||
* controller: string,
|
||||
* action: string|null,
|
||||
* options: {isReturn?: boolean} & Record,
|
||||
* },
|
||||
* }} params
|
||||
* @return {Promise<import('views/modals/edit').default>}
|
||||
* @since 9.1.0
|
||||
*/
|
||||
async showCreate(view, params) {
|
||||
const entityType = params.entityType;
|
||||
|
||||
const viewName = this.metadata.get(`clientDefs.${entityType}.modalViews.edit`) ||
|
||||
'views/modals/edit';
|
||||
|
||||
/** @type {module:views/modals/edit~options} */
|
||||
const options = {
|
||||
entityType: entityType,
|
||||
fullFormDisabled: params.noFullForm,
|
||||
returnUrl: params.returnUrl || this.router.getCurrentUrl(),
|
||||
returnDispatchParams: params.returnDispatchParams,
|
||||
relate: params.relate,
|
||||
attributes: params.attributes,
|
||||
};
|
||||
|
||||
if (params.rootUrl) {
|
||||
options.rootUrl = params.rootUrl;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
const modalView = /** @type {import('views/modals/edit').default} */
|
||||
await view.createView('modal', viewName, options)
|
||||
|
||||
|
||||
// @todo Revise.
|
||||
modalView.listenToOnce(modalView, 'remove', () => view.clearView('modal'));
|
||||
|
||||
if (params.afterSave) {
|
||||
modalView.listenTo(modalView, 'after:save', model => params.afterSave(model));
|
||||
}
|
||||
|
||||
await modalView.render();
|
||||
|
||||
Espo.Ui.notify();
|
||||
|
||||
return modalView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import RecordModal from 'helpers/record-modal';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -52,65 +53,52 @@ class CreateRelatedHelper {
|
||||
/**
|
||||
* @param {import('model').default} model
|
||||
* @param {string} link
|
||||
* @param {Record} options
|
||||
* @param {{
|
||||
* afterSave: function(import('model').default),
|
||||
* }} [options]
|
||||
*/
|
||||
process(model, link, options = {}) {
|
||||
async process(model, link, options = {}) {
|
||||
const scope = model.defs['links'][link].entity;
|
||||
const foreignLink = model.defs['links'][link].foreign;
|
||||
|
||||
/** @type {Record} */
|
||||
const panelDefs = this.metadata.get(`clientDefs.${model.entityType}.relationshipPanels.${link}`) || {};
|
||||
|
||||
const attributeMap = panelDefs.createAttributeMap || {};
|
||||
const handler = panelDefs.createHandler;
|
||||
|
||||
let attributes = {};
|
||||
|
||||
const attributeMap = this.metadata
|
||||
.get(['clientDefs', model.entityType, 'relationshipPanels', link, 'createAttributeMap']) || {};
|
||||
Object.keys(attributeMap).forEach(attr => attributes[attributeMap[attr]] = model.get(attr));
|
||||
|
||||
Object.keys(attributeMap)
|
||||
.forEach(attr => attributes[attributeMap[attr]] = model.get(attr));
|
||||
if (handler) {
|
||||
const Handler = await Espo.loader.requirePromise(handler);
|
||||
/** @type {{getAttributes: function(import('model').default): Promise<Record>}} */
|
||||
const handlerObj = new Handler(this.view.getHelper());
|
||||
|
||||
Espo.Ui.notify(' ... ');
|
||||
const additionalAttributes = await handlerObj.getAttributes(model);
|
||||
|
||||
const handler = this.metadata
|
||||
.get(['clientDefs', model.entityType, 'relationshipPanels', link, 'createHandler']);
|
||||
|
||||
new Promise(resolve => {
|
||||
if (!handler) {
|
||||
resolve({});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.loader.requirePromise(handler)
|
||||
.then(Handler => new Handler(this.view.getHelper()))
|
||||
.then(handler => {
|
||||
handler.getAttributes(model)
|
||||
.then(attributes => resolve(attributes));
|
||||
});
|
||||
}).then(additionalAttributes => {
|
||||
attributes = {...attributes, ...additionalAttributes};
|
||||
}
|
||||
|
||||
const viewName = this.metadata.get(['clientDefs', scope, 'modalViews', 'edit']) || 'views/modals/edit';
|
||||
const helper = new RecordModal();
|
||||
|
||||
this.view.createView('quickCreate', viewName, {
|
||||
scope: scope,
|
||||
relate: {
|
||||
model: model,
|
||||
link: foreignLink,
|
||||
},
|
||||
attributes: attributes,
|
||||
}, view => {
|
||||
view.render();
|
||||
view.notify(false);
|
||||
await helper.showCreate(this.view, {
|
||||
entityType: scope,
|
||||
relate: {
|
||||
model: model,
|
||||
link: foreignLink,
|
||||
},
|
||||
attributes: attributes,
|
||||
afterSave: m => {
|
||||
if (options.afterSave) {
|
||||
options.afterSave(m);
|
||||
}
|
||||
|
||||
this.view.listenToOnce(view, 'after:save', () => {
|
||||
if (options.fromSelectRelated) {
|
||||
setTimeout(() => this.view.clearView('dialogSelectRelated'), 25);
|
||||
}
|
||||
|
||||
model.trigger(`update-related:${link}`);
|
||||
|
||||
model.trigger('after:relate');
|
||||
model.trigger(`after:relate:${link}`);
|
||||
});
|
||||
});
|
||||
model.trigger(`update-related:${link}`);
|
||||
model.trigger('after:relate');
|
||||
model.trigger(`after:relate:${link}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,6 +1190,15 @@ Espo.Ui = {
|
||||
* @property {boolean} [suppress] Suppress other warning alerts while this is displayed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show the spinner.
|
||||
*
|
||||
* @since 9.1.0
|
||||
*/
|
||||
notifyWait: function () {
|
||||
Espo.Ui.notify(' ... ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a notify-message.
|
||||
*
|
||||
|
||||
@@ -587,7 +587,7 @@ class EmailFromAddressVarchar extends BaseFieldView {
|
||||
|
||||
helper.showDetail(this, {
|
||||
id: data.id,
|
||||
scope: data.scope,
|
||||
entityType: data.scope,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1060,7 +1060,7 @@ class LinkMultipleFieldView extends BaseFieldView {
|
||||
|
||||
helper.showDetail(this, {
|
||||
id: id,
|
||||
scope: entityType,
|
||||
entityType: entityType,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -732,7 +732,7 @@ class LinkParentFieldView extends BaseFieldView {
|
||||
|
||||
helper.showDetail(this, {
|
||||
id: id,
|
||||
scope: entityType,
|
||||
entityType: entityType,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,7 +1098,7 @@ class LinkFieldView extends BaseFieldView {
|
||||
|
||||
helper.showDetail(this, {
|
||||
id: id,
|
||||
scope: entityType,
|
||||
entityType: entityType,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class GlobalSearchNameFieldView extends BaseFieldView {
|
||||
|
||||
helper.showDetail(this, {
|
||||
id: this.model.id,
|
||||
scope: this.model.attributes._scope,
|
||||
entityType: this.model.attributes._scope,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
import MainView from 'views/main';
|
||||
import SearchManager from 'search-manager';
|
||||
import RecordModal from 'helpers/record-modal';
|
||||
import CreateRelatedHelper from 'helpers/record/create-related';
|
||||
|
||||
/**
|
||||
* A list-related view.
|
||||
@@ -632,65 +634,16 @@ class ListRelatedView extends MainView {
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
actionQuickCreate() {
|
||||
async actionQuickCreate() {
|
||||
const link = this.link;
|
||||
const foreignScope = this.foreignScope;
|
||||
const foreignLink = this.model.getLinkParam(link, 'foreign');
|
||||
|
||||
let attributes = {};
|
||||
const helper = new CreateRelatedHelper(this);
|
||||
|
||||
const attributeMap = this.getMetadata()
|
||||
.get(['clientDefs', this.scope, 'relationshipPanels', link, 'createAttributeMap']) || {};
|
||||
|
||||
Object.keys(attributeMap)
|
||||
.forEach(attr => {
|
||||
attributes[attributeMap[attr]] = this.model.get(attr);
|
||||
});
|
||||
|
||||
Espo.Ui.notify(' ... ');
|
||||
|
||||
const handler = this.getMetadata()
|
||||
.get(['clientDefs', this.scope, 'relationshipPanels', link, 'createHandler']);
|
||||
|
||||
(new Promise(resolve => {
|
||||
if (!handler) {
|
||||
resolve({});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.loader.requirePromise(handler)
|
||||
.then(Handler => new Handler(this.getHelper()))
|
||||
.then(handler => {
|
||||
handler.getAttributes(this.model)
|
||||
.then(attributes => resolve(attributes));
|
||||
});
|
||||
}))
|
||||
.then(additionalAttributes => {
|
||||
attributes = {...attributes, ...additionalAttributes};
|
||||
|
||||
const viewName = this.getMetadata()
|
||||
.get(['clientDefs', foreignScope, 'modalViews', 'edit']) || 'views/modals/edit';
|
||||
|
||||
this.createView('quickCreate', viewName, {
|
||||
scope: foreignScope,
|
||||
relate: {
|
||||
model: this.model,
|
||||
link: foreignLink,
|
||||
},
|
||||
attributes: attributes,
|
||||
}, view => {
|
||||
view.render();
|
||||
view.notify(false);
|
||||
|
||||
this.listenToOnce(view, 'after:save', () => {
|
||||
this.collection.fetch();
|
||||
|
||||
this.model.trigger('after:relate');
|
||||
this.model.trigger('after:relate:' + link);
|
||||
});
|
||||
});
|
||||
});
|
||||
return helper.process(this.model, link, {
|
||||
afterSave: () => {
|
||||
this.collection.fetch()
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
@@ -139,7 +139,11 @@ class EditModalView extends ModalView {
|
||||
* @property {boolean} [focusForCreate] Focus for create.
|
||||
* @property {string} [rootUrl] A root URL.
|
||||
* @property {string} [returnUrl] A return URL.
|
||||
* @property {Record} [returnDispatchParams] Return dispatch params.
|
||||
* @property {{
|
||||
* controller: string,
|
||||
* action: string|null,
|
||||
* options: {isReturn?: boolean} & Record,
|
||||
* }} [returnDispatchParams] Return dispatch params.
|
||||
* @property {string} [fullFormUrl] A full-form URL. As of v9.0.
|
||||
*/
|
||||
|
||||
|
||||
@@ -3274,27 +3274,38 @@ class ListRecordView extends View {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await (new RecordModal()).showDetail(this, {
|
||||
const rootUrl = this.options.keepCurrentRootUrl ? this.getRouter().getCurrentUrl() : undefined;
|
||||
|
||||
const helper = new RecordModal();
|
||||
|
||||
await helper.showDetail(this, {
|
||||
id: id,
|
||||
scope: scope,
|
||||
entityType: scope,
|
||||
model: model,
|
||||
rootUrl: this.options.keepCurrentRootUrl ? this.getRouter().getCurrentUrl() : null,
|
||||
rootUrl: rootUrl,
|
||||
editDisabled: this.quickEditDisabled,
|
||||
})
|
||||
afterSave: m => {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
this.trigger('after:save', m);
|
||||
},
|
||||
afterDestroy: m => {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.listenTo(view, 'after:save', model => this.trigger('after:save', model));
|
||||
this.listenTo(view, 'after:destroy', model => this.removeRecordFromList(model.id));
|
||||
this.removeRecordFromList(m.id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* @param {Object.<string, *>} data
|
||||
*/
|
||||
actionQuickEdit(data) {
|
||||
async actionQuickEdit(data) {
|
||||
data = data || {};
|
||||
|
||||
const id = data.id;
|
||||
@@ -3327,43 +3338,18 @@ class ListRecordView extends View {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewName = this.getMetadata().get(['clientDefs', scope, 'modalViews', 'edit']) ||
|
||||
'views/modals/edit';
|
||||
|
||||
if (!this.quickEditDisabled) {
|
||||
Espo.Ui.notify(' ... ');
|
||||
const helper = new RecordModal();
|
||||
|
||||
const options = {
|
||||
scope: scope,
|
||||
const rootUrl = this.options.keepCurrentRootUrl ? this.getRouter().getCurrentUrl() : undefined;
|
||||
|
||||
await helper.showEdit(this, {
|
||||
entityType: scope,
|
||||
id: id,
|
||||
model: model,
|
||||
fullFormDisabled: data.noFullForm,
|
||||
returnUrl: this.getRouter().getCurrentUrl(),
|
||||
returnDispatchParams: {
|
||||
controller: scope,
|
||||
action: null,
|
||||
options: {
|
||||
isReturn: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (this.options.keepCurrentRootUrl) {
|
||||
options.rootUrl = this.getRouter().getCurrentUrl();
|
||||
}
|
||||
|
||||
this.createView('modal', viewName, options, (view) => {
|
||||
view.once('after:render', () => {
|
||||
Espo.Ui.notify(false);
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
this.listenToOnce(view, 'remove', () => {
|
||||
this.clearView('modal');
|
||||
});
|
||||
|
||||
this.listenToOnce(view, 'after:save', (m) => {
|
||||
noFullForm: data.noFullForm,
|
||||
rootUrl: rootUrl,
|
||||
afterSave: m => {
|
||||
const model = this.collection.get(m.id);
|
||||
|
||||
if (model) {
|
||||
@@ -3371,7 +3357,14 @@ class ListRecordView extends View {
|
||||
}
|
||||
|
||||
this.trigger('after:save', m);
|
||||
});
|
||||
},
|
||||
returnDispatchParams: {
|
||||
controller: scope,
|
||||
action: null,
|
||||
options: {
|
||||
isReturn: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -3394,7 +3387,7 @@ class ListRecordView extends View {
|
||||
options.rootUrl = this.getRouter().getCurrentUrl();
|
||||
}
|
||||
|
||||
this.getRouter().navigate('#' + scope + '/edit/' + id, {trigger: false});
|
||||
this.getRouter().navigate(`#${scope}/edit/${id}`, {trigger: false});
|
||||
this.getRouter().dispatch(scope, 'edit', options);
|
||||
}
|
||||
|
||||
|
||||
@@ -744,7 +744,7 @@ class RelationshipPanelView extends BottomPanelView {
|
||||
|
||||
helper
|
||||
.showDetail(this, {
|
||||
scope: scope,
|
||||
entityType: scope,
|
||||
id: id,
|
||||
model: model,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user