[IMP] web: Do not store search panel categories
This commit handles two things: 1) Move the local storage logic of the search panel into the documents module. 2) This allows for a variety of optimisations now that we do not have to constantly wait for a potential default value hidden in the storage. This is why this commit also introduces a way for the search panel model extension to sometimes return its query informations sooner than after being completely loaded. Task 2284207
This commit is contained in:
@@ -693,7 +693,6 @@ ActionManager.include({
|
||||
if (config.device.isMobile && actionData.mobile) {
|
||||
options = Object.assign({}, options, actionData.mobile);
|
||||
}
|
||||
action.flags = _.extend({}, action.flags, {searchPanelDefaultNoFilter: true});
|
||||
return self.doAction(action, options).then(ev.data.on_success, ev.data.on_fail);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -260,17 +260,8 @@ var AbstractView = Factory.extend({
|
||||
if (this.withSearchPanel) {
|
||||
// Search panel (Model)
|
||||
const SearchPanelComponent = this.config.SearchPanel;
|
||||
const defaultValues = {};
|
||||
Object.keys(this.loadParams.context).forEach((key) => {
|
||||
let match = /^searchpanel_default_(.*)$/.exec(key);
|
||||
if (match) {
|
||||
defaultValues[match[1]] = this.loadParams.context[key];
|
||||
}
|
||||
});
|
||||
extensions[SearchPanelComponent.modelExtension] = {
|
||||
archNodes: searchPanelInfo.children,
|
||||
defaultNoFilter: params.searchPanelDefaultNoFilter,
|
||||
defaultValues,
|
||||
};
|
||||
this.controllerParams.withSearchPanel = true;
|
||||
this.rendererParams.withSearchPanel = true;
|
||||
|
||||
@@ -13,6 +13,14 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
const DEFAULT_LIMIT = 200;
|
||||
let nextSectionId = 1;
|
||||
|
||||
/**
|
||||
* @param {Filter} filter
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasDomain(filter) {
|
||||
return filter.domain !== "[]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Section} section
|
||||
* @returns {boolean}
|
||||
@@ -68,14 +76,44 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.searchDomain = null;
|
||||
this.DEFAULT_VALUE_INDEX = 0;
|
||||
this.categoriesToLoad = [];
|
||||
this.defaultValues = {};
|
||||
this.filtersToLoad = [];
|
||||
this.initialStateImport = false;
|
||||
this.searchDomain = [];
|
||||
for (const key in this.config.context) {
|
||||
const match = /^searchpanel_default_(.*)$/.exec(key);
|
||||
if (match) {
|
||||
this.defaultValues[match[1]] = this.config.context[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Public
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async callLoad(params) {
|
||||
const searchDomain = this._getExternalDomain();
|
||||
params.searchDomainChanged = (
|
||||
JSON.stringify(this.searchDomain) !== JSON.stringify(searchDomain)
|
||||
);
|
||||
if (!this.shouldLoad && !this.initialStateImport) {
|
||||
const isFetchable = (section) => section.enableCounters ||
|
||||
(params.searchDomainChanged && !section.expand);
|
||||
this.categoriesToLoad = this.categories.filter(isFetchable);
|
||||
this.filtersToLoad = this.filters.filter(isFetchable);
|
||||
this.shouldLoad = params.searchDomainChanged ||
|
||||
Boolean(this.categoriesToLoad.length + this.filtersToLoad.length);
|
||||
}
|
||||
this.searchDomain = searchDomain;
|
||||
this.initialStateImport = false;
|
||||
await super.callLoad(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -109,6 +147,7 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
* @override
|
||||
*/
|
||||
importState(importedState) {
|
||||
this.initialStateImport = Boolean(importedState && !this.state.sections);
|
||||
super.importState(...arguments);
|
||||
if (importedState) {
|
||||
this.state.sections = new Map(this.state.sections);
|
||||
@@ -127,8 +166,18 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async load() {
|
||||
await this._fetchSections({ initialLoad: true });
|
||||
async isReady() {
|
||||
await this.sectionsPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async load(params) {
|
||||
this.sectionsPromise = this._fetchSections(params.isInitialLoad);
|
||||
if (this._shouldWaitForData(params)) {
|
||||
await this.sectionsPromise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,13 +188,6 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
this._createSectionsFromArch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async reloadAfterDispatch() {
|
||||
await this._fetchSections();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Actions / Getters
|
||||
//---------------------------------------------------------------------
|
||||
@@ -180,18 +222,13 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the active value id of a given category. This will also update
|
||||
* the local storage value.
|
||||
* Sets the active value id of a given category.
|
||||
* @param {number} sectionId
|
||||
* @param {number} valueId
|
||||
*/
|
||||
toggleCategoryValue(sectionId, valueId) {
|
||||
const category = this.state.sections.get(sectionId);
|
||||
category.activeValueId = valueId;
|
||||
const storageKey = `searchpanel_${this.config.modelName}_${category.fieldName}`;
|
||||
this.env.services.local_storage.setItem(storageKey, valueId);
|
||||
// FIXME this should be removed (in another commit): should no longer (re)store
|
||||
// active category in localStorage
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +277,7 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
*/
|
||||
_applyDefaultFilterValues() {
|
||||
for (const { fieldName, values } of this.filters) {
|
||||
const defaultValues = this.config.defaultValues[fieldName] || [];
|
||||
const defaultValues = this.defaultValues[fieldName] || [];
|
||||
for (const valueId of defaultValues) {
|
||||
const value = values.get(valueId);
|
||||
if (value) {
|
||||
@@ -266,15 +303,6 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
if (category.hierarchize) {
|
||||
category.parentField = parentField;
|
||||
}
|
||||
|
||||
const allItem = {
|
||||
childrenIds: [],
|
||||
display_name: this.env._t("All"),
|
||||
id: false,
|
||||
bold: true,
|
||||
parentId: false,
|
||||
};
|
||||
category.values = new Map([[false, allItem]]);
|
||||
for (const value of values) {
|
||||
category.values.set(
|
||||
value.id,
|
||||
@@ -299,7 +327,8 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
}
|
||||
}
|
||||
// Set active value from context
|
||||
category.activeValueId = this._getCategoryDefaultValue(values, category);
|
||||
const valueIds = [false, ...values.map((val) => val.id)];
|
||||
this._ensureCategoryValue(category, valueIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,8 +347,8 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
|
||||
// restore checked property
|
||||
values.forEach((value) => {
|
||||
const oldValue = filter.values && filter.values.get(value.id);
|
||||
value.checked = (oldValue && oldValue.checked) || false;
|
||||
const oldValue = filter.values.get(value.id);
|
||||
value.checked = oldValue ? oldValue.checked : false;
|
||||
});
|
||||
|
||||
filter.values = new Map();
|
||||
@@ -390,12 +419,21 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
index,
|
||||
limit: pyUtils.py_eval(attrs.limit || String(DEFAULT_LIMIT)),
|
||||
type,
|
||||
values: new Map(),
|
||||
};
|
||||
if (type === "category") {
|
||||
section.activeValueId = this.defaultValues[attrs.name];
|
||||
section.icon = section.icon || "fa-folder";
|
||||
section.hierarchize = !!pyUtils.py_eval(
|
||||
attrs.hierarchize || "1"
|
||||
);
|
||||
section.values.set(false, {
|
||||
childrenIds: [],
|
||||
display_name: this.env._t("All"),
|
||||
id: false,
|
||||
bold: true,
|
||||
parentId: false,
|
||||
});
|
||||
} else {
|
||||
section.domain = attrs.domain || "[]";
|
||||
section.groupBy = attrs.groupby;
|
||||
@@ -405,104 +443,97 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the active value of a category is one of its own
|
||||
* existing values.
|
||||
* @private
|
||||
* @param {Category} category
|
||||
* @param {number[]} valueIds
|
||||
*/
|
||||
_ensureCategoryValue(category, valueIds) {
|
||||
if (!valueIds.includes(category.activeValueId)) {
|
||||
category.activeValueId = valueIds[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches values for each category at startup. At reload a category is
|
||||
* only fetched if needed.
|
||||
* @private
|
||||
* @param {{
|
||||
* initialLoad: boolean,
|
||||
* searchDomainHasChanged: boolean
|
||||
* }} options
|
||||
* @param {Category[]} categories
|
||||
* @returns {Promise} resolved when all categories have been fetched
|
||||
*/
|
||||
async _fetchCategories({ initialLoad, searchDomainHasChanged }) {
|
||||
const proms = [];
|
||||
for (const category of this.categories) {
|
||||
const { enableCounters, expand, hierarchize, limit } = category;
|
||||
if (initialLoad || enableCounters || (searchDomainHasChanged && !expand)) {
|
||||
const prom = this.env.services.rpc({
|
||||
method: "search_panel_select_range",
|
||||
model: this.config.modelName,
|
||||
args: [category.fieldName],
|
||||
kwargs: {
|
||||
category_domain: this._getCategoryDomain(
|
||||
category.id
|
||||
),
|
||||
enable_counters: enableCounters,
|
||||
expand,
|
||||
filter_domain: this._getFilterDomain(),
|
||||
hierarchize,
|
||||
limit,
|
||||
search_domain: this.searchDomain,
|
||||
},
|
||||
}).then(result => this._createCategoryTree(category.id, result));
|
||||
proms.push(prom);
|
||||
}
|
||||
}
|
||||
await Promise.all(proms);
|
||||
async _fetchCategories(categories) {
|
||||
const filterDomain = this._getFilterDomain();
|
||||
await Promise.all(categories.map(async (category) => {
|
||||
const result = await this.env.services.rpc({
|
||||
method: "search_panel_select_range",
|
||||
model: this.config.modelName,
|
||||
args: [category.fieldName],
|
||||
kwargs: {
|
||||
category_domain: this._getCategoryDomain(category.id),
|
||||
enable_counters: category.enableCounters,
|
||||
expand: category.expand,
|
||||
filter_domain: filterDomain,
|
||||
hierarchize: category.hierarchize,
|
||||
limit: category.limit,
|
||||
search_domain: this.searchDomain,
|
||||
},
|
||||
});
|
||||
this._createCategoryTree(category.id, result);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches values for each filter. This is done at startup and at each
|
||||
* reload if needed.
|
||||
* @private
|
||||
* @param {{
|
||||
* initialLoad: boolean,
|
||||
* searchDomainHasChanged: boolean
|
||||
* }} options
|
||||
* @param {Filter[]} filters
|
||||
* @returns {Promise} resolved when all filters have been fetched
|
||||
*/
|
||||
async _fetchFilters({ initialLoad, searchDomainHasChanged }) {
|
||||
async _fetchFilters(filters) {
|
||||
const evalContext = {};
|
||||
for (const category of this.categories) {
|
||||
evalContext[category.fieldName] = category.activeValueId;
|
||||
}
|
||||
const categoryDomain = this._getCategoryDomain();
|
||||
const proms = [];
|
||||
for (const filter of this.filters) {
|
||||
const { enableCounters, expand, groupBy, limit } = filter;
|
||||
if (initialLoad || enableCounters || (searchDomainHasChanged && !expand)) {
|
||||
const prom = this.env.services.rpc({
|
||||
method: "search_panel_select_multi_range",
|
||||
model: this.config.modelName,
|
||||
args: [filter.fieldName],
|
||||
kwargs: {
|
||||
category_domain: categoryDomain,
|
||||
comodel_domain: Domain.prototype.stringToArray(
|
||||
filter.domain,
|
||||
evalContext
|
||||
),
|
||||
enable_counters: enableCounters,
|
||||
filter_domain: this._getFilterDomain(filter.id),
|
||||
expand,
|
||||
group_by: groupBy || false,
|
||||
group_domain: this._getGroupDomain(filter),
|
||||
limit,
|
||||
search_domain: this.searchDomain,
|
||||
},
|
||||
}).then(result => this._createFilterTree(filter.id, result));
|
||||
proms.push(prom);
|
||||
}
|
||||
}
|
||||
await Promise.all(proms);
|
||||
await Promise.all(filters.map(async (filter) => {
|
||||
const result = await this.env.services.rpc({
|
||||
method: "search_panel_select_multi_range",
|
||||
model: this.config.modelName,
|
||||
args: [filter.fieldName],
|
||||
kwargs: {
|
||||
category_domain: categoryDomain,
|
||||
comodel_domain: Domain.prototype.stringToArray(
|
||||
filter.domain,
|
||||
evalContext
|
||||
),
|
||||
enable_counters: filter.enableCounters,
|
||||
filter_domain: this._getFilterDomain(filter.id),
|
||||
expand: filter.expand,
|
||||
group_by: filter.groupBy || false,
|
||||
group_domain: this._getGroupDomain(filter),
|
||||
limit: filter.limit,
|
||||
search_domain: this.searchDomain,
|
||||
},
|
||||
});
|
||||
this._createFilterTree(filter.id, result);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches categories and filters at startup or if needed.
|
||||
* @private
|
||||
* @param {Object} [options={}]
|
||||
* @param {boolean} [options.initialLoad=false]
|
||||
* @param {boolean} isInitialLoad
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async _fetchSections(options = {}) {
|
||||
const searchDomain = this._getExternalDomain();
|
||||
if (!options.initialLoad) {
|
||||
options.searchDomainHasChanged =
|
||||
JSON.stringify(this.searchDomain) !== JSON.stringify(searchDomain);
|
||||
}
|
||||
this.searchDomain = searchDomain;
|
||||
await this._fetchCategories(options);
|
||||
await this._fetchFilters(options);
|
||||
if (options.initialLoad) {
|
||||
async _fetchSections(isInitialLoad) {
|
||||
await this._fetchCategories(
|
||||
isInitialLoad ? this.categories : this.categoriesToLoad
|
||||
);
|
||||
await this._fetchFilters(
|
||||
isInitialLoad ? this.filters : this.filtersToLoad
|
||||
);
|
||||
if (isInitialLoad) {
|
||||
this._applyDefaultFilterValues();
|
||||
}
|
||||
}
|
||||
@@ -520,53 +551,22 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
for (const category of this.categories) {
|
||||
if (
|
||||
category.id === excludedCategoryId ||
|
||||
category.activeValueId === false
|
||||
!category.activeValueId
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (category.activeValueId) {
|
||||
const field = this.config.fields[category.fieldName];
|
||||
const operator =
|
||||
field.type === "many2one" && category.parentField ? "child_of" : "=";
|
||||
domain.push([
|
||||
category.fieldName,
|
||||
operator,
|
||||
category.activeValueId,
|
||||
]);
|
||||
}
|
||||
const field = this.config.fields[category.fieldName];
|
||||
const operator =
|
||||
field.type === "many2one" && category.parentField ? "child_of" : "=";
|
||||
domain.push([
|
||||
category.fieldName,
|
||||
operator,
|
||||
category.activeValueId,
|
||||
]);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object[]} values
|
||||
* @param {Category} category
|
||||
* @returns {number | false}
|
||||
*/
|
||||
_getCategoryDefaultValue(values, { fieldName }) {
|
||||
const validValues = [false, ...values.map((val) => val.id)];
|
||||
const defaultValue = this.config.defaultValues[fieldName];
|
||||
if (validValues.includes(defaultValue)) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (this.config.defaultNoFilter) {
|
||||
return false;
|
||||
}
|
||||
// If not set in context, or set to an unknown value, set active value
|
||||
// from localStorage
|
||||
const storageKey = `searchpanel_${this.config.modelName}_${fieldName}`;
|
||||
const storageValue = this.env.services.local_storage.getItem(storageKey);
|
||||
if (validValues.includes(storageValue)) {
|
||||
return storageValue;
|
||||
}
|
||||
// If still not a valid value, get the search panel default value
|
||||
// from the given valid values.
|
||||
return validValues[
|
||||
Math.min(validValues.length - 1, this.DEFAULT_VALUE_INDEX)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain retrieved from the other model extensions.
|
||||
* @private
|
||||
@@ -617,7 +617,7 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
for (const group of groups.values()) {
|
||||
addCondition(fieldName, group.values);
|
||||
}
|
||||
} else if (values) {
|
||||
} else {
|
||||
addCondition(fieldName, values);
|
||||
}
|
||||
}
|
||||
@@ -694,6 +694,33 @@ odoo.define("web/static/src/js/views/search_panel_model_extension.js", function
|
||||
return groupDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the query informations should be considered as ready
|
||||
* before or after having (re-)fetched the sections data.
|
||||
* @private
|
||||
* @param {Object} params
|
||||
* @param {boolean} params.isInitialLoad
|
||||
* @param {boolean} params.searchDomainChanged
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_shouldWaitForData({ isInitialLoad, searchDomainChanged }) {
|
||||
if (isInitialLoad && Object.keys(this.defaultValues).length) {
|
||||
// Default values need to be checked on initial load
|
||||
return true;
|
||||
}
|
||||
if (this.categories.length && this.filters.some(hasDomain)) {
|
||||
// Selected category value might affect the filter values
|
||||
return true;
|
||||
}
|
||||
if (!this.searchDomain.length) {
|
||||
// No search domain -> no need to check for expand
|
||||
return false;
|
||||
}
|
||||
return [...this.state.sections.values()].some(
|
||||
(section) => !section.expand && searchDomainChanged
|
||||
);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Static
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -3591,9 +3591,6 @@ QUnit.module('ActionManager', {
|
||||
active_id: 1,
|
||||
active_ids: [1],
|
||||
},
|
||||
flags: {
|
||||
searchPanelDefaultNoFilter: true,
|
||||
},
|
||||
});
|
||||
var checkSessionStorage = false;
|
||||
var actionManager = await createActionManager({
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
odoo.define("web/static/tests/views/search_panel_tests.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const AbstractStorageService = require('web.AbstractStorageService');
|
||||
const FormView = require('web.FormView');
|
||||
const KanbanView = require('web.KanbanView');
|
||||
const RamStorage = require('web.RamStorage');
|
||||
const testUtils = require('web.test_utils');
|
||||
const SearchPanel = require("web/static/src/js/views/search_panel.js");
|
||||
|
||||
@@ -115,13 +113,6 @@ QUnit.module('Views', {
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
};
|
||||
|
||||
var RamStorageService = AbstractStorageService.extend({
|
||||
storage: new RamStorage(),
|
||||
});
|
||||
this.services = {
|
||||
local_storage: RamStorageService,
|
||||
};
|
||||
},
|
||||
}, function () {
|
||||
|
||||
@@ -138,7 +129,6 @@ QUnit.module('Views', {
|
||||
assert.step((args.method || route) + (args.model ? (' on ' + args.model) : ''));
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -198,7 +188,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -237,7 +226,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
@@ -279,7 +267,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -320,7 +307,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -368,7 +354,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -434,7 +419,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -486,132 +470,6 @@ QUnit.module('Views', {
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('store and retrieve active category value', async function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
var Storage = RamStorage.extend({
|
||||
getItem: function (key) {
|
||||
assert.step(`getItem ${key}`);
|
||||
const item = this._super(...arguments);
|
||||
return item || 3; // default: 'asustek'
|
||||
},
|
||||
setItem: function (key, value) {
|
||||
assert.step(`setItem ${key} to ${value}`);
|
||||
this._super(...arguments);
|
||||
},
|
||||
});
|
||||
var RamStorageService = AbstractStorageService.extend({
|
||||
storage: new Storage(),
|
||||
});
|
||||
|
||||
var expectedActiveId = 3;
|
||||
var kanban = await createView({
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: {
|
||||
local_storage: RamStorageService,
|
||||
},
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
archs: {
|
||||
'partner,false,search': `
|
||||
<search>
|
||||
<searchpanel>
|
||||
<field name="company_id" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.deepEqual(args.domain, [['company_id', 'child_of', expectedActiveId]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
// 'asustek' should be selected by default
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(1) .active');
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
|
||||
|
||||
// select 'agrolait'
|
||||
expectedActiveId = 5;
|
||||
await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
|
||||
|
||||
assert.verifySteps([
|
||||
'getItem searchpanel_partner_company_id', // get on start
|
||||
'setItem searchpanel_partner_company_id to 5',
|
||||
'getItem searchpanel_partner_company_id', // get on reload
|
||||
]);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('retrieved category value does not exist', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var Storage = RamStorage.extend({
|
||||
getItem: function (key) {
|
||||
assert.step('getItem ' + key);
|
||||
return 343; // this value doesn't exist
|
||||
},
|
||||
});
|
||||
var RamStorageService = AbstractStorageService.extend({
|
||||
storage: new Storage(),
|
||||
});
|
||||
|
||||
var kanban = await createView({
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: {
|
||||
local_storage: RamStorageService,
|
||||
},
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
archs: {
|
||||
'partner,false,search': `
|
||||
<search>
|
||||
<searchpanel>
|
||||
<field name="company_id" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.deepEqual(args.domain, []);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
// 'All' should be selected by default as the retrieved value does not exist
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
|
||||
|
||||
assert.verifySteps(['getItem searchpanel_partner_company_id']);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('category has been archived', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
@@ -688,7 +546,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -778,7 +635,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -876,7 +732,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -929,7 +784,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -982,7 +836,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1034,7 +887,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1104,6 +956,187 @@ QUnit.module('Views', {
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("concurrency: single category", async function (assert) {
|
||||
assert.expect(12);
|
||||
|
||||
let prom = testUtils.makeTestPromise();
|
||||
const kanbanPromise = createView({
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
<div t-name="kanban-box">
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
archs: {
|
||||
"partner,false,search": `
|
||||
<search>
|
||||
<filter name="Filter" domain="[('id', '=', 1)]"/>
|
||||
<searchpanel>
|
||||
<field name="company_id" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
},
|
||||
context: {
|
||||
searchpanel_default_company_id: [5],
|
||||
},
|
||||
data: this.data,
|
||||
async mockRPC(route, args) {
|
||||
const _super = this._super.bind(this);
|
||||
if (route !== "/web/dataset/search_read") {
|
||||
await prom;
|
||||
}
|
||||
assert.step(args.method || route);
|
||||
return _super(...arguments);
|
||||
},
|
||||
model: 'partner',
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
// Case 1: search panel is awaited to build the query with search defaults
|
||||
await testUtils.nextTick();
|
||||
assert.verifySteps([]);
|
||||
|
||||
prom.resolve();
|
||||
const kanban = await kanbanPromise;
|
||||
|
||||
assert.verifySteps([
|
||||
"search_panel_select_range",
|
||||
"/web/dataset/search_read",
|
||||
]);
|
||||
|
||||
// Case 2: search domain changed so we wait for the search panel once again
|
||||
prom = testUtils.makeTestPromise();
|
||||
|
||||
await testUtils.controlPanel.toggleFilterMenu(kanban);
|
||||
await testUtils.controlPanel.toggleMenuItem(kanban, 0);
|
||||
|
||||
assert.verifySteps([]);
|
||||
|
||||
prom.resolve();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.verifySteps([
|
||||
"search_panel_select_range",
|
||||
"/web/dataset/search_read",
|
||||
]);
|
||||
|
||||
// Case 3: search domain is the same and default values do not matter anymore
|
||||
prom = testUtils.makeTestPromise();
|
||||
|
||||
await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
|
||||
|
||||
// The search read is executed right away in this case
|
||||
assert.verifySteps(["/web/dataset/search_read"]);
|
||||
|
||||
prom.resolve();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.verifySteps(["search_panel_select_range"]);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("concurrency: category and filter", async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
let prom = testUtils.makeTestPromise();
|
||||
const kanbanPromise = createView({
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
<div t-name="kanban-box">
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
archs: {
|
||||
"partner,false,search": `
|
||||
<search>
|
||||
<searchpanel>
|
||||
<field name="category_id" enable_counters="1"/>
|
||||
<field name="company_id" select="multi" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
},
|
||||
data: this.data,
|
||||
async mockRPC(route, args) {
|
||||
const _super = this._super.bind(this);
|
||||
if (route !== "/web/dataset/search_read") {
|
||||
await prom;
|
||||
}
|
||||
assert.step(args.method || route);
|
||||
return _super(...arguments);
|
||||
},
|
||||
model: 'partner',
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.verifySteps(["/web/dataset/search_read"]);
|
||||
|
||||
prom.resolve();
|
||||
const kanban = await kanbanPromise;
|
||||
|
||||
assert.verifySteps([
|
||||
"search_panel_select_range",
|
||||
"search_panel_select_multi_range",
|
||||
]);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("concurrency: category and filter with a domain", async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
let prom = testUtils.makeTestPromise();
|
||||
const kanbanPromise = createView({
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
<div t-name="kanban-box">
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
archs: {
|
||||
"partner,false,search": `
|
||||
<search>
|
||||
<searchpanel>
|
||||
<field name="category_id" enable_counters="1"/>
|
||||
<field name="company_id" select="multi" domain="[['category_id', '=', category_id]]" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>`,
|
||||
},
|
||||
data: this.data,
|
||||
async mockRPC(route, args) {
|
||||
const _super = this._super.bind(this);
|
||||
if (route !== "/web/dataset/search_read") {
|
||||
await prom;
|
||||
}
|
||||
assert.step(args.method || route);
|
||||
return _super(...arguments);
|
||||
},
|
||||
model: 'partner',
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.verifySteps([]);
|
||||
|
||||
prom.resolve();
|
||||
const kanban = await kanbanPromise;
|
||||
|
||||
assert.verifySteps([
|
||||
"search_panel_select_range",
|
||||
"search_panel_select_multi_range",
|
||||
"/web/dataset/search_read",
|
||||
]);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('concurrency: misordered get_filters', async function (assert) {
|
||||
assert.expect(15);
|
||||
|
||||
@@ -1119,7 +1152,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1154,7 +1186,7 @@ QUnit.module('Views', {
|
||||
// 'All' should still be selected, and there should still be 4 records
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(1) .active');
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
|
||||
|
||||
// select 'ghi' (delay the reload)
|
||||
def = testUtils.makeTestPromise();
|
||||
@@ -1164,7 +1196,7 @@ QUnit.module('Views', {
|
||||
// 'All' should still be selected, and there should still be 4 records
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
|
||||
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(3) .active');
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
|
||||
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
|
||||
|
||||
// unlock ghi search
|
||||
ghiDef.resolve();
|
||||
@@ -1198,7 +1230,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1264,7 +1295,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1371,7 +1401,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1463,7 +1492,6 @@ QUnit.module('Views', {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1533,7 +1561,6 @@ QUnit.module('Views', {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1606,7 +1633,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1711,7 +1737,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1823,7 +1848,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -1952,7 +1976,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2002,7 +2025,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2073,7 +2095,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2123,7 +2144,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2165,7 +2185,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2215,7 +2234,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `<kanban>
|
||||
<templates><t t-name="kanban-box">
|
||||
<div>
|
||||
@@ -2261,7 +2279,6 @@ QUnit.module('Views', {
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2358,7 +2375,6 @@ QUnit.module('Views', {
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.step(JSON.stringify(args.domain));
|
||||
@@ -2407,7 +2423,6 @@ QUnit.module('Views', {
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.step(JSON.stringify(args.domain));
|
||||
@@ -2488,26 +2503,10 @@ QUnit.module('Views', {
|
||||
QUnit.test('after onExecuteAction, selects "All" as default category value', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var Storage = RamStorage.extend({
|
||||
getItem: function (key) {
|
||||
assert.step('getItem ' + key);
|
||||
return 3; // 'asustek'
|
||||
},
|
||||
setItem: function (key, value) {
|
||||
assert.step('setItem ' + key + ' to ' + value);
|
||||
},
|
||||
});
|
||||
var RamStorageService = AbstractStorageService.extend({
|
||||
storage: new Storage(),
|
||||
});
|
||||
|
||||
var actionManager = await createActionManager({
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: {
|
||||
local_storage: RamStorageService,
|
||||
},
|
||||
});
|
||||
|
||||
await actionManager.doAction(2);
|
||||
@@ -2530,7 +2529,6 @@ QUnit.module('Views', {
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
await actionManager.doAction(2);
|
||||
@@ -2549,7 +2547,6 @@ QUnit.module('Views', {
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
@@ -2587,7 +2584,6 @@ QUnit.module('Views', {
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
actionManager.$el.css('max-height', 300);
|
||||
|
||||
@@ -2669,7 +2665,6 @@ QUnit.module('Views', {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -2694,7 +2689,7 @@ QUnit.module('Views', {
|
||||
assert.verifySteps([
|
||||
'search_panel_select_range',
|
||||
"search_panel_select_multi_range",
|
||||
'/web/dataset/search_read'
|
||||
'/web/dataset/search_read',
|
||||
]);
|
||||
|
||||
assert.deepEqual(getCounters(kanban), [
|
||||
@@ -2712,7 +2707,7 @@ QUnit.module('Views', {
|
||||
assert.verifySteps([
|
||||
'search_panel_select_range',
|
||||
"search_panel_select_multi_range",
|
||||
'/web/dataset/search_read'
|
||||
'/web/dataset/search_read',
|
||||
]);
|
||||
|
||||
kanban.destroy();
|
||||
@@ -2745,7 +2740,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2788,7 +2782,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2831,7 +2824,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2869,7 +2861,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2907,7 +2898,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2950,7 +2940,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -2993,7 +2982,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3031,7 +3019,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3067,7 +3054,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3103,7 +3089,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3139,7 +3124,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3175,7 +3159,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3211,7 +3194,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3247,7 +3229,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3283,7 +3264,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3319,7 +3299,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3355,7 +3334,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3391,7 +3369,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3427,7 +3404,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3463,7 +3439,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3499,7 +3474,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3535,7 +3509,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3571,7 +3544,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3607,7 +3579,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3643,7 +3614,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3679,7 +3649,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3715,7 +3684,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3751,7 +3719,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3787,7 +3754,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3823,7 +3789,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3859,7 +3824,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3895,7 +3859,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3936,7 +3899,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -3980,7 +3942,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -4018,7 +3979,6 @@ QUnit.module('Views', {
|
||||
},
|
||||
data: this.data,
|
||||
model: 'partner',
|
||||
services: this.services,
|
||||
View: KanbanView,
|
||||
});
|
||||
|
||||
@@ -4043,7 +4003,6 @@ QUnit.module('Views', {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
@@ -4115,7 +4074,6 @@ QUnit.module('Views', {
|
||||
assert.step(args.method || route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: this.services,
|
||||
arch: `
|
||||
<kanban>
|
||||
<templates>
|
||||
|
||||
Reference in New Issue
Block a user