Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing issues of tour test for awesome_tshirt #1

Open
wants to merge 56 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
efd7bdb
[Solution] 1.1 A counter Component
fdardenne Sep 7, 2022
26109aa
[Solution] 1.2 A Todo Component
fdardenne Sep 7, 2022
8012da4
[Solution] 1.3. Props Validation
fdardenne Sep 7, 2022
8addafd
[Solution] 1.4. A List of todos
fdardenne Sep 7, 2022
943ff9c
[Solution] 1.5. Adding todo
fdardenne Sep 7, 2022
1e915c0
[Solution] 1.6. Focusing the input
fdardenne Sep 7, 2022
0baba48
[Solution] 1.7. Toggling todos
fdardenne Sep 7, 2022
3e1a5d5
[Solution] 1.8 Deleting todos
fdardenne Sep 7, 2022
16e5013
[Solution] 1.9 Generic components with Slots
fdardenne Sep 8, 2022
6adecde
[Solution] 1.10 Miscellaneous small tasks
fdardenne Sep 8, 2022
e9096ae
[Solution] 2.0 Reset the client_action
fdardenne Sep 8, 2022
6ae4a58
[Solution] 2.1. A new Layout
fdardenne Sep 8, 2022
de92f3d
[Solution] 2.2 Add some buttons for quick navigation
fdardenne Sep 8, 2022
f0e5329
[Solution] 2.3 Call the server, add some statistics
fdardenne Sep 9, 2022
93e3c54
[Solution] 2.4 Cache network calls, create a service
fdardenne Sep 9, 2022
a0ddc6a
[Solution] 2.5 Display a pie chart
fdardenne Sep 9, 2022
429ceb7
[Solution] 2.6 Misc
fdardenne Sep 12, 2022
a5e9ad6
[Solution] 3.1 An `image_preview` field
fdardenne Sep 12, 2022
e5e13f6
[Solution] 3.2 Improving the image_preview field
fdardenne Sep 12, 2022
80cb3dc
[Solution] 3.3 Customizing a field component
fdardenne Sep 12, 2022
05c660b
[Solution] 3.4 Message for some customers
fdardenne Sep 12, 2022
9851e33
[Solution] 3.5 use markup
fdardenne Sep 29, 2022
1372e79
[Solution] 3.6 Add buttons in control panel
fdardenne Sep 12, 2022
f6d1d3d
[Solution] 3.7 Auto reload the kanban view
fdardenne Sep 12, 2022
efd0834
[Solution] 4.1 Interacting with the notification system
fdardenne Sep 12, 2022
33ef1e3
[Solution] 4.2 Add a systray item
fdardenne Sep 12, 2022
a846967
[Solution] 4.3 Real life update
fdardenne Sep 12, 2022
8e36404
[Solution] 4.4 Add a command to the command palette
fdardenne Sep 16, 2022
398056c
[Solution] 4.5 Monkey patching a component
fdardenne Sep 19, 2022
023c335
[Solution] 4.6 Fetching orders from a customer
fdardenne Sep 19, 2022
7840198
[Solution] 4.7 Reintroduce Kitten Mode
fdardenne Sep 20, 2022
62cea19
[Solution] 4.8 Lazy loading our dashboard
fdardenne Sep 20, 2022
5de3211
[Solution] 5.1 Create a new kanban view
fdardenne Sep 20, 2022
e71b0ba
[Solution] 5.2 Create a CustomerList component
fdardenne Sep 21, 2022
dce197f
[Solution] 5.3 Load and display data
fdardenne Sep 23, 2022
f5e0c10
[Solution] 5.4 Update the main kanban view
fdardenne Sep 23, 2022
f1c3d05
[Solution] 5.5 Only display customers which have an active order
fdardenne Sep 23, 2022
8f21263
[Solution] 5.6 Add a search bar to Customer List
fdardenne Sep 23, 2022
8200dc1
[Solution] 5.7 Refactor the code to use t-model
fdardenne Sep 30, 2022
3849365
[Solution] 5.8 Paginate customers!
fdardenne Sep 29, 2022
34f5458
[Solution] 6.1 Make a hello world view
fdardenne Sep 27, 2022
5d848ae
[Solution] 6.2 Use the Layout component
fdardenne Sep 27, 2022
040cbdd
[Solution] 6.3 Parse the arch
fdardenne Sep 27, 2022
daddde0
[Solution] 6.4 Load some data
fdardenne Sep 27, 2022
19501fa
[Solution] 6.5 Reorganize code
fdardenne Sep 28, 2022
c508235
[Solution] 6.6 Display images
fdardenne Sep 28, 2022
bed60e0
[Solution] 6.7 Switch to form view on click
fdardenne Sep 29, 2022
4e1735f
[Solution] 6.8 Add an optional tooltip
fdardenne Sep 29, 2022
c28bce4
[Solution] 6.9 Add pagination
fdardenne Sep 29, 2022
ca77b94
[Solution] 6.10 Validating views
fdardenne Sep 30, 2022
bd8c852
[Solution] 7.1 Integration testing
fdardenne Oct 3, 2022
80e934f
[Solution] 7.2 Unit testing a Component
fdardenne Oct 4, 2022
6d15225
[Solution] 7.3 Unit testing our gallery view
fdardenne Oct 4, 2022
6309ff6
remove ref to readonly mode in 3.2
ged-odoo Oct 11, 2022
0b395ff
Fixing issues of tour test for awesome_tshirt
Oct 14, 2022
2a507c0
Fixing wrong name for tour step
Oct 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions awesome_gallery/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# -*- coding: utf-8 -*-
from . import models
from . import validation
1 change: 1 addition & 0 deletions awesome_gallery/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'data': [],
'assets': {
'web.assets_backend': [
'awesome_gallery/static/tests/**/*',
'awesome_gallery/static/src/**/*',
],
},
Expand Down
17 changes: 17 additions & 0 deletions awesome_gallery/rng/gallery.rng
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:a="http://relaxng.org/ns/annotation/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<rng:define name="gallery">
<rng:element name="gallery">
<rng:attribute name="image_field"/>
<rng:optional><rng:attribute name="tooltip_field"/></rng:optional>
<rng:optional><rng:attribute name="limit"/></rng:optional>
</rng:element>
</rng:define>
<rng:start>
<rng:choice>
<rng:ref name="gallery" />
</rng:choice>
</rng:start>
</rng:grammar>
17 changes: 17 additions & 0 deletions awesome_gallery/static/src/gallery_arch_parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** @odoo-module */

