Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,53 @@
/** @odoo-module **/
import {useOpenX2ManyRecord, useX2ManyCrud} from "@web/views/fields/relational_utils";
import {AutomationKanbanRenderer} from "../../views/automation_kanban/automation_kanban_renderer.esm";
import {X2ManyField} from "@web/views/fields/x2many/x2many_field";
import {registry} from "@web/core/registry";
const {useSubEnv} = owl;
export class AutomationActivity extends X2ManyField {
setup() {
super.setup();
useSubEnv({
onAddActivity: this.onAdd.bind(this),
});
const {saveRecord, updateRecord} = useX2ManyCrud(
() => this.list,
this.isMany2Many
);
const openRecord = useOpenX2ManyRecord({
resModel: this.list.resModel,
activeField: this.activeField,
activeActions: this.activeActions,
getList: () => this.list,
saveRecord: async (record) => {
await saveRecord(record);
await this.props.record.save();
},
updateRecord,
withParentId: this.activeField.widget !== "many2many",
});
this._openRecord = (params) => {
const activeElement = document.activeElement;
openRecord({
...params,
onClose: async () => {
if (activeElement) {
activeElement.focus();
}
await this.props.record.save();
this.props.record.model.notify();
},
});
};
}
}
AutomationActivity.components = {
...AutomationActivity.components,
KanbanRenderer: AutomationKanbanRenderer,
};
registry.category("fields").add("automation_step", AutomationActivity);

View file

@ -0,0 +1,104 @@
/** @odoo-module **/
/* global Chart*/
import {loadJS} from "@web/core/assets";
import {registry} from "@web/core/registry";
import {standardFieldProps} from "@web/views/fields/standard_field_props";
const {Component, onWillStart, useEffect, useRef} = owl;
export class AutomationGraph extends Component {
setup() {
this.chart = null;
this.canvasRef = useRef("canvas");
onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js"));
useEffect(() => {
this.renderChart();
return () => {
if (this.chart) {
this.chart.destroy();
}
};
});
}
_getChartConfig() {
return {
type: "line",
data: {
labels: this.props.value.done.map(function (pt) {
return pt.x;
}),
datasets: [
{
backgroundColor: "#4CAF5080",
borderColor: "#4CAF50",
data: this.props.value.done,
fill: "start",
label: this.env._t("Done"),
borderWidth: 2,
},
{
backgroundColor: "#F4433680",
borderColor: "#F44336",
data: this.props.value.error,
fill: "start",
label: this.env._t("Error"),
borderWidth: 2,
},
],
},
options: {
legend: {display: false},
layout: {
padding: {left: 10, right: 10, top: 10, bottom: 10},
},
scales: {
yAxes: [
{
type: "linear",
display: false,
ticks: {
beginAtZero: true,
},
},
],
xAxes: [
{
ticks: {
maxRotation: 0,
},
},
],
},
maintainAspectRatio: false,
elements: {
line: {
tension: 0.000001,
},
},
tooltips: {
intersect: false,
position: "nearest",
caretSize: 0,
borderWidth: 2,
},
},
};
}
renderChart() {
if (this.chart) {
this.chart.destroy();
}
var config = this._getChartConfig();
this.chart = new Chart(this.canvasRef.el, config);
Chart.animationService.advance();
}
}
AutomationGraph.template = "automation_oca.AutomationGraph";
AutomationGraph.props = {
...standardFieldProps,
};
registry.category("fields").add("automation_graph", AutomationGraph);

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates id="template" xml:space="preserve">
<t t-name="automation_oca.AutomationGraph" owl="1">
<div class="o_automation_graph w-100" t-att-class="props.className">
<canvas t-ref="canvas" />
</div>
</t>
</templates>

View file

