From 96b532a0f4741246a33844b809a11045ca384049 Mon Sep 17 00:00:00 2001 From: Sean Hatfield Date: Mon, 16 Jun 2025 09:59:38 -0700 Subject: [PATCH] Publish system prompts to hub (#3976) * 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 --------- Co-authored-by: Timothy Carambat --- .../SystemPrompts/index.jsx | 242 ++++++++++++++++++ .../CommunityHub/PublishEntityModal/index.jsx | 43 ++++ .../UnauthenticatedHubModal/index.jsx | 40 +++ frontend/src/hooks/useCommunityHubAuth.js | 30 +++ frontend/src/index.css | 2 + frontend/src/locales/ar/common.js | 29 +++ frontend/src/locales/da/common.js | 29 +++ frontend/src/locales/de/common.js | 29 +++ frontend/src/locales/en/common.js | 34 +++ frontend/src/locales/es/common.js | 29 +++ frontend/src/locales/fa/common.js | 29 +++ frontend/src/locales/fr/common.js | 29 +++ frontend/src/locales/he/common.js | 29 +++ frontend/src/locales/it/common.js | 29 +++ frontend/src/locales/ja/common.js | 29 +++ frontend/src/locales/ko/common.js | 29 +++ frontend/src/locales/lv/common.js | 29 +++ frontend/src/locales/nl/common.js | 29 +++ frontend/src/locales/pt_BR/common.js | 29 +++ frontend/src/locales/ru/common.js | 29 +++ frontend/src/locales/tr/common.js | 29 +++ frontend/src/locales/vn/common.js | 29 +++ frontend/src/locales/zh/common.js | 29 +++ frontend/src/locales/zh_TW/common.js | 29 +++ frontend/src/models/communityHub.js | 28 ++ .../PromptHistoryItem/index.jsx | 15 +- .../ChatPromptHistory/index.jsx | 3 +- .../ChatSettings/ChatPromptSettings/index.jsx | 76 ++++-- frontend/src/utils/paths.js | 3 + frontend/tailwind.config.js | 1 + server/endpoints/communityHub.js | 33 +++ server/models/communityHub.js | 36 +++ 32 files changed, 1090 insertions(+), 18 deletions(-) create mode 100644 frontend/src/components/CommunityHub/PublishEntityModal/SystemPrompts/index.jsx create mode 100644 frontend/src/components/CommunityHub/PublishEntityModal/index.jsx create mode 100644 frontend/src/components/CommunityHub/UnauthenticatedHubModal/index.jsx create mode 100644 frontend/src/hooks/useCommunityHubAuth.js diff --git a/frontend/src/components/CommunityHub/PublishEntityModal/SystemPrompts/index.jsx b/frontend/src/components/CommunityHub/PublishEntityModal/SystemPrompts/index.jsx new file mode 100644 index 00000000..a3187922 --- /dev/null +++ b/frontend/src/components/CommunityHub/PublishEntityModal/SystemPrompts/index.jsx @@ -0,0 +1,242 @@ +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/dist/ssr"; + +export default function SystemPrompts({ 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"), + prompt: form.get("prompt"), + tags: tags, + visibility: visibility, + }; + + const { success, error, itemId } = + await CommunityHub.createSystemPrompt(data); + if (!success) throw new Error(error); + setItemId(itemId); + setIsSuccess(true); + } catch (error) { + console.error("Failed to publish prompt:", error); + showToast(`Failed to publish prompt: ${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("chat.prompt.publish.success_title")} +

+

+ {t("chat.prompt.publish.success_description")} +

+

+ {t("chat.prompt.publish.success_thank_you")} +

+ + {t("chat.prompt.publish.view_on_hub")} + +
+
+ ); + } + + return ( + <> +
+

+ {t(`chat.prompt.publish.modal_title`)} +

+
+
+
+
+ +
+ {t("chat.prompt.publish.name_description")} +
+ +
+ +
+ +
+ {t("chat.prompt.publish.description_description")} +
+