link link multiple autocomplete apply all filters, fix empty autocomplete

This commit is contained in:
Yuri Kuznetsov
2023-09-22 15:47:08 +03:00
parent fef2d74ec2
commit 9967bc26d9
2 changed files with 191 additions and 98 deletions
+101 -45
View File
@@ -331,6 +331,10 @@ class LinkMultipleFieldView extends BaseFieldView {
this.$element.get(0).focus({preventScroll: true});
};
}
/** @type {Object.<string, *>} */
this.panelDefs = this.getMetadata()
.get(['clientDefs', this.entityType, 'relationshipPanels', this.name]) || {};
}
/**
@@ -385,7 +389,7 @@ class LinkMultipleFieldView extends BaseFieldView {
* Compose an autocomplete URL. Can be extended.
*
* @protected
* @return {string}
* @return {string|Promise<string>}
*/
getAutocompleteUrl() {
let url = this.foreignScope + '?&maxSize=' + this.getAutocompleteMaxCount();
@@ -407,20 +411,36 @@ class LinkMultipleFieldView extends BaseFieldView {
url += '&select=' + select.join(',')
}
/** @var {Object.<string, *>} */
const panelDefs = this.getMetadata()
.get(['clientDefs', this.entityType, 'relationshipPanels', this.name]) || {};
if (this.panelDefs.selectHandler) {
return new Promise(resolve => {
this._getSelectFilters().then(filters => {
if (filters.bool) {
url += '&' + $.param({'boolFilterList': filters.bool});
}
if (filters.primary) {
url += '&' + $.param({'primaryFilter': filters.primary});
}
if (filters.advanced) {
url += '&' + $.param({'advanced': filters.advanced});
}
resolve(url);
});
});
}
const boolList = [
...(this.getSelectBoolFilterList() || []),
...(panelDefs.selectBoolFilterList || []),
...(this.panelDefs.selectBoolFilterList || []),
];
if (boolList.length) {
url += '&' + $.param({'boolFilterList': boolList});
}
const primary = this.getSelectPrimaryFilterName() || panelDefs.selectPrimaryFilterName;
const primary = this.getSelectPrimaryFilterName() || this.panelDefs.selectPrimaryFilterName;
if (primary) {
url += '&' + $.param({'primaryFilter': primary});
@@ -444,8 +464,15 @@ class LinkMultipleFieldView extends BaseFieldView {
const minChar = this.autocompleteOnEmpty ? 0 : 1;
this.$element.autocomplete({
serviceUrl: () => {
return this.getAutocompleteUrl();
lookup: (q, callback) => {
Promise.resolve(this.getAutocompleteUrl(q))
.then(url => {
Espo.Ajax
.getRequest(url, {q: q})
.then(response => {
callback(this._transformAutocompleteResult(response));
});
});
},
minChars: minChar,
paramName: 'q',
@@ -876,9 +903,7 @@ class LinkMultipleFieldView extends BaseFieldView {
actionSelect() {
Espo.Ui.notify(' ... ');
/** @var {Object.<string, *>} */
const panelDefs = this.getMetadata()
.get(['clientDefs', this.entityType, 'relationshipPanels', this.name]) || {};
const panelDefs = this.panelDefs;
const viewName = panelDefs.selectModalView ||
this.getMetadata().get(`clientDefs.${this.foreignScope}.modalViews.select`) ||
@@ -887,9 +912,7 @@ class LinkMultipleFieldView extends BaseFieldView {
const mandatorySelectAttributeList = this.mandatorySelectAttributeList ||
panelDefs.selectMandatoryAttributeList;
const handler = panelDefs.selectHandler || null;
let createButton = this.isEditMode() &&
const createButton = this.isEditMode() &&
(!this.createDisabled && !panelDefs.createDisabled || this.forceCreateButton);
let createAttributesProvider = null;
@@ -918,40 +941,13 @@ class LinkMultipleFieldView extends BaseFieldView {
};
}
new Promise(resolve => {
if (!handler || this.isSearchMode()) {
resolve({});
return;
}
Espo.loader.requirePromise(handler)
.then(Handler => new Handler(this.getHelper()))
.then(/** module:handlers/select-related */handler => {
handler.getFilters(this.model)
.then(filters => resolve(filters));
});
}).then(filters => {
const advanced = {...(this.getSelectFilters() || {}), ...(filters.advanced || {})};
const primaryFilter = this.getSelectPrimaryFilterName() ||
filters.primary || panelDefs.selectPrimaryFilterName;
const localBoolFilterList = this.getSelectBoolFilterList();
const boolFilterList = (localBoolFilterList || filters.bool || panelDefs.selectBoolFilterList) ?
[
...(localBoolFilterList || []),
...(filters.bool || []),
...(panelDefs.selectBoolFilterList || []),
] :
undefined;
this._getSelectFilters().then(filters => {
this.createView('dialog', viewName, {
scope: this.foreignScope,
createButton: createButton,
filters: advanced,
boolFilterList: boolFilterList,
primaryFilterName: primaryFilter,
filters: filters.advanced,
boolFilterList: filters.bool,
primaryFilterName: filters.primary,
filterList: this.getSelectFilterList(),
multiple: true,
mandatorySelectAttributeList: mandatorySelectAttributeList,
@@ -976,6 +972,66 @@ class LinkMultipleFieldView extends BaseFieldView {
});
});
}
/**
* @private
* @return {Promise<{bool?: string[], advanced?: Object, primary?: string}>}
*/
_getSelectFilters() {
const handler = this.panelDefs.selectHandler;
if (!handler || this.isSearchMode()) {
return Promise.resolve({});
}
return new Promise(resolve => {
Espo.loader.requirePromise(handler)
.then(Handler => new Handler(this.getHelper()))
.then(/** module:handlers/select-related */handler => {
return handler.getFilters(this.model);
})
.then(filters => {
const advanced = {...(this.getSelectFilters() || {}), ...(filters.advanced || {})};
const primaryFilter = this.getSelectPrimaryFilterName() ||
filters.primary || this.panelDefs.selectPrimaryFilterName;
const localBoolFilterList = this.getSelectBoolFilterList();
const boolFilterList = (localBoolFilterList || filters.bool || this.panelDefs.selectBoolFilterList) ?
[
...(localBoolFilterList || []),
...(filters.bool || []),
...(this.panelDefs.selectBoolFilterList || []),
] :
undefined;
resolve({
bool: boolFilterList,
primary: primaryFilter,
advanced: advanced,
});
});
});
}
/**
* @private
*/
_transformAutocompleteResult(response) {
const list = [];
response.list.forEach(item => {
list.push({
id: item.id,
name: item.name || item.id,
data: item.id,
value: item.name || item.id,
attributes: item,
});
});
return {suggestions: list};
}
}
export default LinkMultipleFieldView;
+90 -53
View File
@@ -162,8 +162,6 @@ class LinkFieldView extends BaseFieldView {
*/
mandatorySelectAttributeList = null
getEmptyAutocompleteResult = null
/**
* Trigger autocomplete on empty input.
*
@@ -464,7 +462,7 @@ class LinkFieldView extends BaseFieldView {
* Compose an autocomplete URL. Can be extended.
*
* @protected
* @return {string}
* @return {string|Promise<string>}
*/
getAutocompleteUrl() {
let url = this.foreignScope + '?maxSize=' + this.getAutocompleteMaxCount();
@@ -482,13 +480,36 @@ class LinkFieldView extends BaseFieldView {
url += '&select=' + select.join(',');
}
const boolList = this.getSelectBoolFilterList();
if (this.panelDefs.selectHandler) {
return new Promise(resolve => {
this._getSelectFilters().then(filters => {
if (filters.bool) {
url += '&' + $.param({'boolFilterList': filters.bool});
}
if (boolList) {
url += '&' + $.param({'boolFilterList': boolList});
if (filters.primary) {
url += '&' + $.param({'primaryFilter': filters.primary});
}
if (filters.advanced) {
url += '&' + $.param({'advanced': filters.advanced});
}
resolve(url);
});
});
}
const primary = this.getSelectPrimaryFilterName();
const boolList = [
...(this.getSelectBoolFilterList() || []),
...(this.panelDefs.selectBoolFilterList || []),
];
const primary = this.getSelectPrimaryFilterName() || this.panelDefs.selectPrimaryFilterName;
if (boolList.length) {
url += '&' + $.param({'boolFilterList': boolList});
}
if (primary) {
url += '&' + $.param({'primaryFilter': primary});
@@ -526,7 +547,7 @@ class LinkFieldView extends BaseFieldView {
if (!this.autocompleteDisabled) {
let isEmptyQueryResult = false;
if (this.getEmptyAutocompleteResult) {
if (this.getEmptyAutocompleteResult()) {
this.$elementName.on('keydown', e => {
if (e.code === 'Tab' && isEmptyQueryResult) {
e.stopImmediatePropagation();
@@ -540,17 +561,14 @@ class LinkFieldView extends BaseFieldView {
$c.addClass('small');
}
},
serviceUrl: q => {
return this.getAutocompleteUrl(q);
},
lookup: (q, callback) => {
if (!this.autocompleteOnEmpty && q.length === 0) {
isEmptyQueryResult = true;
if (this.getEmptyAutocompleteResult) {
callback(
this._transformAutocompleteResult(this.getEmptyAutocompleteResult())
);
const emptyResult = this.getEmptyAutocompleteResult();
if (emptyResult) {
callback(this._transformAutocompleteResult(emptyResult));
}
return;
@@ -558,10 +576,13 @@ class LinkFieldView extends BaseFieldView {
isEmptyQueryResult = false;
Espo.Ajax
.getRequest(this.getAutocompleteUrl(q), {q: q})
.then(response => {
callback(this._transformAutocompleteResult(response));
Promise.resolve(this.getAutocompleteUrl(q))
.then(url => {
Espo.Ajax
.getRequest(url, {q: q})
.then(response => {
callback(this._transformAutocompleteResult(response));
});
});
},
minChars: 0,
@@ -670,7 +691,7 @@ class LinkFieldView extends BaseFieldView {
* @private
*/
_transformAutocompleteResult(response) {
let list = [];
const list = [];
response.list.forEach(item => {
list.push({
@@ -978,8 +999,6 @@ class LinkFieldView extends BaseFieldView {
const mandatorySelectAttributeList = this.mandatorySelectAttributeList ||
panelDefs.selectMandatoryAttributeList;
const handler = panelDefs.selectHandler || null;
const createButton = this.isEditMode() &&
(!this.createDisabled && !panelDefs.createDisabled || this.forceCreateButton);
@@ -1009,40 +1028,13 @@ class LinkFieldView extends BaseFieldView {
};
}
new Promise(resolve => {
if (!handler || this.isSearchMode()) {
resolve({});
return;
}
Espo.loader.requirePromise(handler)
.then(Handler => new Handler(this.getHelper()))
.then(/** module:handlers/select-related */handler => {
handler.getFilters(this.model)
.then(filters => resolve(filters));
});
}).then(filters => {
const advanced = {...(this.getSelectFilters() || {}), ...(filters.advanced || {})};
const primaryFilter = this.getSelectPrimaryFilterName() ||
filters.primary || panelDefs.selectPrimaryFilterName;
const localBoolFilterList = this.getSelectBoolFilterList();
const boolFilterList = (localBoolFilterList || filters.bool || panelDefs.selectBoolFilterList) ?
[
...(localBoolFilterList || []),
...(filters.bool || []),
...(panelDefs.selectBoolFilterList || []),
] :
undefined;
this._getSelectFilters().then(filters => {
this.createView('dialog', viewName, {
scope: this.foreignScope,
createButton: createButton,
filters: advanced,
boolFilterList: boolFilterList,
primaryFilterName: primaryFilter,
filters: filters.advanced,
boolFilterList: filters.bool,
primaryFilterName: filters.primary,
mandatorySelectAttributeList: mandatorySelectAttributeList,
forceSelectAllAttributes: this.forceSelectAllAttributes,
filterList: this.getSelectFilterList(),
@@ -1061,6 +1053,47 @@ class LinkFieldView extends BaseFieldView {
});
}
/**
* @private
* @return {Promise<{bool?: string[], advanced?: Object, primary?: string}>}
*/
_getSelectFilters() {
const handler = this.panelDefs.selectHandler;
if (!handler || this.isSearchMode()) {
return Promise.resolve({});
}
return new Promise(resolve => {
Espo.loader.requirePromise(handler)
.then(Handler => new Handler(this.getHelper()))
.then(/** module:handlers/select-related */handler => {
return handler.getFilters(this.model);
})
.then(filters => {
const advanced = {...(this.getSelectFilters() || {}), ...(filters.advanced || {})};
const primaryFilter = this.getSelectPrimaryFilterName() ||
filters.primary || this.panelDefs.selectPrimaryFilterName;
const localBoolFilterList = this.getSelectBoolFilterList();
const boolFilterList = (localBoolFilterList || filters.bool || this.panelDefs.selectBoolFilterList) ?
[
...(localBoolFilterList || []),
...(filters.bool || []),
...(this.panelDefs.selectBoolFilterList || []),
] :
undefined;
resolve({
bool: boolFilterList,
primary: primaryFilter,
advanced: advanced,
});
});
});
}
actionSelectOneOf() {
Espo.Ui.notify(' ... ');
@@ -1093,6 +1126,10 @@ class LinkFieldView extends BaseFieldView {
});
});
}
getEmptyAutocompleteResult() {
return undefined;
}
}
export default LinkFieldView;