mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-11-02 20:30:20 -06:00
[PATCH] Upstream patch - 18012022
This commit is contained in:
1 parent
a6d4ddf2ea
commit
02e4797361
290 files changed
+4422
-1070
No files matched your search
@@ -128,9 +128,8 @@ def redirect_with_hash(*args, **kw):
|
||||
return http.redirect_with_hash(*args, **kw)
|
||||
|
||||
def abort_and_redirect(url):
|
||||
r = request.httprequest
|
||||
response = werkzeug.utils.redirect(url, 302)
|
||||
response = r.app.get_response(r, response, explicit_session=False)
|
||||
response = http.root.get_response(request.httprequest, response, explicit_session=False)
|
||||
werkzeug.exceptions.abort(response)
|
||||
|
||||
def ensure_db(redirect='/web/database/selector'):
|
||||
@@ -647,6 +646,10 @@ class HomeStaticTemplateHelpers(object):
|
||||
def get_qweb_templates(cls, addons, db=None, debug=False):
|
||||
return cls(addons, db, debug=debug)._get_qweb_templates()[0]
|
||||
|
||||
# Shared parameters for all login/signup flows
|
||||
SIGN_UP_REQUEST_PARAMS = {'db', 'login', 'debug', 'token', 'message', 'error', 'scope', 'mode',
|
||||
'redirect', 'redirect_hostname', 'email', 'name', 'partner_id',
|
||||
'password', 'confirm_password', 'city', 'country_id', 'lang'}
|
||||
|
||||
class GroupsTreeNode:
|
||||
"""
|
||||
@@ -934,7 +937,7 @@ class Home(http.Controller):
|
||||
if not request.uid:
|
||||
request.uid = flectra.SUPERUSER_ID
|
||||
|
||||
values = request.params.copy()
|
||||
values = {k: v for k, v in request.params.items() if k in SIGN_UP_REQUEST_PARAMS}
|
||||
try:
|
||||
values['databases'] = http.db_list()
|
||||
except flectra.exceptions.AccessDenied:
|
||||
@@ -1102,7 +1105,7 @@ class Proxy(http.Controller):
|
||||
from werkzeug.wrappers import BaseResponse
|
||||
base_url = request.httprequest.base_url
|
||||
query_string = request.httprequest.query_string
|
||||
client = Client(request.httprequest.app, BaseResponse)
|
||||
client = Client(http.root, BaseResponse)
|
||||
headers = {'X-Openerp-Session-Id': request.session.sid}
|
||||
return client.post('/' + path, base_url=base_url, query_string=query_string,
|
||||
headers=headers, data=data)
|
||||
@@ -2067,9 +2070,10 @@ class ReportController(http.Controller):
|
||||
# Misc. route utils
|
||||
#------------------------------------------------------
|
||||
@http.route(['/report/barcode', '/report/barcode/<type>/<path:value>'], type='http', auth="public")
|
||||
def report_barcode(self, type, value, width=600, height=100, humanreadable=0, quiet=1, mask=None):
|
||||
def report_barcode(self, type, value, **kwargs):
|
||||
"""Contoller able to render barcode images thanks to reportlab.
|
||||
Samples:
|
||||
Samples::
|
||||
|
||||
<img t-att-src="'/report/barcode/QR/%s' % o.name"/>
|
||||
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' %
|
||||
('QR', o.name, 200, 200)"/>
|
||||
@@ -2077,6 +2081,8 @@ class ReportController(http.Controller):
|
||||
:param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
|
||||
'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
|
||||
'UPCA', 'USPS_4State'
|
||||
:param width: Pixel width of the barcode
|
||||
:param height: Pixel height of the barcode
|
||||
:param humanreadable: Accepted values: 0 (default) or 1. 1 will insert the readable value
|
||||
at the bottom of the output image
|
||||
:param quiet: Accepted values: 0 (default) or 1. 1 will display white
|
||||
@@ -2084,10 +2090,11 @@ class ReportController(http.Controller):
|
||||
:param mask: The mask code to be used when rendering this QR-code.
|
||||
Masks allow adding elements on top of the generated image,
|
||||
such as the Swiss cross in the center of QR-bill codes.
|
||||
:param barLevel: QR code Error Correction Levels. Default is 'L'.
|
||||
ref: https://hg.reportlab.com/hg-public/reportlab/file/830157489e00/src/reportlab/graphics/barcode/qr.py#l101
|
||||
"""
|
||||
try:
|
||||
barcode = request.env['ir.actions.report'].barcode(type, value, width=width,
|
||||
height=height, humanreadable=humanreadable, quiet=quiet, mask=mask)
|
||||
barcode = request.env['ir.actions.report'].barcode(type, value, **kwargs)
|
||||
except (ValueError, AttributeError):
|
||||
raise werkzeug.exceptions.HTTPException(description='Cannot convert into barcode.')
|
||||
|
||||
|
||||
@@ -359,6 +359,7 @@
|
||||
* the list of variables so it does not get replaced by a lookup in the context
|
||||
*/
|
||||
function compileExprToArray(expr, scope) {
|
||||
const localVars = new Set();
|
||||
scope = Object.create(scope);
|
||||
const tokens = tokenize(expr);
|
||||
let i = 0;
|
||||
@@ -407,12 +408,14 @@
|
||||
if (tokens[j].type === "SYMBOL" && tokens[j].originalValue) {
|
||||
tokens[j].value = tokens[j].originalValue;
|
||||
scope[tokens[j].value] = { id: tokens[j].value, expr: tokens[j].value };
|
||||
localVars.add(tokens[j].value);
|
||||
}
|
||||
j--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope[token.value] = { id: token.value, expr: token.value };
|
||||
localVars.add(token.value);
|
||||
}
|
||||
}
|
||||
if (isVar) {
|
||||
@@ -427,6 +430,13 @@
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Mark all variables that have been used locally.
|
||||
// This assumes the expression has only one scope (incorrect but "good enough for now")
|
||||
for (const token of tokens) {
|
||||
if (token.type === "SYMBOL" && localVars.has(token.value)) {
|
||||
token.isLocal = true;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
function compileExpr(expr, scope) {
|
||||
@@ -577,8 +587,24 @@
|
||||
const tokens = compileExprToArray(expr, this.variables);
|
||||
const done = new Set();
|
||||
return tokens
|
||||
.map((tok) => {
|
||||
if (tok.varName) {
|
||||
.map((tok, i) => {
|
||||
// "this" in captured expressions should be the current component
|
||||
if (tok.value === "this") {
|
||||
if (!done.has("this")) {
|
||||
done.add("this");
|
||||
this.addLine(`const this_${argId} = utils.getComponent(context);`);
|
||||
}
|
||||
tok.value = `this_${argId}`;
|
||||
}
|
||||
// Variables that should be looked up in the scope. isLocal is for arrow
|
||||
// function arguments that should stay untouched (eg "ev => ev" should
|
||||
// not become "const ev_1 = scope['ev']; ev_1 => ev_1")
|
||||
if (tok.varName &&
|
||||
!tok.isLocal &&
|
||||
// HACK: for backwards compatibility, we don't capture bare methods
|
||||
// this allows them to be called with the rendering context/scope
|
||||
// as their this value.
|
||||
(!tokens[i + 1] || tokens[i + 1].type !== "LEFT_PAREN")) {
|
||||
if (!done.has(tok.varName)) {
|
||||
done.add(tok.varName);
|
||||
this.addLine(`const ${tok.varName}_${argId} = ${tok.value};`);
|
||||
@@ -3176,7 +3202,12 @@ See https://github.com/flectra/owl/blob/master/doc/reference/config.md#mode for
|
||||
else if (!name.startsWith("t-")) {
|
||||
if (name !== "class" && name !== "style") {
|
||||
// this is a prop!
|
||||
props[name] = ctx.formatExpression(value) || "undefined";
|
||||
if (value.includes("=>")) {
|
||||
props[name] = ctx.captureExpression(value);
|
||||
}
|
||||
else {
|
||||
props[name] = ctx.formatExpression(value) || "undefined";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5546,9 +5577,9 @@ See https://github.com/flectra/owl/blob/master/doc/reference/config.md#mode for
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
|
||||
__info__.version = '1.4.8';
|
||||
__info__.date = '2021-11-03T12:45:36.455Z';
|
||||
__info__.hash = '307b936';
|
||||
__info__.version = '1.4.10';
|
||||
__info__.date = '2021-12-07T14:32:29.551Z';
|
||||
__info__.hash = 'bc04f72';
|
||||
__info__.url = 'https://github.com/flectra/owl';
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 326 B |
@@ -3083,7 +3083,7 @@ var JournalDashboardGraph = AbstractField.extend({
|
||||
var labels = this.data[0].values.map(function (pt) {
|
||||
return pt.x;
|
||||
});
|
||||
var borderColor = this.data[0].is_sample_data ? '#dddddd' : '#2496f6';
|
||||
var borderColor = this.data[0].is_sample_data ? '#dddddd' : '#009EFB';
|
||||
var backgroundColor = this.data[0].is_sample_data ? '#ebebeb' : '#dcd0d9';
|
||||
return {
|
||||
type: 'line',
|
||||
|
||||
@@ -432,8 +432,9 @@ DebugManager.include({
|
||||
var self = this;
|
||||
var dialog = new Dialog(this, { title: _t("Fields View Get") });
|
||||
dialog.opened().then(function () {
|
||||
const arch = self._controller.renderer.arch || self._controller.renderer.props.arch;
|
||||
$('<pre>').text(utils.json_node_to_xml(
|
||||
self._controller.renderer.arch, true)
|
||||
arch, true)
|
||||
).appendTo(dialog.$el);
|
||||
});
|
||||
dialog.open();
|
||||
|
||||
@@ -1014,6 +1014,7 @@ var BasicModel = AbstractModel.extend({
|
||||
var params = {
|
||||
model: modelName,
|
||||
ids: resIDs,
|
||||
context: data.getContext(),
|
||||
};
|
||||
if (options.offset) {
|
||||
params.offset = options.offset;
|
||||
@@ -1037,6 +1038,7 @@ var BasicModel = AbstractModel.extend({
|
||||
model: modelName,
|
||||
method: 'read',
|
||||
args: [resIDs, [field]],
|
||||
context: data.getContext(),
|
||||
}).then(function (records) {
|
||||
if (data.data.length) {
|
||||
var dataType = self.localData[data.data[0]].type;
|
||||
@@ -5123,6 +5125,7 @@ var BasicModel = AbstractModel.extend({
|
||||
var fieldsInfo = view ? view.fieldsInfo : fieldInfo.fieldsInfo;
|
||||
var fields = view ? view.fields : fieldInfo.relatedFields;
|
||||
var viewType = view ? view.type : fieldInfo.viewType;
|
||||
var id2Values = new Map(values.map((value) => [value.id, value]))
|
||||
|
||||
_.each(records, function (record) {
|
||||
var x2mList = self.localData[record.data[fieldName]];
|
||||
@@ -5130,7 +5133,7 @@ var BasicModel = AbstractModel.extend({
|
||||
_.each(x2mList.res_ids, function (res_id) {
|
||||
var dataPoint = self._makeDataPoint({
|
||||
modelName: field.relation,
|
||||
data: _.findWhere(values, {id: res_id}),
|
||||
data: id2Values.get(res_id),
|
||||
fields: fields,
|
||||
fieldsInfo: fieldsInfo,
|
||||
parentID: x2mList.id,
|
||||
|
||||
@@ -49,6 +49,9 @@ var FORMAT_OPTIONS = {
|
||||
var NO_DATA = [_t('No data')];
|
||||
NO_DATA.isNoData = true;
|
||||
|
||||
var FAKE_DATA = [""];
|
||||
FAKE_DATA.isFakeData = true;
|
||||
|
||||
// hide top legend when too many items for device size
|
||||
var MAX_LEGEND_LENGTH = 4 * (Math.max(1, config.device.size_class));
|
||||
|
||||
@@ -720,7 +723,7 @@ return AbstractRenderer.extend({
|
||||
* @returns {string}
|
||||
*/
|
||||
_relabelling: function (label, originIndex) {
|
||||
if (label.isNoData) {
|
||||
if (label.isNoData || label.isFakeData) {
|
||||
return label[0];
|
||||
}
|
||||
var i = this.state.comparisonFieldIndex;
|
||||
@@ -873,7 +876,7 @@ return AbstractRenderer.extend({
|
||||
dataset.pointBackgroundColor = dataset.borderColor;
|
||||
dataset.pointBorderColor = 'rgba(0,0,0,0.2)';
|
||||
});
|
||||
if (data.datasets.length === 1) {
|
||||
if (data.datasets.length === 1 && data.datasets[0].originIndex === 0) {
|
||||
const dataset = data.datasets[0];
|
||||
dataset.fill = 'origin';
|
||||
dataset.backgroundColor = hexToRGBA(COLORS[0], 0.4);
|
||||
@@ -882,7 +885,7 @@ return AbstractRenderer.extend({
|
||||
// center the points in the chart (without that code they are put on the left and the graph seems empty)
|
||||
data.labels = data.labels.length > 1 ?
|
||||
data.labels :
|
||||
Array.prototype.concat.apply([], [[['']], data.labels, [['']]]);
|
||||
Array.prototype.concat.apply([], [[FAKE_DATA], data.labels, [FAKE_DATA]]);
|
||||
|
||||
// prepare options
|
||||
var options = this._prepareOptions(data.datasets.length);
|
||||
|
||||
@@ -219,6 +219,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.oe_kanban_content {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
// ------- Compatibility of old (<= v10) Generic layouts -------
|
||||
|
||||
@@ -169,6 +169,16 @@
|
||||
-moz-transform: scale(0.9999); // Smooth the caret on firefox
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cursor
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@mixin o-grab-cursor() {
|
||||
// Use a custom cursor for the open hand icon as "grab" is not properly
|
||||
// working on Chrome Linux (at least)
|
||||
cursor: url(/web/static/src/img/openhand.cur), grab;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Hovering effects
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -1540,7 +1540,7 @@
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" t-att-value="widget.model"/>
|
||||
<input type="hidden" name="id" value="0"/>
|
||||
<input type="hidden" name="id" t-att-value="widget.res_id or 0"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1738,7 +1738,7 @@
|
||||
<a role="menuitem" href="#" data-menu="support" class="dropdown-item">Support</a>
|
||||
<div role="separator" class="dropdown-divider"/>
|
||||
<a role="menuitem" href="#" data-menu="settings" class="dropdown-item">Preferences</a>
|
||||
<a role="menuitem" href="#" data-menu="account" class="dropdown-item">My flectrahq.com account</a>
|
||||
<a role="menuitem" href="#" data-menu="account" class="dropdown-item">My Flectrahq.com account</a>
|
||||
<a role="menuitem" href="#" data-menu="logout" class="dropdown-item">Log out</a>
|
||||
</t>
|
||||
|
||||
@@ -1858,7 +1858,7 @@
|
||||
|
||||
<t t-name="web.IframeWrapper">
|
||||
<div class="o_preview_iframe_wrapper">
|
||||
<i class="o_iframe_wrapper_spinner fa fa-spinner fa-spin fa-4x" style="color: #2496f6; z-index: 2"/>
|
||||
<i class="o_iframe_wrapper_spinner fa fa-spinner fa-spin fa-4x" style="color: #009EFB; z-index: 2"/>
|
||||
<!--suppress CheckTagEmptyBody -->
|
||||
<iframe src="about:blank" class="o_preview_iframe" style="display:none"></iframe>
|
||||
</div>
|
||||
|
||||
@@ -80,6 +80,41 @@ flectra.define('web.basic_model_tests', function (require) {
|
||||
}, function () {
|
||||
QUnit.module('BasicModel');
|
||||
|
||||
QUnit.test('context is given when using a resequence', async function (assert) {
|
||||
assert.expect(2);
|
||||
delete this.params["res_id"];
|
||||
this.data.product.fields.sequence = {string: "Sequence", type: "integer"};
|
||||
|
||||
const model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/resequence') {
|
||||
assert.deepEqual(args.context, { active_field: 2 },
|
||||
"context should be correct after a resequence");
|
||||
}
|
||||
else if (args.method === "read") {
|
||||
assert.deepEqual(args.kwargs.context, { active_field: 2 },
|
||||
"context should be correct after a 'read' RPC");
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
const params = _.extend(this.params, {
|
||||
context: { active_field: 2 },
|
||||
groupedBy: ['product_id'],
|
||||
fieldNames: ['foo'],
|
||||
});
|
||||
|
||||
model.load(params)
|
||||
.then(function (stateID) {
|
||||
return model.resequence('product', [41, 37], stateID);
|
||||
})
|
||||
.then(function () {
|
||||
model.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('can process x2many commands', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
|
||||
@@ -423,6 +423,76 @@ QUnit.module('Views', {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('fake data in line chart', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const unpatchDate = patchDate(2020, 4, 19, 1, 0, 0);
|
||||
|
||||
this.data.foo.records = [];
|
||||
|
||||
var graph = await createView({
|
||||
View: GraphView,
|
||||
model: "foo",
|
||||
data: this.data,
|
||||
context: { search_default_date_filter: 1, },
|
||||
arch: '<graph type="line">' +
|
||||
'<field name="date"/>' +
|
||||
'</graph>',
|
||||
archs: {
|
||||
'foo,false,search': `
|
||||
<search>
|
||||
<filter name="date_filter" domain="[]" date="date" default_period="third_quarter"/>
|
||||
</search>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
await cpHelpers.toggleComparisonMenu(graph);
|
||||
await cpHelpers.toggleMenuItem(graph, 'Date: Previous period');
|
||||
|
||||
assert.checkLabels(graph, [[''], ['']]);
|
||||
|
||||
unpatchDate();
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no filling color for period of comparison', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const unpatchDate = patchDate(2020, 4, 19, 1, 0, 0);
|
||||
|
||||
this.data.foo.records.forEach((r) => {
|
||||
if (r.date) {
|
||||
r.date = r.date.replace(/\d\d\d\d/, "2019");
|
||||
}
|
||||
});
|
||||
|
||||
var graph = await createView({
|
||||
View: GraphView,
|
||||
model: "foo",
|
||||
data: this.data,
|
||||
context: { search_default_date_filter: 1, },
|
||||
arch: '<graph type="line">' +
|
||||
'<field name="product_id"/>' +
|
||||
'</graph>',
|
||||
archs: {
|
||||
'foo,false,search': `
|
||||
<search>
|
||||
<filter name="date_filter" domain="[]" date="date" default_period="this_year"/>
|
||||
</search>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
await cpHelpers.toggleComparisonMenu(graph);
|
||||
await cpHelpers.toggleMenuItem(graph, 'Date: Previous period');
|
||||
|
||||
assert.checkDatasets(graph, ["data", "backgroundColor"], { data: [4, 2] });
|
||||
|
||||
unpatchDate();
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no content helper after update', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
|
||||
@@ -6896,6 +6896,7 @@ QUnit.module('Views', {
|
||||
if (route === '/web/dataset/resequence') {
|
||||
if (moves === 0) {
|
||||
assert.deepEqual(args, {
|
||||
context: {},
|
||||
model: "foo",
|
||||
ids: [4, 3],
|
||||
offset: 13,
|
||||
@@ -6904,6 +6905,7 @@ QUnit.module('Views', {
|
||||
}
|
||||
if (moves === 1) {
|
||||
assert.deepEqual(args, {
|
||||
context: {},
|
||||
model: "foo",
|
||||
ids: [4, 2],
|
||||
offset: 12,
|
||||
@@ -6912,6 +6914,7 @@ QUnit.module('Views', {
|
||||
}
|
||||
if (moves === 2) {
|
||||
assert.deepEqual(args, {
|
||||
context: {},
|
||||
model: "foo",
|
||||
ids: [2, 4],
|
||||
offset: 12,
|
||||
@@ -6920,6 +6923,7 @@ QUnit.module('Views', {
|
||||
}
|
||||
if (moves === 3) {
|
||||
assert.deepEqual(args, {
|
||||
context: {},
|
||||
model: "foo",
|
||||
ids: [4, 2],
|
||||
offset: 12,
|
||||
|
||||
@@ -533,7 +533,7 @@
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-if="company.external_report_layout_id" t-call="{{company.external_report_layout_id.key}}"><t t-raw="0"/></t>
|
||||
<t t-if="company.external_report_layout_id" t-call="{{company.external_report_layout_id.sudo().key}}"><t t-raw="0"/></t>
|
||||
<t t-else="else" t-call="web.external_layout_standard"><t t-raw="0"/></t>
|
||||
|
||||
</template>
|
||||
|
||||
Reference in new issue
Block a user