first push message
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="dashboard_template" name="Survey Dashboard">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="title">Dashboard: <t t-esc="survey.title"/></t>
|
||||
<!-- Load Chart.js CDN -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
</t>
|
||||
|
||||
<!-- ✅ Data is passed here via data-questions-json attribute -->
|
||||
<div id="dashboard-root"
|
||||
t-att-data-questions-json="questions_json"
|
||||
class="container-fluid py-4">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4 border-bottom pb-3">
|
||||
<div>
|
||||
<h2 class="mb-2"><t t-esc="survey.title"/></h2>
|
||||
<span class="badge bg-primary me-2">Responses: <t t-esc="total_responses"/></span>
|
||||
<span class="badge bg-success">Completion: <t t-esc="completion_rate"/>%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons: NO onclick attributes -->
|
||||
<div class="mb-3 d-flex gap-2">
|
||||
<button type="button" class="btn btn-primary active" id="btn-list">
|
||||
<i class="fa fa-list me-1"/> List
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" id="btn-pie">
|
||||
<i class="fa fa-pie-chart me-1"/> Pie Chart
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" id="btn-bar">
|
||||
<i class="fa fa-bar-chart me-1"/> Bar Graph
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Question Selector -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Select Question:</label>
|
||||
<select class="form-select" id="question-selector" style="max-width: 600px;">
|
||||
<t t-foreach="questions" t-as="q" t-if="q.get('type') == 'question'">
|
||||
<option t-att-value="q.get('id')">
|
||||
<t t-esc="q.get('title')"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Content Area -->
|
||||
<div class="dashboard-scroll-wrapper" style="max-height: calc(100vh - 250px); overflow-y: auto;">
|
||||
<!-- List View -->
|
||||
<div id="view-list" class="view-section">
|
||||
<t t-foreach="questions" t-as="q">
|
||||
<t t-if="q.get('type') == 'page'">
|
||||
<h3 class="h4 mt-4 mb-3 text-primary border-top pt-3"><t t-esc="q.get('title')"/></h3>
|
||||
</t>
|
||||
<t t-elif="q.get('type') == 'question'">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header d-flex justify-content-between">
|
||||
<strong><t t-esc="q.get('title')"/></strong>
|
||||
<span class="badge bg-secondary"><t t-esc="q.get('qtype')"/></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<t t-if="q.get('stats')">
|
||||
<t t-foreach="q.get('stats')" t-as="stat">
|
||||
<div class="mb-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span><t t-esc="stat.get('label')"/></span>
|
||||
<span><t t-esc="stat.get('count')"/> (<t t-esc="stat.get('percent')"/>%)</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 15px;">
|
||||
<div class="progress-bar bg-primary" t-att-style="'width: ' + str(stat.get('percent', 0)) + '%'"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<!-- Chart Views -->
|
||||
<div id="view-pie" class="view-section d-none">
|
||||
<div class="card"><div class="card-body"><canvas id="pieChart" style="max-height: 400px;"></canvas></div></div>
|
||||
</div>
|
||||
<div id="view-bar" class="view-section d-none">
|
||||
<div class="card"><div class="card-body"><canvas id="barChart" style="max-height: 400px;"></canvas></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- 🔹 Server Action: Dynamic URL with selected survey ID -->
|
||||
<record id="action_survey_dashboard_dynamic" model="ir.actions.server">
|
||||
<field name="name">Open Survey Dashboard</field>
|
||||
<field name="model_id" ref="survey.model_survey_survey"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code"><![CDATA[
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': f'/survey/dashboard/{records[0].id}',
|
||||
'target': 'self',
|
||||
}
|
||||
else:
|
||||
# Show survey selector - using VALID fields only
|
||||
action = {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'survey.survey',
|
||||
'view_mode': 'list,form',
|
||||
'name': 'Select a Survey',
|
||||
'domain': [
|
||||
('active', '=', True),
|
||||
('user_input_ids', '!=', False)
|
||||
],
|
||||
'context': {'search_default_finished': 1},
|
||||
'help': "Select an active survey with responses to view its dashboard.",
|
||||
}
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
<!-- 🔹 Top-Level Menu: Surveys -->
|
||||
<menuitem id="menu_survey_root" name="Dashboard Surveys" sequence="10" web_icon="survey,static/description/icon.png"/>
|
||||
|
||||
<!-- 🔹 Sub-Menu: Dashboard -->
|
||||
<menuitem id="menu_survey_dashboard"
|
||||
name="📊 Survey Dashboard"
|
||||
parent="menu_survey_root"
|
||||
action="action_survey_dashboard_dynamic"
|
||||
sequence="5"
|
||||
groups="survey.group_survey_manager,survey.group_survey_user"/>
|
||||
|
||||
<!-- 🔹 Optional: Keep "See Results" button on form -->
|
||||
<record id="survey_form_inherit_dashboard" model="ir.ui.view">
|
||||
<field name="name">survey.survey.form.inherit.dashboard</field>
|
||||
<field name="model">survey.survey</field>
|
||||
<field name="inherit_id" ref="survey.survey_survey_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Option A: Add button AFTER existing results button (safer) -->
|
||||
<xpath expr="//button[@name='action_result_survey']" position="after">
|
||||
<button name="%(dashboard_survey.action_survey_dashboard_dynamic)d"
|
||||
type="action"
|
||||
string="📊 Dashboard"
|
||||
class="btn btn-secondary ms-2"
|
||||
icon="fa-chart-bar"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Option B: Replace (uncomment if you want to replace) -->
|
||||
<!--
|
||||
<xpath expr="//button[@name='action_result_survey']" position="replace">
|
||||
<button name="%(dashboard_survey.action_survey_dashboard_dynamic)d"
|
||||
type="action"
|
||||
string="📊 See Dashboard"
|
||||
class="oe_stat_button"
|
||||
icon="fa-dashboard"/>
|
||||
</xpath>
|
||||
-->
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,24 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<!--
|
||||
<template id="listing">
|
||||
<ul>
|
||||
<li t-foreach="objects" t-as="object">
|
||||
<a t-attf-href="#{ root }/objects/#{ object.id }">
|
||||
<t t-esc="object.display_name"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
<template id="object">
|
||||
<h1><t t-esc="object.display_name"/></h1>
|
||||
<dl>
|
||||
<t t-foreach="object._fields" t-as="field">
|
||||
<dt><t t-esc="field"/></dt>
|
||||
<dd><t t-esc="object[field]"/></dd>
|
||||
</t>
|
||||
</dl>
|
||||
</template>
|
||||
-->
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_survey_qa_tree" model="ir.ui.view">
|
||||
<field name="name">survey.user.input.line.tree.qa</field>
|
||||
<field name="model">survey.user_input.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Survey Answers" create="0" edit="0" delete="0">
|
||||
<field name="survey_id"/>
|
||||
<field name="question_id"/>
|
||||
<field name="display_answer"/>
|
||||
<field name="answer_is_correct" widget="boolean_circle"/>
|
||||
<field name="user_input_id" optional="hide"/>
|
||||
<field name="create_date" optional="show"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<!-- 🔹 GRAPH VIEW -->
|
||||
<record id="view_survey_qa_graph" model="ir.ui.view">
|
||||
<field name="name">survey.user.input.line.graph.qa</field>
|
||||
<field name="model">survey.user_input.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Survey Q and A Distribution" type="bar">
|
||||
<field name="question_id" type="col"/>
|
||||
<field name="display_answer" type="row"/>
|
||||
<field name="id" type="measure" string="Responses"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 🔹 PIVOT VIEW -->
|
||||
<record id="view_survey_qa_pivot" model="ir.ui.view">
|
||||
<field name="name">survey.user.input.line.pivot.qa</field>
|
||||
<field name="model">survey.user_input.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Survey QA Breakdown" disable_linking="1">
|
||||
<field name="survey_id" type="col"/>
|
||||
<field name="question_id" type="row"/>
|
||||
<field name="display_answer" type="row"/>
|
||||
<!-- ✅ Same measure, works flawlessly in v19 -->
|
||||
<!-- <field name="response_count" type="measure" string="Count"/>-->
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 🔹 ACTION & MENU -->
|
||||
<record id="action_survey_qa_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Survey Q A Dashboard</field>
|
||||
<field name="res_model">survey.user_input.line</field>
|
||||
<field name="view_mode">list,graph,pivot</field>
|
||||
<!-- ✅ FIXED: Filter by completed responses only -->
|
||||
<field name="domain">[('user_input_id.state', '=', 'done'), ('user_input_id.test_entry', '=', False)]</field>
|
||||
<field name="context">{'search_default_group_by_question': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No survey answers yet. Collect completed responses to see QA analytics.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_survey_qa_dashboard"
|
||||
name="Q and A Dashboard"
|
||||
parent="survey.menu_surveys"
|
||||
action="action_survey_qa_dashboard"
|
||||
sequence="50"/>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user