fix update Section Block

This commit is contained in:
Your Name committed 2026-06-17 21:08:24 -04:00
1 parent 996dfdabd0
commit 6f67ee6077
47 files changed
+1792 -197

No files matched your search

+224 -7
View File
@@ -40,9 +40,196 @@ function findNodeAndParent(tree: any[], targetId: string, parent: any = null, li
return null;
}
let BACKEND_URL = "http://localhost:3051/api";
const ADMIN_USERNAME = process.env.ADMIN_USERNAME || "admin";
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || "homaroma123"; // เปลี่ยนรหัสผ่านตรงนี้ให้ตรงกับ Production ด้วยนะครับ
const localizedStringSchema = {
oneOf: [
{ type: "string" },
{
type: "object",
additionalProperties: { type: "string" }
}
]
};
const localizedStringListSchema = {
type: "array",
items: localizedStringSchema
};
const SECTION_TOOL_CONFIGS = [
{
name: "update_hero_article",
sectionType: "HERO_ARTICLE",
description: "Update a HERO_ARTICLE section with structured editorial fields.",
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" }
},
required: ["sectionId"]
},
{
name: "update_rich_text",
sectionType: "RICH_TEXT",
description: "Update a RICH_TEXT section with localized title and content.",
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" }
},
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.",
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" }
},
required: ["sectionId"]
},
{
name: "update_quote_callout",
sectionType: "QUOTE_CALLOUT",
description: "Update a QUOTE_CALLOUT section with a localized quote, author, and role.",
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" }
},
required: ["sectionId"]
},
{
name: "update_product_carousel",
sectionType: "PRODUCT_CAROUSEL",
description: "Update a PRODUCT_CAROUSEL section with localized copy and carousel options.",
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" },
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" }
},
required: ["sectionId"]
},
{
name: "update_accordion",
sectionType: "ACCORDION",
description: "Update an ACCORDION section with categories, questions, and localized answers.",
properties: {
sectionId: { type: "number", description: "The numeric ID of the section to update" },
title: { ...localizedStringSchema, description: "Localized section title" },
categories: {
type: "array",
description: "Accordion categories",
items: {
type: "object",
properties: {
name: { ...localizedStringSchema, description: "Localized category name" },
icon: { type: "string", description: "Optional icon or emoji" },
questions: {
type: "array",
description: "Questions under the category",
items: {
type: "object",
properties: {
q: { ...localizedStringSchema, description: "Localized question" },
a: { ...localizedStringSchema, description: "Localized answer" }
},
required: ["q", "a"]
}
}
},
required: ["name", "questions"]
}
}
},
required: ["sectionId", "categories"]
},
{
name: "update_contact_info",
sectionType: "CONTACT_INFO",
description: "Update a CONTACT_INFO section with localized address, email, line, and hours.",
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" }
},
required: ["sectionId", "address", "email", "line", "hours"]
},
{
name: "update_contact_form",
sectionType: "CONTACT_FORM",
description: "Update a CONTACT_FORM section with localized title and subtitle.",
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" }
},
required: ["sectionId"]
}
] as const;
const SECTION_TOOL_CONFIG_BY_NAME = new Map(
SECTION_TOOL_CONFIGS.map((config) => [config.name, config] as const)
);
function buildSectionPayload(params: any, fields: readonly string[]) {
const payload: Record<string, any> = {};
for (const field of fields) {
if (params[field] !== undefined) {
payload[field] = params[field];
}
}
return payload;
}
function buildSectionUpdateResult(toolName: string, sectionType: string, updatedSection: any, payload: Record<string, any>) {
return {
content: [
{
type: "text",
text: JSON.stringify(
{
success: true,
tool: toolName,
sectionType,
sectionId: updatedSection?.id,
updatedFields: Object.keys(payload),
section: updatedSection
},
null,
2
)
}
]
};
}
const LOCAL_BACKEND_URL = process.env.MCP_BACKEND_URL_LOCAL || "http://localhost:3051/api";
const PRODUCTION_BACKEND_URL = process.env.MCP_BACKEND_URL_PRODUCTION || "https://api.homaroma.shop/api";
let BACKEND_URL = process.env.MCP_BACKEND_URL || LOCAL_BACKEND_URL;
const ADMIN_USERNAME = process.env.MCP_ADMIN_USERNAME || process.env.ADMIN_USERNAME || "admin";
const ADMIN_PASSWORD = process.env.MCP_ADMIN_PASSWORD || process.env.ADMIN_PASSWORD || "homaroma123";
let authToken = "";
@@ -442,6 +629,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
required: ["sectionId"]
}
},
...SECTION_TOOL_CONFIGS.map((config) => ({
name: config.name,
description: config.description,
inputSchema: {
type: "object",
properties: config.properties,
required: config.required
}
})),
{
name: "delete_page_section",
description: "Delete a block section from a dynamic page layout",
@@ -569,9 +765,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "set_target_environment": {
const env = params.env;
if (env === "production") {
BACKEND_URL = "https://api.homaroma.shop/api";
BACKEND_URL = PRODUCTION_BACKEND_URL;
} else {
BACKEND_URL = "http://localhost:3051/api";
BACKEND_URL = LOCAL_BACKEND_URL;
}
api.defaults.baseURL = BACKEND_URL;
authToken = ""; // reset token so it logs in again on next request
@@ -807,7 +1003,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (params.payload) payload.payload = params.payload;
if (params.isActive !== undefined) payload.isActive = params.isActive;
const res = await api.put(`/pages/sections/${params.sectionId}`, payload);
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
return buildSectionUpdateResult("update_page_section", res.data?.type ?? params.type ?? "UNKNOWN", res.data, payload);
}
case "update_hero_article":
case "update_rich_text":
case "update_scent_notes_breakdown":
case "update_quote_callout":
case "update_product_carousel":
case "update_accordion":
case "update_contact_info":
case "update_contact_form": {
const config = SECTION_TOOL_CONFIG_BY_NAME.get(request.params.name);
if (!config) {
throw new Error(`Unknown tool config for: ${request.params.name}`);
}
const payload = buildSectionPayload(params, Object.keys(config.properties).filter((key) => key !== "sectionId"));
const res = await api.put(`/pages/sections/${params.sectionId}`, {
type: config.sectionType,
...payload
});
return buildSectionUpdateResult(request.params.name, config.sectionType, res.data, payload);
}
case "delete_page_section": {
const res = await api.delete(`/pages/sections/${params.sectionId}`);
@@ -1043,4 +1260,4 @@ async function main() {
console.error("HomAroma MCP Server running on stdio");
}
main().catch(console.error);
main().catch(console.error);