itsulu-blog-publisher/addons/itsulu_blog_publisher/views/res_config_settings_views.xml
Nicholas Riegel 0fc4febabf Reorganize codebase into Odoo addon structure per ARCHITECTURE.md
Restructure project files to follow the addon layout:
- Move models to addons/itsulu_blog_publisher/models/
- Move services (LLM providers, routers) to addons/itsulu_blog_publisher/services/
- Move wizards to addons/itsulu_blog_publisher/wizards/
- Move views (XML templates) to addons/itsulu_blog_publisher/views/
- Move data (cron, mail templates) to addons/itsulu_blog_publisher/data/
- Move security (ACL) to addons/itsulu_blog_publisher/security/
- Move tests and factories to addons/itsulu_blog_publisher/tests/
- Move BDD features to addons/itsulu_blog_publisher/features/
- Create __init__.py files for all Python packages

This enables proper Odoo module discovery and import structure.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-29 12:11:42 -04:00

271 lines
16 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_blog_publisher_settings" model="ir.ui.view">
<field name="name">res.config.settings.blog.publisher</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.action_general_configuration"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('settings')]" position="inside">
<div class="app_settings_block" data-string="Blog Publisher"
data-key="itsulu_blog_publisher"
string="Blog Publisher"
data-test-id="settings-blog-publisher">
<!-- ================================================
Content Defaults
================================================ -->
<h2>Content Defaults</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Default Blog</span>
<div class="text-muted">Blog for "Generate Now" when no slot is specified.</div>
<div class="content-group">
<field name="blog_pub_default_blog_id" data-test-id="setting-default-blog"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Default Tone</span>
<div class="text-muted">Writing tone passed to LLM.</div>
<div class="content-group">
<field name="blog_pub_default_tone"/>
</div>
</div>
</div>
</div>
<!-- ================================================
Notification Emails
================================================ -->
<h2>Notification Emails</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Notification Recipients</span>
<div class="text-muted">
Comma-separated email addresses. The user who triggers generation is always added automatically.
Default: nicholasr@itsulu.com, sales@itsulu.com
</div>
<div class="content-group">
<field name="blog_pub_notification_emails"
placeholder="nicholasr@itsulu.com,sales@itsulu.com"
data-test-id="setting-notification-emails"/>
</div>
</div>
</div>
</div>
<!-- ================================================
Default LLM Provider
================================================ -->
<h2>Default LLM Provider</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<field name="blog_pub_default_provider" data-test-id="setting-default-provider"/>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<field name="blog_pub_default_model" data-test-id="setting-default-model"/>
</div>
</div>
</div>
<!-- ================================================
Anthropic Claude
================================================ -->
<h2>🔵 Anthropic Claude</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">API Key / Pro Account Token</span>
<div class="text-muted">
Accepts standard API keys (sk-ant-api03-...) and Claude Pro account
personal API tokens from claude.ai/api. Never stored in plain text.
</div>
<div class="content-group">
<field name="blog_pub_anthropic_api_key"
password="True"
data-test-id="setting-anthropic-key"
placeholder="sk-ant-api03-..."/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Default Anthropic Model</span>
<div class="content-group">
<field name="blog_pub_anthropic_model" data-test-id="setting-anthropic-model"/>
</div>
<button name="action_test_anthropic_connection" type="object"
string="Test Connection" class="btn btn-sm btn-secondary mt8"/>
</div>
</div>
</div>
<!-- ================================================
OpenAI
================================================ -->
<h2>🟢 OpenAI ChatGPT / DALL·E</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">OpenAI API Key</span>
<div class="text-muted">Used for GPT-4o text and DALL·E 3 image generation.</div>
<div class="content-group">
<field name="blog_pub_openai_api_key"
password="True"
data-test-id="setting-openai-key"
placeholder="sk-..."/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<field name="blog_pub_openai_model" data-test-id="setting-openai-model"/>
<button name="action_test_openai_connection" type="object"
string="Test Connection" class="btn btn-sm btn-secondary mt8"/>
</div>
</div>
</div>
<!-- ================================================
Google Gemini
================================================ -->
<h2>🔴 Google Gemini / Imagen</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Gemini API Key</span>
<div class="text-muted">From Google AI Studio (aistudio.google.com).</div>
<div class="content-group">
<field name="blog_pub_gemini_api_key"
password="True"
data-test-id="setting-gemini-key"
placeholder="AIzaSy..."/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<field name="blog_pub_gemini_model" data-test-id="setting-gemini-model"/>
<button name="action_test_gemini_connection" type="object"
string="Test Connection" class="btn btn-sm btn-secondary mt8"/>
</div>
</div>
</div>
<!-- ================================================
Ollama / Open WebUI
================================================ -->
<h2>🟠 Ollama / Open WebUI (Local &amp; Self-Hosted)</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Base URL</span>
<div class="text-muted">
Local Ollama: http://localhost:11434<br/>
Self-hosted Ollama: http://192.168.x.x:11434<br/>
Open WebUI (local): http://localhost:3000<br/>
Open WebUI (server): https://openwebui.yourcompany.com
</div>
<div class="content-group">
<field name="blog_pub_ollama_base_url"
data-test-id="setting-ollama-url"
placeholder="http://localhost:11434"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Default Ollama Model</span>
<div class="text-muted">Must be pulled first: ollama pull mistral</div>
<div class="content-group">
<field name="blog_pub_ollama_model"
data-test-id="setting-ollama-model"
placeholder="mistral"/>
</div>
<button name="action_test_ollama_connection" type="object"
string="Test Connection" class="btn btn-sm btn-secondary mt8"/>
</div>
</div>
</div>
<!-- ================================================
Image Generation
================================================ -->
<h2>🖼 Image Generation</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<field name="blog_pub_default_image_provider" data-test-id="setting-image-provider"/>
<div class="text-muted">Independent from the text LLM. Uses the same API keys as the providers above.</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">Ollama Image Model</span>
<div class="text-muted">Only needed when using Stable Diffusion via Ollama.</div>
<div class="content-group">
<field name="blog_pub_image_ollama_model" placeholder="stable-diffusion"/>
</div>
</div>
</div>
</div>
<!-- ================================================
Prompt Templates
================================================ -->
<h2>✏️ Prompt Templates</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">System Prompt</span>
<div class="text-muted">Persona and output format instructions sent to the LLM.</div>
<field name="blog_pub_system_prompt"
data-test-id="setting-system-prompt"
style="min-height: 100px;"/>
</div>
</div>
<div class="col-12 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">User Prompt Template</span>
<div class="text-muted">
Available variables: {topic}, {blog_name}, {date}, {tone}, {enabled_platforms}
</div>
<field name="blog_pub_user_prompt_template"
data-test-id="setting-user-prompt"
style="min-height: 200px; font-family: monospace;"/>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>