import { XMLParser } from "@web/core/utils/xml";

export class GalleryArchParser extends XMLParser {
parse(arch) {
const xmlDoc = this.parseXML(arch);
const imageField = xmlDoc.getAttribute("image_field");
const limit = xmlDoc.getAttribute("limit") || 80;
const tooltipField = xmlDoc.getAttribute("tooltip_field");
return {
imageField,
limit,
tooltipField,
};
}
}
50 changes: 50 additions & 0 deletions awesome_gallery/static/src/gallery_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/** @odoo-module */

import { Layout } from "@web/search/layout";
import { useService } from "@web/core/utils/hooks";
import { usePager } from "@web/search/pager_hook";

const { Component, onWillStart, onWillUpdateProps, useState } = owl;

export class GalleryController extends Component {
setup() {
this.orm = useService("orm");

this.model = useState(
new this.props.Model(
this.orm,
this.props.resModel,
this.props.fields,
this.props.archInfo,
this.props.domain
)
);

usePager(() => {
return {
offset: this.model.pager.offset,
limit: this.model.pager.limit,
total: this.model.recordsLength,
onUpdate: async ({ offset, limit }) => {
this.model.pager.offset = offset;
this.model.pager.limit = limit;
await this.model.load();
},
};
});

onWillStart(async () => {
await this.model.load();
});

onWillUpdateProps(async (nextProps) => {
if (JSON.stringify(nextProps.domain) !== JSON.stringify(this.props.domain)) {
this.model.domain = nextProps.domain;
await this.model.load();
}
});
}
}

