feat: category filter dropdown on unmatched Odoo products panel
Filter by Odoo product category or clear filter. Backend supports both include and exclude category filtering. Loads all categories on init for the dropdown. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -644,6 +644,21 @@ html[style*="color-scheme: dark"] {
|
||||
box-shadow: 0 0 0 2px var(--woo-accent-glow);
|
||||
}
|
||||
|
||||
/* Category filter dropdown */
|
||||
.woo-filter-select {
|
||||
padding: 3px 8px;
|
||||
border: 1px solid var(--woo-input-border);
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
background: var(--woo-input-bg);
|
||||
color: var(--woo-text-primary);
|
||||
max-width: 200px;
|
||||
}
|
||||
.woo-filter-select option {
|
||||
background: var(--woo-bg-primary);
|
||||
color: var(--woo-text-primary);
|
||||
}
|
||||
|
||||
.woo-edit-input-text {
|
||||
text-align: left;
|
||||
width: 120px;
|
||||
|
||||
@@ -60,12 +60,18 @@ export class ProductMapping extends Component {
|
||||
// Pagination
|
||||
pageSize: 50,
|
||||
|
||||
// Category filters
|
||||
odooCategories: [],
|
||||
odooFilterCategoryId: false,
|
||||
odooExcludeCategoryIds: [],
|
||||
|
||||
// Conflicts tab
|
||||
conflicts: [],
|
||||
});
|
||||
|
||||
onWillStart(async () => {
|
||||
await this._loadInstances();
|
||||
await this._loadOdooCategories();
|
||||
await this._refreshAll();
|
||||
});
|
||||
}
|
||||
@@ -125,6 +131,15 @@ export class ProductMapping extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async _loadOdooCategories() {
|
||||
try {
|
||||
const result = await rpc("/woo/search/odoo_categories", {});
|
||||
this.state.odooCategories = result || [];
|
||||
} catch (err) {
|
||||
console.error("[ProductMapping] _loadOdooCategories error:", err);
|
||||
}
|
||||
}
|
||||
|
||||
async _loadOdooProducts(query = "") {
|
||||
try {
|
||||
const params = {
|
||||
@@ -135,6 +150,12 @@ export class ProductMapping extends Component {
|
||||
if (this.state.instanceId) {
|
||||
params.instance_id = this.state.instanceId;
|
||||
}
|
||||
if (this.state.odooFilterCategoryId) {
|
||||
params.category_id = this.state.odooFilterCategoryId;
|
||||
}
|
||||
if (this.state.odooExcludeCategoryIds.length) {
|
||||
params.exclude_category_ids = JSON.stringify(this.state.odooExcludeCategoryIds);
|
||||
}
|
||||
const result = await rpc("/woo/search/odoo_products", params);
|
||||
this.state.odooProducts = (result && result.results) || [];
|
||||
this.state.unmatchedOdooTotal = (result && result.total) || 0;
|
||||
@@ -260,6 +281,42 @@ export class ProductMapping extends Component {
|
||||
await this._refreshAll();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Category filter
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
async onOdooCategoryFilter(ev) {
|
||||
const val = ev.target.value;
|
||||
this.state.odooFilterCategoryId = val ? parseInt(val, 10) : false;
|
||||
this.state.unmatchedOdooPage = 1;
|
||||
await this._loadOdooProducts("");
|
||||
}
|
||||
|
||||
toggleExcludeCategory(catId) {
|
||||
const idx = this.state.odooExcludeCategoryIds.indexOf(catId);
|
||||
if (idx >= 0) {
|
||||
this.state.odooExcludeCategoryIds.splice(idx, 1);
|
||||
} else {
|
||||
this.state.odooExcludeCategoryIds.push(catId);
|
||||
}
|
||||
}
|
||||
|
||||
async applyExcludeCategories() {
|
||||
this.state.unmatchedOdooPage = 1;
|
||||
await this._loadOdooProducts("");
|
||||
}
|
||||
|
||||
isCategoryExcluded(catId) {
|
||||
return this.state.odooExcludeCategoryIds.includes(catId);
|
||||
}
|
||||
|
||||
async clearCategoryFilter() {
|
||||
this.state.odooFilterCategoryId = false;
|
||||
this.state.odooExcludeCategoryIds = [];
|
||||
this.state.unmatchedOdooPage = 1;
|
||||
await this._loadOdooProducts("");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Mapped tab
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -333,8 +333,24 @@
|
||||
<div class="woo-split">
|
||||
<!-- Odoo products panel -->
|
||||
<div class="woo-split-panel">
|
||||
<div class="woo-split-panel-header">
|
||||
<div class="woo-split-panel-header" style="flex-wrap: wrap; gap: 6px;">
|
||||
<span>Odoo Products</span>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<select class="woo-filter-select" t-on-change="onOdooCategoryFilter">
|
||||
<option value="">All Categories</option>
|
||||
<t t-foreach="state.odooCategories" t-as="cat" t-key="cat.id">
|
||||
<option t-att-value="cat.id"
|
||||
t-att-selected="state.odooFilterCategoryId === cat.id">
|
||||
<t t-esc="cat.complete_name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<t t-if="state.odooFilterCategoryId || state.odooExcludeCategoryIds.length">
|
||||
<button class="woo-btn-icon" title="Clear filter" t-on-click="clearCategoryFilter">
|
||||
<i class="fa fa-times"/>
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
<AjaxSearch
|
||||
endpoint="'/woo/search/odoo_products'"
|
||||
t-props="{ instanceId: state.instanceId, onResults: onOdooResults.bind(this), placeholder: 'Search Odoo…' }"
|
||||
|
||||
Reference in New Issue
Block a user