@ -0,0 +1,128 @@
.o_automation_kanban {
.o_kanban_renderer.o_kanban_ungrouped .o_kanban_record {
flex: 0 0 100%;
width: unset;
margin: 0px;
> div {
border: none;
}
.o_automation_kanban_box {
display: flex;
.o_automation_kanban_card {
width: 600px;
max-width: 600px;
}
.o_automation_kanban_extra {
flex-direction: column;
width: 10rem;
}
.o_automation_kanban_position_line {
border-right: 3px dotted $gray-300;
top: -0.5rem;
bottom: 0.5rem;
width: 8.75rem;
position: absolute;
}
.o_automation_kanban_card_position {
position: absolute;
top: 1.5rem;
text-align: right;
width: 9.125rem;
}
.o_automation_kanban_time {
flex-direction: column;
.o_automation_kanban_time_info {
border: 1px solid $gray-300;
width: 7rem;
}
}
.o_automation_kanban_card {
border: 1px solid $gray-300;
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
flex-direction: column;
.o_automation_kanban_header {
position: relative;
.o_automation_kanban_header_icon {
display: inline-block;
padding: 3px 7px;
margin: 5px;
width: 28px;
height: 28px;
color: white;
font-size: 14px;
border-radius: 3px;
}
.o_automation_kanban_header_title {
display: inline-block;
position: absolute;
top: auto;
left: auto;
bottom: auto;
right: auto;
}
.o_automation_kanban_header_actions {
position: absolute;
top: 0px;
left: auto;
bottom: auto;
right: 0px;
}
}
.o_automation_kanban_graph {
.o_automation_kpi_processed {
color: #4caf50;
}
.o_automation_kpi_error {
color: #f44336;
}
}
.o_automation_kanban_child_add {
.o_automation_kanban_child_add_title {
padding: 2px;
}
.o_automation_kanban_child_add_buttons {
display: none;
}
}
.o_automation_kanban_child_add:hover {
.o_automation_kanban_child_add_buttons {
display: flex;
.o_automation_kanban_child_add_button {
cursor: pointer;
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
flex-direction: column;
border: 1px solid $gray-300;
}
}
}
.o_automation_kanban_states {
display: flex;
.o_automation_kanban_state {
padding: 0.5rem;
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
flex-direction: column;
border-top: 1px solid $gray-300;
border-right: 1px solid $gray-300;
text-align: center;
}
.o_automation_kanban_state:last-child {
border-right: none;
}
}
}
}
}
}
.o_field_automation_graph {
width: 100%;
}
.filter-left {
text-align: left;
}

View file

@ -0,0 +1,22 @@
/** @odoo-module */
import {KanbanCompiler} from "@web/views/kanban/kanban_compiler";
export class AutomationKanbanCompiler extends KanbanCompiler {
setup() {
super.setup();
this.compilers.push({
selector: ".o_automation_kanban_child_add_button[t-att-trigger-type]",
fn: this.compileHierarchyAddButton,
});
}
compileHierarchyAddButton(el) {
el.setAttribute(
"t-on-click",
"() => this.addNewChild({trigger_type: " +
el.getAttribute("t-att-trigger-type") +
"})"
);
return el;
}
}

View file

@ -0,0 +1,17 @@
/** @odoo-module */
import {AutomationKanbanCompiler} from "./automation_kanban_compiler.esm";
import {KanbanRecord} from "@web/views/kanban/kanban_record";
export class AutomationKanbanRecord extends KanbanRecord {
addNewChild(params) {
this.env.onAddActivity({
context: {
default_parent_id: this.props.record.data.id,
default_trigger_type: params.trigger_type,
},
});
}
}
AutomationKanbanRecord.Compiler = AutomationKanbanCompiler;

View file

@ -0,0 +1,38 @@
/** @odoo-module */
import {AutomationKanbanRecord} from "./automation_kanban_record.esm";
import {KanbanRenderer} from "@web/views/kanban/kanban_renderer";
export class AutomationKanbanRenderer extends KanbanRenderer {
/*
Here we are going to reorder the items in the proper way and
we will show the items with the proper padding
*/
getGroupsOrRecords() {
return this._sortRecordsHierarchy(this.props.list.records, false).map(
(record) => ({
record,
key: record.id,
})
);
}
_sortRecordsHierarchy(records, parent_id) {
return records.flatMap((record) => {
if (!record.data.id) {
return [];
}
if (record.data.parent_id && record.data.parent_id[0] !== parent_id) {
return [];
}
if (!record.data.parent_id && parent_id) {
return [];
}
return [record, ...this._sortRecordsHierarchy(records, record.data.id)];
});
}
}
AutomationKanbanRenderer.components = {
...AutomationKanbanRenderer.components,
KanbanRecord: AutomationKanbanRecord,
};