GalleryController.template = "awesome_gallery.View";
GalleryController.components = { Layout };
8 changes: 8 additions & 0 deletions awesome_gallery/static/src/gallery_controller.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="awesome_gallery.View" owl="1">
<Layout display="props.display" className="'h-100 overflow-auto'">
<t t-component="props.Renderer" images="model.images" imageField="model.imageField" tooltipField="model.tooltipField"/>
</Layout>
</t>
</templates>
24 changes: 24 additions & 0 deletions awesome_gallery/static/src/gallery_image/gallery_image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/** @odoo-module */

const { Component } = owl;
import { useTooltip } from "@web/core/tooltip/tooltip_hook";

export class GalleryImage extends Component {
setup() {
useTooltip("tooltip", {
tooltip: this.props.image[this.props.tooltipField],
});
}
onClick() {
this.props.onClick(this.props.image.id);
}
}

GalleryImage.template = "awesome_gallery.GalleryImage";
GalleryImage.props = {
image: { type: Object },
className: { type: String },
imageField: { type: String },
tooltipField: { type: String },
onClick: { type: Function },
};
9 changes: 9 additions & 0 deletions awesome_gallery/static/src/gallery_image/gallery_image.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="awesome_gallery.GalleryImage" owl="1">
<div t-att-class="props.className" t-on-click="onClick">
<img t-if="props.image[props.imageField]" class="img-thumbnail" t-att-src="props.image[props.imageField]" t-ref="tooltip"/>
<div t-else="" class="p-5 bg-white border" t-ref="tooltip"></div>
</div>
</t>
</templates>
56 changes: 56 additions & 0 deletions awesome_gallery/static/src/gallery_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/** @odoo-module */

import { KeepLast } from "@web/core/utils/concurrency";

export class GalleryModel {
constructor(orm, resModel, fields, archInfo, domain) {
this.orm = orm;
this.resModel = resModel;
const { imageField, limit, tooltipField } = archInfo;
this.imageField = imageField;
this.fields = fields;
this.limit = limit;
this.domain = domain;
this.tooltipField = tooltipField;
this.keepLast = new KeepLast();
this.pager = { offset: 0, limit: limit };
if (!(imageField in this.fields)) {
throw `image_field error: ${imageField} is not a field of ${resModel}`;
}
if (!(tooltipField in this.fields)) {
throw `image_field error: ${tooltipField} is not a field of ${resModel}`;
}
}

async load() {
const { length, records } = await this.keepLast.add(
this.orm.webSearchRead(
this.resModel,
this.domain,
[this.imageField, this.tooltipField],
{
limit: this.pager.limit,
offset: this.pager.offset,
}
)
);
this.recordsLength = length;

switch (this.fields[this.tooltipField].type) {
case "many2one":
this.images = records.map((record) => ({
...record,
[this.tooltipField]: record[this.tooltipField][1],
}));
break;
case "integer":
this.images = records.map((record) => ({
...record,
[this.tooltipField]: String(record[this.tooltipField]),
}));
break;
default:
this.images = records;
}
}
}
17 changes: 17 additions & 0 deletions awesome_gallery/static/src/gallery_renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
const { Component } = owl;
import { GalleryImage } from "./gallery_image/gallery_image";

export class GalleryRenderer extends Component {
setup() {
this.action = useService("action");
}

onImageClick(resId) {
this.action.switchView("form", { resId });
}
}

GalleryRenderer.components = { GalleryImage };
GalleryRenderer.template = "awesome_gallery.Renderer";
10 changes: 10 additions & 0 deletions awesome_gallery/static/src/gallery_renderer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="awesome_gallery.Renderer" owl="1">
<div class="row">
<t t-foreach="props.images" t-as="image" t-key="image.id">
<GalleryImage image="image" imageField="props.imageField" tooltipField="props.tooltipField" className="'col-3'" onClick.bind="onImageClick"/>
</t>
</div>
</t>
</templates>
33 changes: 33 additions & 0 deletions awesome_gallery/static/src/gallery_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/** @odoo-module */

