mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-21 10:52:01 +02:00
Initial commit: Core packages
This commit is contained in:
commit
12c29a983b
9512 changed files with 8379910 additions and 0 deletions
193
odoo-bringout-oca-ocb-web/web/static/src/views/model.js
Normal file
193
odoo-bringout-oca-ocb-web/web/static/src/views/model.js
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { useBus, useService } from "@web/core/utils/hooks";
|
||||
import { SEARCH_KEYS } from "@web/search/with_search/with_search";
|
||||
import { buildSampleORM } from "@web/views/sample_server";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
|
||||
import { EventBus, onMounted, onWillStart, onWillUpdateProps, status, useComponent } from "@odoo/owl";
|
||||
|
||||
/**
|
||||
* @typedef {import("@web/search/search_model").SearchParams} SearchParams
|
||||
*/
|
||||
|
||||
export class Model extends EventBus {
|
||||
/**
|
||||
* @param {Object} env
|
||||
* @param {Object} services
|
||||
*/
|
||||
constructor(env, params, services) {
|
||||
super();
|
||||
this.env = env;
|
||||
this.orm = services.orm;
|
||||
this.useSampleModel = false; // will be set to true by the "useModel" hook if necessary
|
||||
this.setup(params, services);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} params
|
||||
* @param {Object} services
|
||||
*/
|
||||
setup(/* params, services */) {}
|
||||
|
||||
/**
|
||||
* @param {SearchParams} searchParams
|
||||
*/
|
||||
async load(/* searchParams */) {}
|
||||
|
||||
/**
|
||||
* This function is meant to be overriden by models that want to implement
|
||||
* the sample data feature. It should return true iff the last loaded state
|
||||
* actually contains data. If not, another load will be done (if the sample
|
||||
* feature is enabled) with the orm service substituted by another using the
|
||||
* SampleServer, to have sample data to display instead of an empty screen.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasData() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is meant to be overriden by models that want to combine
|
||||
* sample data with real groups that exist on the server.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getGroups() {
|
||||
return null;
|
||||
}
|
||||
|
||||
notify() {
|
||||
this.trigger("update");
|
||||
}
|
||||
}
|
||||
Model.services = [];
|
||||
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @returns {SearchParams}
|
||||
*/
|
||||
function getSearchParams(props) {
|
||||
const params = {};
|
||||
for (const key of SEARCH_KEYS) {
|
||||
params[key] = props[key];
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template {Model} T
|
||||
* @param {new (env: Object, params: Object, services: Object) => T} ModelClass
|
||||
* @param {Object} params
|
||||
* @param {Object} [options]
|
||||
* @param {Function} [options.onUpdate]
|
||||
* @returns {T}
|
||||
*/
|
||||
export function useModel(ModelClass, params, options = {}) {
|
||||
const component = useComponent();
|
||||
if (!(ModelClass.prototype instanceof Model)) {
|
||||
throw new Error(`the model class should extend Model`);
|
||||
}
|
||||
const services = {};
|
||||
for (const key of ModelClass.services) {
|
||||
services[key] = useService(key);
|
||||
}
|
||||
services.orm = services.orm || useService("orm");
|
||||
if (services.dialog) {
|
||||
services.dialog = Object.create(services.dialog);
|
||||
const dialogAddOrigin = services.dialog.add;
|
||||
let dialogRequests = [];
|
||||
services.dialog.add = (...args) => {
|
||||
const index = dialogRequests.push(args);
|
||||
return () => {
|
||||
dialogRequests[index] = null;
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
services.dialog.add = dialogAddOrigin;
|
||||
for (const req of dialogRequests) {
|
||||
if (req) {
|
||||
dialogAddOrigin(...req);
|
||||
}
|
||||
}
|
||||
dialogRequests = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (!("isAlive" in params)) {
|
||||
params.isAlive = () => status(component) !== "destroyed";
|
||||
}
|
||||
|
||||
const model = new ModelClass(component.env, params, services);
|
||||
useBus(
|
||||
model,
|
||||
"update",
|
||||
options.onUpdate ||
|
||||
(() => {
|
||||
component.render(true); // FIXME WOWL reactivity
|
||||
})
|
||||
);
|
||||
|
||||
const globalState = component.props.globalState || {};
|
||||
let useSampleModel =
|
||||
component.props.useSampleModel &&
|
||||
(!("useSampleModel" in globalState) || globalState.useSampleModel);
|
||||
model.useSampleModel = !options.ignoreUseSampleModel ? useSampleModel : false;
|
||||
const orm = model.orm;
|
||||
let sampleORM = globalState.sampleORM;
|
||||
const user = useService("user");
|
||||
let started = false;
|
||||
async function load(props) {
|
||||
const searchParams = getSearchParams(props);
|
||||
await model.load(searchParams);
|
||||
if (!options.ignoreUseSampleModel) {
|
||||
if (useSampleModel && !model.hasData()) {
|
||||
sampleORM =
|
||||
sampleORM ||
|
||||
buildSampleORM(component.props.resModel, component.props.fields, user);
|
||||
sampleORM.setGroups(model.getGroups());
|
||||
// Load data with sampleORM then restore real ORM.
|
||||
model.orm = sampleORM;
|
||||
await model.load(searchParams);
|
||||
model.orm = orm;
|
||||
} else {
|
||||
useSampleModel = false;
|
||||
model.useSampleModel = useSampleModel;
|
||||
}
|
||||
}
|
||||
if (started) {
|
||||
model.notify();
|
||||
}
|
||||
}
|
||||
onWillStart(async () => {
|
||||
// FIXME: we have a problem here: in the view, we have two onWillStart:
|
||||
// - 1) to load the subviews that aren't inline
|
||||
// - 2) to load the data
|
||||
// 2) must be done after 1), but we can't sync two onWillStarts
|
||||
// The problem is also there with the relational model, but it isn't visible
|
||||
// in the tests because the load the sub views in a tick, and we look inside
|
||||
// the fieldsInfo after a tick as well. Here, we look into fieldsInfo directly.
|
||||
if (params.beforeLoadProm) {
|
||||
await params.beforeLoadProm;
|
||||
}
|
||||
await load(component.props);
|
||||
started = true;
|
||||
});
|
||||
onWillUpdateProps((nextProps) => {
|
||||
if (!options.ignoreUseSampleModel) {
|
||||
useSampleModel = false;
|
||||
}
|
||||
load(nextProps);
|
||||
});
|
||||
|
||||
useSetupView({
|
||||
getGlobalState() {
|
||||
if (component.props.useSampleModel) {
|
||||
return { sampleORM, useSampleModel };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return model;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue