x
This commit is contained in:
1 parent
6f67ee6077
commit
62db477dbd
13 files changed
+660
-98
No files matched your search
+97
-44
@@ -55,92 +55,96 @@ const localizedStringListSchema = {
|
||||
items: localizedStringSchema
|
||||
};
|
||||
|
||||
const localizedStringExample = '{ "th": "ข้อความภาษาไทย", "en": "English text" }';
|
||||
const localizedStringListExample = `[ ${localizedStringExample} ]`;
|
||||
|
||||
const SECTION_TOOL_CONFIGS = [
|
||||
{
|
||||
name: "update_hero_article",
|
||||
sectionType: "HERO_ARTICLE",
|
||||
description: "Update a HERO_ARTICLE section with structured editorial fields.",
|
||||
description: `Update a HERO_ARTICLE section. Use localized objects for title, subtitle, author, and category. Use plain strings for image URLs, overlayColor, publishDate/date, and buttonLink. Example payload: { "sectionId": 12, "title": ${localizedStringExample}, "subtitle": ${localizedStringExample}, "author": ${localizedStringExample}, "imageUrl": "https://..." }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized article title" },
|
||||
subtitle: { ...localizedStringSchema, description: "Localized subtitle" },
|
||||
author: { ...localizedStringSchema, description: "Localized author name" },
|
||||
category: { ...localizedStringSchema, description: "Localized category or tag" },
|
||||
publishDate: { type: "string", description: "Publish date or display date" },
|
||||
date: { type: "string", description: "Alternative date field accepted by backend" },
|
||||
imageUrl: { type: "string", description: "Main image URL" },
|
||||
backgroundImageUrl: { type: "string", description: "Background image URL" },
|
||||
overlayColor: { type: "string", description: "Overlay color in hex or rgba" }
|
||||
title: { ...localizedStringSchema, description: `Localized article title, for example ${localizedStringExample}` },
|
||||
subtitle: { ...localizedStringSchema, description: `Localized subtitle, for example ${localizedStringExample}` },
|
||||
author: { ...localizedStringSchema, description: `Localized author name, for example ${localizedStringExample}` },
|
||||
category: { ...localizedStringSchema, description: `Localized category or tag, for example ${localizedStringExample}` },
|
||||
publishDate: { type: "string", description: "Plain string publish date or display date" },
|
||||
date: { type: "string", description: "Plain string alternative date field accepted by backend" },
|
||||
imageUrl: { type: "string", description: "Plain string main image URL" },
|
||||
backgroundImageUrl: { type: "string", description: "Plain string background image URL" },
|
||||
overlayColor: { type: "string", description: "Plain string overlay color in hex or rgba" }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_rich_text",
|
||||
sectionType: "RICH_TEXT",
|
||||
description: "Update a RICH_TEXT section with localized title and content.",
|
||||
description: `Update a RICH_TEXT section. Title is optional and localized. Content is required and may be HTML or plain text per language. Example payload: { "sectionId": 34, "title": ${localizedStringExample}, "content": ${localizedStringExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized title displayed above the content" },
|
||||
content: { ...localizedStringSchema, description: "Localized HTML or plain text content" }
|
||||
title: { ...localizedStringSchema, description: `Localized title displayed above the content, for example ${localizedStringExample}` },
|
||||
content: { ...localizedStringSchema, description: `Localized HTML or plain text content, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["sectionId", "content"]
|
||||
},
|
||||
{
|
||||
name: "update_scent_notes_breakdown",
|
||||
sectionType: "SCENT_NOTES_BREAKDOWN",
|
||||
description: "Update a SCENT_NOTES_BREAKDOWN section with localized title, description, and note groups.",
|
||||
description: `Update a SCENT_NOTES_BREAKDOWN section. Title and description are localized. Each note item can be a plain string or a localized object. Use either heartNotes or middleNotes; the backend mirrors whichever one you provide so both stay in sync. Example payload: { "sectionId": 40, "title": ${localizedStringExample}, "topNotes": ${localizedStringListExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized title" },
|
||||
description: { ...localizedStringSchema, description: "Localized supporting description" },
|
||||
topNotes: { type: "array", items: localizedStringSchema, description: "Top note values" },
|
||||
heartNotes: { type: "array", items: localizedStringSchema, description: "Heart note values" },
|
||||
middleNotes: { type: "array", items: localizedStringSchema, description: "Middle note values" },
|
||||
baseNotes: { type: "array", items: localizedStringSchema, description: "Base note values" }
|
||||
title: { ...localizedStringSchema, description: `Localized title, for example ${localizedStringExample}` },
|
||||
description: { ...localizedStringSchema, description: `Localized supporting description, for example ${localizedStringExample}` },
|
||||
topNotes: { ...localizedStringListSchema, description: `Top note values, for example ${localizedStringListExample}` },
|
||||
heartNotes: { ...localizedStringListSchema, description: `Heart note values. The server mirrors heartNotes and middleNotes, for example ${localizedStringListExample}` },
|
||||
middleNotes: { ...localizedStringListSchema, description: `Middle note values. The server mirrors heartNotes and middleNotes, for example ${localizedStringListExample}` },
|
||||
baseNotes: { ...localizedStringListSchema, description: `Base note values, for example ${localizedStringListExample}` }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_quote_callout",
|
||||
sectionType: "QUOTE_CALLOUT",
|
||||
description: "Update a QUOTE_CALLOUT section with a localized quote, author, and role.",
|
||||
description: `Update a QUOTE_CALLOUT section. Quote is required and localized. Author and role are optional localized fields. Example payload: { "sectionId": 48, "quote": ${localizedStringExample}, "author": ${localizedStringExample}, "role": ${localizedStringExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
quote: { ...localizedStringSchema, description: "Localized quote text" },
|
||||
author: { ...localizedStringSchema, description: "Localized author name" },
|
||||
role: { ...localizedStringSchema, description: "Localized author role or title" }
|
||||
quote: { ...localizedStringSchema, description: `Localized quote text, for example ${localizedStringExample}` },
|
||||
author: { ...localizedStringSchema, description: `Localized author name, for example ${localizedStringExample}` },
|
||||
role: { ...localizedStringSchema, description: `Localized author role or title, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_product_carousel",
|
||||
sectionType: "PRODUCT_CAROUSEL",
|
||||
description: "Update a PRODUCT_CAROUSEL section with localized copy and carousel options.",
|
||||
description: `Update a PRODUCT_CAROUSEL section. Title and description are localized. collectionId, limit, showPrice, showAddToCart, and products are plain values. If products is omitted, backend can auto-populate products on read-back using collectionId/type/productIds/limit. Example payload: { "sectionId": 52, "title": ${localizedStringExample}, "collectionId": "summer", "limit": 6, "showPrice": true }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized title" },
|
||||
description: { ...localizedStringSchema, description: "Localized supporting description" },
|
||||
collectionId: { type: "string", description: "Optional collection identifier" },
|
||||
title: { ...localizedStringSchema, description: `Localized title, for example ${localizedStringExample}` },
|
||||
description: { ...localizedStringSchema, description: `Localized supporting description, for example ${localizedStringExample}` },
|
||||
collectionId: { type: "string", description: "Optional plain string collection identifier" },
|
||||
limit: { type: "number", description: "Maximum number of products to show" },
|
||||
showPrice: { type: "boolean", description: "Show product price" },
|
||||
showAddToCart: { type: "boolean", description: "Show add to cart button" }
|
||||
showAddToCart: { type: "boolean", description: "Show add to cart button" },
|
||||
products: { type: "array", description: "Optional explicit product list. Omit this to let backend auto-populate on read-back.", items: { type: "object" } }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_accordion",
|
||||
sectionType: "ACCORDION",
|
||||
description: "Update an ACCORDION section with categories, questions, and localized answers.",
|
||||
description: `Update an ACCORDION section. title is optional and localized. categories is required. Each category needs a localized name, optional icon, and at least one question. Each question needs localized q and a fields. Example payload: { "sectionId": 60, "categories": [ { "name": ${localizedStringExample}, "questions": [ { "q": ${localizedStringExample}, "a": ${localizedStringExample} } ] } ] }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized section title" },
|
||||
title: { ...localizedStringSchema, description: `Localized section title, for example ${localizedStringExample}` },
|
||||
categories: {
|
||||
type: "array",
|
||||
description: "Accordion categories",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { ...localizedStringSchema, description: "Localized category name" },
|
||||
name: { ...localizedStringSchema, description: `Localized category name, for example ${localizedStringExample}` },
|
||||
icon: { type: "string", description: "Optional icon or emoji" },
|
||||
questions: {
|
||||
type: "array",
|
||||
@@ -148,8 +152,8 @@ const SECTION_TOOL_CONFIGS = [
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
q: { ...localizedStringSchema, description: "Localized question" },
|
||||
a: { ...localizedStringSchema, description: "Localized answer" }
|
||||
q: { ...localizedStringSchema, description: `Localized question, for example ${localizedStringExample}` },
|
||||
a: { ...localizedStringSchema, description: `Localized answer, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["q", "a"]
|
||||
}
|
||||
@@ -164,25 +168,25 @@ const SECTION_TOOL_CONFIGS = [
|
||||
{
|
||||
name: "update_contact_info",
|
||||
sectionType: "CONTACT_INFO",
|
||||
description: "Update a CONTACT_INFO section with localized address, email, line, and hours.",
|
||||
description: `Update a CONTACT_INFO section. title is optional and localized. address and hours are localized text. email and line are plain strings. Example payload: { "sectionId": 72, "title": ${localizedStringExample}, "address": ${localizedStringExample}, "email": "hello@example.com", "line": "@homaroma", "hours": ${localizedStringExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized section title" },
|
||||
address: { ...localizedStringSchema, description: "Localized address" },
|
||||
email: { ...localizedStringSchema, description: "Localized email" },
|
||||
line: { ...localizedStringSchema, description: "Localized Line ID or contact" },
|
||||
hours: { ...localizedStringSchema, description: "Localized business hours" }
|
||||
title: { ...localizedStringSchema, description: `Localized section title, for example ${localizedStringExample}` },
|
||||
address: { ...localizedStringSchema, description: `Localized address, for example ${localizedStringExample}` },
|
||||
email: { type: "string", description: "Plain string email address" },
|
||||
line: { type: "string", description: "Plain string Line ID or contact" },
|
||||
hours: { ...localizedStringSchema, description: `Localized business hours, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["sectionId", "address", "email", "line", "hours"]
|
||||
},
|
||||
{
|
||||
name: "update_contact_form",
|
||||
sectionType: "CONTACT_FORM",
|
||||
description: "Update a CONTACT_FORM section with localized title and subtitle.",
|
||||
description: `Update a CONTACT_FORM section. title and subtitle are localized; this block has no extra fields. Example payload: { "sectionId": 73, "title": ${localizedStringExample}, "subtitle": ${localizedStringExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: "Localized form title" },
|
||||
subtitle: { ...localizedStringSchema, description: "Localized form subtitle" }
|
||||
title: { ...localizedStringSchema, description: `Localized form title, for example ${localizedStringExample}` },
|
||||
subtitle: { ...localizedStringSchema, description: `Localized form subtitle, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
}
|
||||
@@ -203,6 +207,13 @@ function buildSectionPayload(params: any, fields: readonly string[]) {
|
||||
}
|
||||
|
||||
function buildSectionUpdateResult(toolName: string, sectionType: string, updatedSection: any, payload: Record<string, any>) {
|
||||
const notes: string[] = [];
|
||||
if (sectionType === "SCENT_NOTES_BREAKDOWN") {
|
||||
notes.push("heartNotes and middleNotes are mirrored automatically by the backend");
|
||||
}
|
||||
if (sectionType === "PRODUCT_CAROUSEL") {
|
||||
notes.push("If products was omitted, the backend may populate products on read-back");
|
||||
}
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
@@ -214,6 +225,8 @@ function buildSectionUpdateResult(toolName: string, sectionType: string, updated
|
||||
sectionType,
|
||||
sectionId: updatedSection?.id,
|
||||
updatedFields: Object.keys(payload),
|
||||
appliedPayload: payload,
|
||||
notes,
|
||||
section: updatedSection
|
||||
},
|
||||
null,
|
||||
@@ -404,6 +417,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
required: ["id", "lang", "title"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "update_page_translations",
|
||||
description: "Add or update multiple page title translations in one call. Use this when you want to set several languages at once instead of calling update_page_translation repeatedly.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "number", description: "Page ID" },
|
||||
translations: {
|
||||
type: "object",
|
||||
description: "Language-code map for the page title, for example { \"th\": \"...\", \"en\": \"...\" }. Each key becomes or updates one locale."
|
||||
}
|
||||
},
|
||||
required: ["id", "translations"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "update_hero_translation",
|
||||
description: "Add or update translations for a specific hero.",
|
||||
@@ -827,6 +855,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "update_page_translations": {
|
||||
const { id, translations } = params as any;
|
||||
const res = await api.patch(`/pages/${id}/translations`, {
|
||||
title: translations
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, pageId: id, translations: res.data?.translations ?? res.data, page: res.data?.page ?? res.data }, null, 2) }] };
|
||||
}
|
||||
case "update_hero_translation": {
|
||||
const { id, lang, tagline, title, description, buttonText } = params as any;
|
||||
const payload: any = {};
|
||||
@@ -984,7 +1019,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
payload.id = params.id;
|
||||
}
|
||||
const res = await api.post("/pages", payload);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
const pageData = res.data?.page ?? res.data;
|
||||
const normalized = {
|
||||
success: res.data?.success ?? ((res.status >= 200) && (res.status < 300)),
|
||||
operation: res.data?.operation ?? (params.id ? "update" : "create"),
|
||||
pageId: res.data?.pageId ?? pageData?.id ?? null,
|
||||
slug: res.data?.slug ?? pageData?.slug ?? params.slug,
|
||||
title: res.data?.title ?? pageData?.title ?? params.title,
|
||||
isPublished: res.data?.isPublished ?? pageData?.isPublished ?? payload.isPublished ?? true,
|
||||
diagnostic: res.data?.diagnostic ?? (params.id ? "Page updated successfully." : "Page created successfully."),
|
||||
page: pageData,
|
||||
};
|
||||
return { content: [{ type: "text", text: JSON.stringify(normalized, null, 2) }] };
|
||||
}
|
||||
case "add_page_section": {
|
||||
const payload: any = {
|
||||
@@ -1019,6 +1065,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
}
|
||||
|
||||
const payload = buildSectionPayload(params, Object.keys(config.properties).filter((key) => key !== "sectionId"));
|
||||
if (config.sectionType === "SCENT_NOTES_BREAKDOWN") {
|
||||
if (payload.heartNotes !== undefined && payload.middleNotes === undefined) {
|
||||
payload.middleNotes = payload.heartNotes;
|
||||
} else if (payload.middleNotes !== undefined && payload.heartNotes === undefined) {
|
||||
payload.heartNotes = payload.middleNotes;
|
||||
}
|
||||
}
|
||||
const res = await api.put(`/pages/sections/${params.sectionId}`, {
|
||||
type: config.sectionType,
|
||||
...payload
|
||||
|
||||
Reference in new issue
Block a user