import { registry } from "@web/core/registry";
import { GalleryController } from "./gallery_controller";
import { GalleryArchParser } from "./gallery_arch_parser";
import { GalleryModel } from "./gallery_model";
import { GalleryRenderer } from "./gallery_renderer";

export const galleryView = {
type: "gallery",
display_name: "Gallery",
icon: "fa fa-picture-o",
multiRecord: true,
Controller: GalleryController,
ArchParser: GalleryArchParser,
Model: GalleryModel,
Renderer: GalleryRenderer,

props(genericProps, view) {
const { ArchParser } = view;
const { arch } = genericProps;
const archInfo = new ArchParser().parse(arch);

return {
...genericProps,
Model: view.Model,
Renderer: view.Renderer,
archInfo,
};
},
};

registry.category("views").add("gallery", galleryView);
73 changes: 73 additions & 0 deletions awesome_gallery/static/tests/gallery_view_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/** @odoo-module **/

import { click, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils";
import { registry } from "@web/core/registry";
import { tooltipService } from "@web/core/tooltip/tooltip_service";
import { uiService } from "@web/core/ui/ui_service";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { actionService } from "@web/webclient/actions/action_service";

const serviceRegistry = registry.category("services");

let serverData;
let target;

QUnit.module("Views", (hooks) => {
hooks.beforeEach(() => {
serverData = {
models: {
order: {
fields: {
image_url: { string: "Image", type: "char" },
description: { string: "Description", type: "char" },
},
records: [
{
id: 1,
image_url: "",
description: "A nice description",
},
{
id: 2,
image_url: "",
description: "A second nice description",
},
],
},
},
views: {},
};
setupViewRegistries();
serviceRegistry.add("tooltip", tooltipService);
target = getFixture();
serviceRegistry.add("ui", uiService);
});

QUnit.module("GalleryView");

QUnit.test("open record on image click", async function (assert) {
assert.expect(3);

patchWithCleanup(actionService, {
start() {
const result = this._super(...arguments);
return {
...result,
switchView(viewType, { resId }) {
assert.step(JSON.stringify({ viewType, resId }));
},
};
},
});

await makeView({
type: "gallery",
resModel: "order",
serverData,
arch: '<gallery image_field="image_url" tooltip_field="description"/>',
});
assert.containsOnce(target, ".o_control_panel");
await click(target, ".row > div:nth-child(1) > div");
assert.verifySteps([`{"viewType":"form","resId":1}`]);
});
});
32 changes: 32 additions & 0 deletions awesome_gallery/validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
import logging
import os

from lxml import etree

from odoo.loglevels import ustr
from odoo.tools import misc, view_validation

_logger = logging.getLogger(__name__)

_gallery_validator = None


@view_validation.validate('gallery')
def schema_gallery(arch, **kwargs):
""" Check the gallery view against its schema

:type arch: etree._Element
"""
global _gallery_validator

if _gallery_validator is None:
with misc.file_open(os.path.join('awesome_gallery', 'rng', 'gallery.rng')) as f:
_gallery_validator = etree.RelaxNG(etree.parse(f))

if _gallery_validator.validate(arch):
return True

for error in _gallery_validator.error_log:
_logger.error(ustr(error))
return False
1 change: 1 addition & 0 deletions awesome_tshirt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from . import controllers
from . import models
from . import tests
12 changes: 12 additions & 0 deletions awesome_tshirt/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@
'assets': {
'web.assets_backend': [
'awesome_tshirt/static/src/**/*',
'awesome_tshirt/static/tests/**/*',
('remove', 'awesome_tshirt/static/src/dashboard/**/*'),
],
'awesome_tshirt.dashboard': [
# To include bootstrap scss variables
("include", 'web._assets_helpers'),
('include', 'web._assets_backend_helpers'),
'awesome_tshirt/static/src/dashboard/**/*',
],
'web.order_tests': [
("include", 'web.assets_frontend'),
'awesome_tshirt/static/tests/**/*',
],
}
}
Loading