Files
one-os-dev-wayland-html5-co…/models/compositor_session_views.xml
T
1b-agent 93a5a0a221 Initial commit: one_os_compositor Odoo 20 addon — core OWL library + backend models + JWT auth
Includes:
- compositor.app, compositor.session, compositor.session.app, compositor.audit.log models
- /web/compositor/{token,apps,launch,audit} HTTP controllers with JWT (HS256)
- CompositorService OWL service (reusable via useService('compositor'))
- CompositorCanvas OWL component (reusable canvas wrapper)
- Security: compositor_group_user, compositor_group_manager groups + ir.access.csv rules
- 5 demo apps pre-loaded (gnome-calculator, xterm, gtk4-demo, glxgears, featherpad)
- Audit log capturing JWT issuance + app launch events
- Stub mode: launching apps returns a stub SurfaceHandle when proxy isn't connected
- Tested against Odoo 20 + PostgreSQL 17

Author: 1bspace.com
Parent company: 1B Global
License: Proprietary (1B Space internal use)
2026-10-08 08:48:46 +00:00

141 lines
8.3 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- ─── Session List View ─────────────────────────────────────── -->
<record id="view_compositor_session_list" model="ir.ui.view">
<field name="name">compositor.session.list</field>
<field name="model">compositor.session</field>
<field name="arch" type="xml">
<list string="Compositor Sessions">
<field name="compositor_session_id"/>
<field name="user_id"/>
<field name="state" widget="badge"
decoration-success="state == 'active'"
decoration-warning="state == 'disconnected'"
decoration-danger="state == 'closed'"
decoration-info="state == 'pending'"/>
<field name="running_app_count" string="Apps"/>
<field name="started_at"/>
<field name="last_activity"/>
<field name="duration_seconds" widget="float_time" string="Duration"/>
</list>
</field>
</record>
<!-- ─── Session Form View ─────────────────────────────────────── -->
<record id="view_compositor_session_form" model="ir.ui.view">
<field name="name">compositor.session.form</field>
<field name="model">compositor.session</field>
<field name="arch" type="xml">
<form string="Compositor Session">
<header>
<button name="action_close" string="Close Session" type="object"
class="btn-danger"
confirm="This will terminate all running apps. Continue?"
invisible="state == 'closed'"/>
<button name="action_reconnect" string="Mark Reconnected" type="object"
class="btn-secondary"
invisible="state not in ['disconnected', 'closed']"/>
<field name="state" widget="statusbar"
statusbar_visible="pending,active,disconnected,closed"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_view_app_instances" type="object"
class="oe_stat_button" icon="fa-desktop">
<field name="running_app_count" widget="statinfo"
string="Running Apps"/>
</button>
<button name="action_view_app_instances" type="object"
class="oe_stat_button" icon="fa-list">
<field name="app_count" widget="statinfo" string="Total Apps"/>
</button>
</div>
<group>
<group>
<field name="compositor_session_id" readonly="1"/>
<field name="user_id" readonly="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group>
<field name="proxy_url" readonly="1"/>
<field name="wayland_display" readonly="1"/>
<field name="proxy_pid" readonly="1"/>
</group>
</group>
<group>
<group string="Timing">
<field name="started_at" readonly="1"/>
<field name="last_activity" readonly="1"/>
<field name="ended_at" readonly="1"/>
<field name="duration_seconds" widget="float_time" readonly="1"/>
</group>
<group string="JWT">
<field name="last_jwt_issued_at" readonly="1"/>
<field name="last_jwt_expires_at" readonly="1"/>
</group>
</group>
<notebook>
<page string="App Instances" name="app_instances">
<field name="app_instance_ids" context="{'default_session_id': id}">
<list>
<field name="app_id"/>
<field name="title"/>
<field name="state" widget="badge"
decoration-success="state == 'running'"
decoration-info="state == 'launching'"
decoration-danger="state == 'crashed'"
decoration-muted="state == 'terminated'"/>
<field name="pid"/>
<field name="started_at"/>
<field name="ended_at"/>
<button name="action_terminate" type="object" string="Terminate"
class="btn-danger btn-sm" icon="fa-stop"
invisible="state not in ['launching', 'running']"/>
<button name="action_force_kill" type="object" string="Force Kill"
class="btn-danger btn-sm" icon="fa-times"
invisible="state not in ['launching', 'running']"/>
</list>
</field>
</page>
<page string="Audit Log" name="audit_log">
<field name="message_ids" context="{'default_session_id': id}"/>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!-- ─── Session Search View ───────────────────────────────────── -->
<record id="view_compositor_session_search" model="ir.ui.view">
<field name="name">compositor.session.search</field>
<field name="model">compositor.session</field>
<field name="arch" type="xml">
<search string="Compositor Sessions">
<field name="compositor_session_id"/>
<field name="user_id"/>
<filter name="active" string="Active" domain="[('state', '=', 'active')]"/>
<filter name="disconnected" string="Disconnected" domain="[('state', '=', 'disconnected')]"/>
<filter name="my_sessions" string="My Sessions" domain="[('user_id', '=', uid)]"/>
<separator/>
<filter name="group_user" string="User" context="{'group_by': 'user_id'}"/>
<filter name="group_state" string="State" context="{'group_by': 'state'}"/>
</search>
</field>
</record>
<!-- ─── Action ────────────────────────────────────────────────── -->
<record id="action_compositor_session" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">compositor.session</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="view_compositor_session_search"/>
</record>
</data>
</odoo>