ux improved
This commit is contained in:
68
src/modules/0-ui/controllers/aliases.js
Normal file
68
src/modules/0-ui/controllers/aliases.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import { handleListAliases, handleCreateAlias, handleUpdateAlias, handleDeleteAlias } from "../handlers/aliases.js";
|
||||
|
||||
export const makeListAliases = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const q = req.query.q || "";
|
||||
const woo_product_id = req.query.woo_product_id ? parseInt(req.query.woo_product_id, 10) : null;
|
||||
const limit = req.query.limit || "200";
|
||||
const result = await handleListAliases({ tenantId, q, woo_product_id, limit });
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeCreateAlias = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const { alias, woo_product_id, boost, category_hint, metadata } = req.body || {};
|
||||
|
||||
if (!alias || !woo_product_id) {
|
||||
return res.status(400).json({ ok: false, error: "alias_and_woo_product_id_required" });
|
||||
}
|
||||
|
||||
const result = await handleCreateAlias({ tenantId, alias, woo_product_id, boost, category_hint, metadata });
|
||||
res.json({ ok: true, item: result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err.code === "23505") { // unique violation
|
||||
return res.status(409).json({ ok: false, error: "alias_already_exists" });
|
||||
}
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeUpdateAlias = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const alias = req.params.alias;
|
||||
const { woo_product_id, boost, category_hint, metadata } = req.body || {};
|
||||
|
||||
if (!woo_product_id) {
|
||||
return res.status(400).json({ ok: false, error: "woo_product_id_required" });
|
||||
}
|
||||
|
||||
const result = await handleUpdateAlias({ tenantId, alias, woo_product_id, boost, category_hint, metadata });
|
||||
if (!result) {
|
||||
return res.status(404).json({ ok: false, error: "alias_not_found" });
|
||||
}
|
||||
res.json({ ok: true, item: result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeDeleteAlias = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const alias = req.params.alias;
|
||||
const result = await handleDeleteAlias({ tenantId, alias });
|
||||
res.json({ ok: true, ...result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { handleSearchProducts } from "../handlers/products.js";
|
||||
import { handleSearchProducts, handleListProducts, handleGetProduct, handleSyncProducts } from "../handlers/products.js";
|
||||
|
||||
export const makeSearchProducts = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
@@ -14,3 +14,43 @@ export const makeSearchProducts = (tenantIdOrFn) => async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const makeListProducts = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const q = req.query.q || "";
|
||||
const limit = req.query.limit || "2000";
|
||||
const offset = req.query.offset || "0";
|
||||
const result = await handleListProducts({ tenantId, q, limit, offset });
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeGetProduct = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const wooProductId = req.params.id;
|
||||
const result = await handleGetProduct({ tenantId, wooProductId });
|
||||
if (!result) {
|
||||
return res.status(404).json({ ok: false, error: "product_not_found" });
|
||||
}
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeSyncProducts = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const result = await handleSyncProducts({ tenantId });
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
88
src/modules/0-ui/controllers/recommendations.js
Normal file
88
src/modules/0-ui/controllers/recommendations.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
handleListRecommendations,
|
||||
handleGetRecommendation,
|
||||
handleCreateRecommendation,
|
||||
handleUpdateRecommendation,
|
||||
handleDeleteRecommendation
|
||||
} from "../handlers/recommendations.js";
|
||||
|
||||
export const makeListRecommendations = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const q = req.query.q || "";
|
||||
const limit = req.query.limit || "200";
|
||||
const result = await handleListRecommendations({ tenantId, q, limit });
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeGetRecommendation = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const id = req.params.id;
|
||||
const result = await handleGetRecommendation({ tenantId, id });
|
||||
if (!result) {
|
||||
return res.status(404).json({ ok: false, error: "recommendation_not_found" });
|
||||
}
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeCreateRecommendation = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const { rule_key, trigger, queries, boosts, ask_slots, active, priority } = req.body || {};
|
||||
|
||||
if (!rule_key) {
|
||||
return res.status(400).json({ ok: false, error: "rule_key_required" });
|
||||
}
|
||||
|
||||
const result = await handleCreateRecommendation({
|
||||
tenantId, rule_key, trigger, queries, boosts, ask_slots, active, priority
|
||||
});
|
||||
res.json({ ok: true, item: result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err.code === "23505") { // unique violation
|
||||
return res.status(409).json({ ok: false, error: "rule_key_already_exists" });
|
||||
}
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeUpdateRecommendation = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const id = req.params.id;
|
||||
const { trigger, queries, boosts, ask_slots, active, priority } = req.body || {};
|
||||
|
||||
const result = await handleUpdateRecommendation({
|
||||
tenantId, id, trigger, queries, boosts, ask_slots, active, priority
|
||||
});
|
||||
if (!result) {
|
||||
return res.status(404).json({ ok: false, error: "recommendation_not_found" });
|
||||
}
|
||||
res.json({ ok: true, item: result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const makeDeleteRecommendation = (tenantIdOrFn) => async (req, res) => {
|
||||
try {
|
||||
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
|
||||
const id = req.params.id;
|
||||
const result = await handleDeleteRecommendation({ tenantId, id });
|
||||
res.json({ ok: true, ...result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: "internal_error" });
|
||||
}
|
||||
};
|
||||
296
src/modules/0-ui/db/repo.js
Normal file
296
src/modules/0-ui/db/repo.js
Normal file
@@ -0,0 +1,296 @@
|
||||
import { pool } from "../../shared/db/pool.js";
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Products
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
export async function listProducts({ tenantId, q = "", limit = 2000, offset = 0 }) {
|
||||
const lim = Math.max(1, Math.min(5000, parseInt(limit, 10) || 2000));
|
||||
const off = Math.max(0, parseInt(offset, 10) || 0);
|
||||
const query = String(q || "").trim();
|
||||
|
||||
let sql, params;
|
||||
if (query) {
|
||||
const like = `%${query}%`;
|
||||
sql = `
|
||||
select
|
||||
woo_id as woo_product_id,
|
||||
name,
|
||||
slug as sku,
|
||||
price_current as price,
|
||||
stock_status,
|
||||
categories,
|
||||
attributes_normalized,
|
||||
updated_at as refreshed_at,
|
||||
raw as payload
|
||||
from woo_products_snapshot
|
||||
where tenant_id = $1
|
||||
and (name ilike $2 or coalesce(slug,'') ilike $2)
|
||||
order by name asc
|
||||
limit $3 offset $4
|
||||
`;
|
||||
params = [tenantId, like, lim, off];
|
||||
} else {
|
||||
sql = `
|
||||
select
|
||||
woo_id as woo_product_id,
|
||||
name,
|
||||
slug as sku,
|
||||
price_current as price,
|
||||
stock_status,
|
||||
categories,
|
||||
attributes_normalized,
|
||||
updated_at as refreshed_at,
|
||||
raw as payload
|
||||
from woo_products_snapshot
|
||||
where tenant_id = $1
|
||||
order by name asc
|
||||
limit $2 offset $3
|
||||
`;
|
||||
params = [tenantId, lim, off];
|
||||
}
|
||||
|
||||
const { rows } = await pool.query(sql, params);
|
||||
return rows;
|
||||
}
|
||||
|
||||
export async function getProductByWooId({ tenantId, wooProductId }) {
|
||||
const sql = `
|
||||
select
|
||||
woo_id as woo_product_id,
|
||||
name,
|
||||
slug as sku,
|
||||
price_current as price,
|
||||
stock_status,
|
||||
categories,
|
||||
attributes_normalized,
|
||||
updated_at as refreshed_at,
|
||||
raw as payload
|
||||
from woo_products_snapshot
|
||||
where tenant_id = $1 and woo_id = $2
|
||||
limit 1
|
||||
`;
|
||||
const { rows } = await pool.query(sql, [tenantId, wooProductId]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Aliases
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
function normalizeAlias(alias) {
|
||||
return String(alias || "")
|
||||
.toLowerCase()
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export async function listAliases({ tenantId, q = "", woo_product_id = null, limit = 200 }) {
|
||||
const lim = Math.max(1, Math.min(500, parseInt(limit, 10) || 200));
|
||||
const query = String(q || "").trim();
|
||||
|
||||
let sql, params;
|
||||
if (woo_product_id) {
|
||||
sql = `
|
||||
select alias, normalized_alias, woo_product_id, category_hint, boost, metadata, created_at, updated_at
|
||||
from product_aliases
|
||||
where tenant_id = $1 and woo_product_id = $2
|
||||
order by alias asc
|
||||
limit $3
|
||||
`;
|
||||
params = [tenantId, woo_product_id, lim];
|
||||
} else if (query) {
|
||||
const like = `%${query}%`;
|
||||
sql = `
|
||||
select alias, normalized_alias, woo_product_id, category_hint, boost, metadata, created_at, updated_at
|
||||
from product_aliases
|
||||
where tenant_id = $1 and (alias ilike $2 or normalized_alias ilike $2)
|
||||
order by alias asc
|
||||
limit $3
|
||||
`;
|
||||
params = [tenantId, like, lim];
|
||||
} else {
|
||||
sql = `
|
||||
select alias, normalized_alias, woo_product_id, category_hint, boost, metadata, created_at, updated_at
|
||||
from product_aliases
|
||||
where tenant_id = $1
|
||||
order by alias asc
|
||||
limit $2
|
||||
`;
|
||||
params = [tenantId, lim];
|
||||
}
|
||||
|
||||
const { rows } = await pool.query(sql, params);
|
||||
return rows;
|
||||
}
|
||||
|
||||
export async function insertAlias({ tenantId, alias, woo_product_id, boost = 0, category_hint = null, metadata = {} }) {
|
||||
const normalizedAlias = normalizeAlias(alias);
|
||||
|
||||
const sql = `
|
||||
insert into product_aliases (tenant_id, alias, normalized_alias, woo_product_id, category_hint, boost, metadata)
|
||||
values ($1, $2, $3, $4, $5, $6, $7)
|
||||
returning alias, normalized_alias, woo_product_id, category_hint, boost, metadata, created_at, updated_at
|
||||
`;
|
||||
|
||||
const { rows } = await pool.query(sql, [
|
||||
tenantId,
|
||||
alias.toLowerCase().trim(),
|
||||
normalizedAlias,
|
||||
woo_product_id,
|
||||
category_hint,
|
||||
boost || 0,
|
||||
JSON.stringify(metadata || {}),
|
||||
]);
|
||||
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
export async function updateAlias({ tenantId, alias, woo_product_id, boost = 0, category_hint = null, metadata = {} }) {
|
||||
const normalizedAlias = normalizeAlias(alias);
|
||||
|
||||
const sql = `
|
||||
update product_aliases
|
||||
set woo_product_id = $3, category_hint = $4, boost = $5, metadata = $6, normalized_alias = $7, updated_at = now()
|
||||
where tenant_id = $1 and alias = $2
|
||||
returning alias, normalized_alias, woo_product_id, category_hint, boost, metadata, created_at, updated_at
|
||||
`;
|
||||
|
||||
const { rows } = await pool.query(sql, [
|
||||
tenantId,
|
||||
alias.toLowerCase().trim(),
|
||||
woo_product_id,
|
||||
category_hint,
|
||||
boost || 0,
|
||||
JSON.stringify(metadata || {}),
|
||||
normalizedAlias,
|
||||
]);
|
||||
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
export async function deleteAlias({ tenantId, alias }) {
|
||||
const sql = `delete from product_aliases where tenant_id = $1 and alias = $2 returning alias`;
|
||||
const { rows } = await pool.query(sql, [tenantId, alias.toLowerCase().trim()]);
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Recommendations
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
export async function listRecommendations({ tenantId, q = "", limit = 200 }) {
|
||||
const lim = Math.max(1, Math.min(500, parseInt(limit, 10) || 200));
|
||||
const query = String(q || "").trim();
|
||||
|
||||
let sql, params;
|
||||
if (query) {
|
||||
const like = `%${query}%`;
|
||||
sql = `
|
||||
select id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
|
||||
from product_reco_rules
|
||||
where tenant_id = $1 and rule_key ilike $2
|
||||
order by priority desc, rule_key asc
|
||||
limit $3
|
||||
`;
|
||||
params = [tenantId, like, lim];
|
||||
} else {
|
||||
sql = `
|
||||
select id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
|
||||
from product_reco_rules
|
||||
where tenant_id = $1
|
||||
order by priority desc, rule_key asc
|
||||
limit $2
|
||||
`;
|
||||
params = [tenantId, lim];
|
||||
}
|
||||
|
||||
const { rows } = await pool.query(sql, params);
|
||||
return rows;
|
||||
}
|
||||
|
||||
export async function getRecommendationById({ tenantId, id }) {
|
||||
const sql = `
|
||||
select id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
|
||||
from product_reco_rules
|
||||
where tenant_id = $1 and id = $2
|
||||
limit 1
|
||||
`;
|
||||
const { rows } = await pool.query(sql, [tenantId, id]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
export async function insertRecommendation({
|
||||
tenantId,
|
||||
rule_key,
|
||||
trigger = {},
|
||||
queries = [],
|
||||
boosts = {},
|
||||
ask_slots = [],
|
||||
active = true,
|
||||
priority = 100,
|
||||
}) {
|
||||
const sql = `
|
||||
insert into product_reco_rules (tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority)
|
||||
values ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
returning id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
|
||||
`;
|
||||
|
||||
const { rows } = await pool.query(sql, [
|
||||
tenantId,
|
||||
rule_key.toLowerCase().trim(),
|
||||
JSON.stringify(trigger || {}),
|
||||
JSON.stringify(queries || []),
|
||||
JSON.stringify(boosts || {}),
|
||||
JSON.stringify(ask_slots || []),
|
||||
active !== false,
|
||||
priority || 100,
|
||||
]);
|
||||
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
export async function updateRecommendation({
|
||||
tenantId,
|
||||
id,
|
||||
trigger,
|
||||
queries,
|
||||
boosts,
|
||||
ask_slots,
|
||||
active,
|
||||
priority,
|
||||
}) {
|
||||
const sql = `
|
||||
update product_reco_rules
|
||||
set
|
||||
trigger = $3,
|
||||
queries = $4,
|
||||
boosts = $5,
|
||||
ask_slots = $6,
|
||||
active = $7,
|
||||
priority = $8,
|
||||
updated_at = now()
|
||||
where tenant_id = $1 and id = $2
|
||||
returning id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
|
||||
`;
|
||||
|
||||
const { rows } = await pool.query(sql, [
|
||||
tenantId,
|
||||
id,
|
||||
JSON.stringify(trigger || {}),
|
||||
JSON.stringify(queries || []),
|
||||
JSON.stringify(boosts || {}),
|
||||
JSON.stringify(ask_slots || []),
|
||||
active !== false,
|
||||
priority || 100,
|
||||
]);
|
||||
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
export async function deleteRecommendation({ tenantId, id }) {
|
||||
const sql = `delete from product_reco_rules where tenant_id = $1 and id = $2 returning id`;
|
||||
const { rows } = await pool.query(sql, [tenantId, id]);
|
||||
return rows.length > 0;
|
||||
}
|
||||
19
src/modules/0-ui/handlers/aliases.js
Normal file
19
src/modules/0-ui/handlers/aliases.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { listAliases, insertAlias, updateAlias, deleteAlias } from "../db/repo.js";
|
||||
|
||||
export async function handleListAliases({ tenantId, q = "", woo_product_id = null, limit = 200 }) {
|
||||
const items = await listAliases({ tenantId, q, woo_product_id, limit });
|
||||
return { items };
|
||||
}
|
||||
|
||||
export async function handleCreateAlias({ tenantId, alias, woo_product_id, boost = 0, category_hint = null, metadata = {} }) {
|
||||
return insertAlias({ tenantId, alias, woo_product_id, boost, category_hint, metadata });
|
||||
}
|
||||
|
||||
export async function handleUpdateAlias({ tenantId, alias, woo_product_id, boost = 0, category_hint = null, metadata = {} }) {
|
||||
return updateAlias({ tenantId, alias, woo_product_id, boost, category_hint, metadata });
|
||||
}
|
||||
|
||||
export async function handleDeleteAlias({ tenantId, alias }) {
|
||||
const deleted = await deleteAlias({ tenantId, alias });
|
||||
return { deleted };
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { searchSnapshotItems } from "../../shared/wooSnapshot.js";
|
||||
import { listProducts, getProductByWooId } from "../db/repo.js";
|
||||
|
||||
export async function handleSearchProducts({ tenantId, q = "", limit = "10", forceWoo = "0" }) {
|
||||
const { items, source } = await searchSnapshotItems({
|
||||
@@ -9,3 +10,18 @@ export async function handleSearchProducts({ tenantId, q = "", limit = "10", for
|
||||
return { items, source };
|
||||
}
|
||||
|
||||
export async function handleListProducts({ tenantId, q = "", limit = 2000, offset = 0 }) {
|
||||
const items = await listProducts({ tenantId, q, limit, offset });
|
||||
return { items };
|
||||
}
|
||||
|
||||
export async function handleGetProduct({ tenantId, wooProductId }) {
|
||||
return getProductByWooId({ tenantId, wooProductId });
|
||||
}
|
||||
|
||||
export async function handleSyncProducts({ tenantId }) {
|
||||
// This is a placeholder - actual sync would fetch from Woo API
|
||||
// For now, just return success
|
||||
return { ok: true, message: "Sync triggered (use import script for full sync)" };
|
||||
}
|
||||
|
||||
|
||||
47
src/modules/0-ui/handlers/recommendations.js
Normal file
47
src/modules/0-ui/handlers/recommendations.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
listRecommendations,
|
||||
getRecommendationById,
|
||||
insertRecommendation,
|
||||
updateRecommendation,
|
||||
deleteRecommendation,
|
||||
} from "../db/repo.js";
|
||||
|
||||
export async function handleListRecommendations({ tenantId, q = "", limit = 200 }) {
|
||||
const items = await listRecommendations({ tenantId, q, limit });
|
||||
return { items };
|
||||
}
|
||||
|
||||
export async function handleGetRecommendation({ tenantId, id }) {
|
||||
return getRecommendationById({ tenantId, id });
|
||||
}
|
||||
|
||||
export async function handleCreateRecommendation({
|
||||
tenantId,
|
||||
rule_key,
|
||||
trigger = {},
|
||||
queries = [],
|
||||
boosts = {},
|
||||
ask_slots = [],
|
||||
active = true,
|
||||
priority = 100,
|
||||
}) {
|
||||
return insertRecommendation({ tenantId, rule_key, trigger, queries, boosts, ask_slots, active, priority });
|
||||
}
|
||||
|
||||
export async function handleUpdateRecommendation({
|
||||
tenantId,
|
||||
id,
|
||||
trigger,
|
||||
queries,
|
||||
boosts,
|
||||
ask_slots,
|
||||
active,
|
||||
priority,
|
||||
}) {
|
||||
return updateRecommendation({ tenantId, id, trigger, queries, boosts, ask_slots, active, priority });
|
||||
}
|
||||
|
||||
export async function handleDeleteRecommendation({ tenantId, id }) {
|
||||
const deleted = await deleteRecommendation({ tenantId, id });
|
||||
return { deleted };
|
||||
}
|
||||
Reference in New Issue
Block a user