From 91e498229cc6893744ae718df3479cd742c0e2e3 Mon Sep 17 00:00:00 2001 From: Sean Hatfield Date: Tue, 24 Jun 2025 16:19:50 -0700 Subject: [PATCH] Publish slash commands to hub (#4019) * implement ui for publish system prompt to hub * rework ui + add backend to upload to hub * add success modal view + publish menu item + translations * normalize translations * refactor PublishEntityModal + add hook for hub auth * normalize translations * fix ui for success screen * refactor, auth checks, UI/UX, and naming conventions to be more clear * move components to CommunityHub folder + small ui tweak * wip publish agent flows to community hub * rework translations/implement uploading agent flows * normalize/restructure translations * rename component/add jsdoc for consistency * fix en translation * remove comments/duplicate function from merge conf * update styles of publish button in flow builder * resolve ssr icon issue * implement uploading slash commands to hub * normalize translations * show command, non editable --------- Co-authored-by: Timothy Carambat --- .../SlashCommands/index.jsx | 256 ++++++++++++++++++ .../CommunityHub/PublishEntityModal/index.jsx | 3 + .../SlashCommands/SlashPresets/index.jsx | 135 +++++++-- frontend/src/locales/ar/common.js | 26 ++ frontend/src/locales/da/common.js | 26 ++ frontend/src/locales/de/common.js | 128 +++++---- frontend/src/locales/en/common.js | 31 +++ frontend/src/locales/es/common.js | 26 ++ frontend/src/locales/fa/common.js | 26 ++ frontend/src/locales/fr/common.js | 26 ++ frontend/src/locales/he/common.js | 26 ++ frontend/src/locales/it/common.js | 26 ++ frontend/src/locales/ja/common.js | 26 ++ frontend/src/locales/ko/common.js | 26 ++ frontend/src/locales/lv/common.js | 26 ++ frontend/src/locales/nl/common.js | 26 ++ frontend/src/locales/pt_BR/common.js | 26 ++ frontend/src/locales/ru/common.js | 26 ++ frontend/src/locales/tr/common.js | 26 ++ frontend/src/locales/vn/common.js | 26 ++ frontend/src/locales/zh/common.js | 26 ++ frontend/src/locales/zh_TW/common.js | 26 ++ frontend/src/models/communityHub.js | 30 +- server/models/communityHub.js | 2 +- 24 files changed, 945 insertions(+), 82 deletions(-) create mode 100644 frontend/src/components/CommunityHub/PublishEntityModal/SlashCommands/index.jsx diff --git a/frontend/src/components/CommunityHub/PublishEntityModal/SlashCommands/index.jsx b/frontend/src/components/CommunityHub/PublishEntityModal/SlashCommands/index.jsx new file mode 100644 index 00000000..44111373 --- /dev/null +++ b/frontend/src/components/CommunityHub/PublishEntityModal/SlashCommands/index.jsx @@ -0,0 +1,256 @@ +import { useState, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import CommunityHub from "@/models/communityHub"; +import showToast from "@/utils/toast"; +import paths from "@/utils/paths"; +import { X } from "@phosphor-icons/react"; + +export default function SlashCommands({ entity }) { + const { t } = useTranslation(); + const formRef = useRef(null); + const [isSubmitting, setIsSubmitting] = useState(false); + const [tags, setTags] = useState([]); + const [tagInput, setTagInput] = useState(""); + const [visibility, setVisibility] = useState("public"); + const [isSuccess, setIsSuccess] = useState(false); + const [itemId, setItemId] = useState(null); + + const handleSubmit = async (e) => { + e.preventDefault(); + e.stopPropagation(); + setIsSubmitting(true); + try { + const form = new FormData(formRef.current); + const data = { + name: form.get("name"), + description: form.get("description"), + command: entity.command, + prompt: form.get("prompt"), + tags: tags, + visibility: visibility, + }; + + const { success, error, itemId } = + await CommunityHub.createSlashCommand(data); + if (!success) throw new Error(error); + setItemId(itemId); + setIsSuccess(true); + } catch (error) { + console.error("Failed to publish slash command:", error); + showToast(`Failed to publish slash command: ${error.message}`, "error", { + clear: true, + }); + } finally { + setIsSubmitting(false); + } + }; + + const handleKeyDown = (e) => { + if (e.key === "Enter" || e.key === ",") { + e.preventDefault(); + const value = tagInput.trim(); + if (value.length > 20) return; + if (value && !tags.includes(value)) { + setTags((prevTags) => [...prevTags, value].slice(0, 5)); // Limit to 5 tags + setTagInput(""); + } + } + }; + + const removeTag = (tagToRemove) => { + setTags(tags.filter((tag) => tag !== tagToRemove)); + }; + + if (isSuccess) { + return ( +
+
+

+ {t("community_hub.publish.slash_command.success_title")} +

+

+ {t("community_hub.publish.slash_command.success_description")} +

+

+ {t("community_hub.publish.slash_command.success_thank_you")} +

+ + {t("community_hub.publish.slash_command.view_on_hub")} + +
+
+ ); + } + + return ( + <> +
+

+ {t("community_hub.publish.slash_command.modal_title")} + + {entity.command} + +

+
+
+
+
+ +
+ {t("community_hub.publish.slash_command.name_description")} +
+ +
+ +
+ +
+ {t("community_hub.publish.slash_command.description_description")} +
+