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 <rambat1010@gmail.com>
This commit is contained in:
parent
7cef25822c
commit
96b532a0f4
@ -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 (
|
||||||
|
<div className="p-6 -mt-12 w-[400px]">
|
||||||
|
<div className="flex flex-col items-center justify-center gap-y-2">
|
||||||
|
<h3 className="text-lg font-semibold text-theme-text-primary">
|
||||||
|
{t("chat.prompt.publish.success_title")}
|
||||||
|
</h3>
|
||||||
|
<p className="text-lg text-theme-text-primary text-center max-w-2xl">
|
||||||
|
{t("chat.prompt.publish.success_description")}
|
||||||
|
</p>
|
||||||
|
<p className="text-theme-text-secondary text-center text-sm">
|
||||||
|
{t("chat.prompt.publish.success_thank_you")}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href={paths.communityHub.viewItem("system-prompt", itemId)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="w-[265px] bg-theme-bg-secondary hover:bg-theme-sidebar-item-hover text-theme-text-primary py-2 px-4 rounded-lg transition-colors mt-4 text-sm font-semibold text-center"
|
||||||
|
>
|
||||||
|
{t("chat.prompt.publish.view_on_hub")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="w-full flex gap-x-2 items-center mb-3 -mt-8">
|
||||||
|
<h3 className="text-xl font-semibold text-theme-text-primary px-6 py-3">
|
||||||
|
{t(`chat.prompt.publish.modal_title`)}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<form ref={formRef} className="flex" onSubmit={handleSubmit}>
|
||||||
|
<div className="w-1/2 p-6 pt-0 space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-theme-text-primary mb-1">
|
||||||
|
{t("chat.prompt.publish.name_label")}
|
||||||
|
</label>
|
||||||
|
<div className="text-xs text-theme-text-secondary mb-2">
|
||||||
|
{t("chat.prompt.publish.name_description")}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
required
|
||||||
|
minLength={3}
|
||||||
|
maxLength={300}
|
||||||
|
placeholder={t("chat.prompt.publish.name_placeholder")}
|
||||||
|
className="w-full bg-theme-bg-secondary rounded-lg p-2 text-theme-text-primary text-sm focus:outline-primary-button active:outline-primary-button outline-none placeholder:text-theme-text-placeholder"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-theme-text-primary mb-1">
|
||||||
|
{t("chat.prompt.publish.description_label")}
|
||||||
|
</label>
|
||||||
|
<div className="text-xs text-white/60 mb-2">
|
||||||
|
{t("chat.prompt.publish.description_description")}
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
name="description"
|
||||||
|
required
|
||||||
|
minLength={10}
|
||||||
|
maxLength={1000}
|
||||||
|
placeholder={t("chat.prompt.publish.description_description")}
|
||||||
|
className="w-full bg-theme-bg-secondary rounded-lg p-2 text-white text-sm focus:outline-primary-button active:outline-primary-button outline-none min-h-[80px] placeholder:text-theme-text-placeholder"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-white mb-1">
|
||||||
|
{t("chat.prompt.publish.tags_label")}
|
||||||
|
</label>
|
||||||
|
<div className="text-xs text-white/60 mb-2">
|
||||||
|
{t("chat.prompt.publish.tags_description")}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 p-2 bg-theme-bg-secondary rounded-lg min-h-[42px]">
|
||||||
|
{tags.map((tag, index) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className="flex items-center gap-1 px-2 py-1 text-sm text-theme-text-primary bg-white/10 light:bg-black/10 rounded-md"
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeTag(tag)}
|
||||||
|
className="border-none text-theme-text-primary hover:text-theme-text-secondary cursor-pointer"
|
||||||
|
>
|
||||||
|
<X size={14} />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={tagInput}
|
||||||
|
onChange={(e) => setTagInput(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
placeholder={t("chat.prompt.publish.tags_placeholder")}
|
||||||
|
className="flex-1 min-w-[200px] border-none text-sm bg-transparent text-theme-text-primary placeholder:text-theme-text-placeholder p-0 h-[24px] focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-white mb-1">
|
||||||
|
{t("chat.prompt.publish.visibility_label")}
|
||||||
|
</label>
|
||||||
|
<div className="text-xs text-white/60 mb-2">
|
||||||
|
{visibility === "public"
|
||||||
|
? t("chat.prompt.publish.public_description")
|
||||||
|
: t("chat.prompt.publish.private_description")}
|
||||||
|
</div>
|
||||||
|
<div className="w-fit h-[42px] bg-theme-bg-secondary rounded-lg p-0.5">
|
||||||
|
<div className="flex items-center" role="group">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="public"
|
||||||
|
name="visibility"
|
||||||
|
value="public"
|
||||||
|
className="peer/public hidden"
|
||||||
|
defaultChecked
|
||||||
|
onChange={(e) => setVisibility(e.target.value)}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="private"
|
||||||
|
name="visibility"
|
||||||
|
value="private"
|
||||||
|
className="peer/private hidden"
|
||||||
|
onChange={(e) => setVisibility(e.target.value)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="public"
|
||||||
|
className="h-[36px] px-4 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer text-theme-text-primary hover:text-theme-text-secondary peer-checked/public:bg-theme-sidebar-item-hover peer-checked/public:text-theme-primary-button flex items-center justify-center"
|
||||||
|
>
|
||||||
|
Public
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
htmlFor="private"
|
||||||
|
className="h-[36px] px-4 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer text-theme-text-primary hover:text-theme-text-secondary peer-checked/private:bg-theme-sidebar-item-hover peer-checked/private:text-theme-primary-button flex items-center justify-center"
|
||||||
|
>
|
||||||
|
Private
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2 p-6 pt-0 space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-white mb-1">
|
||||||
|
{t("chat.prompt.publish.prompt_label")}
|
||||||
|
</label>
|
||||||
|
<div className="text-xs text-white/60 mb-2">
|
||||||
|
{t("chat.prompt.publish.prompt_description")}
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
name="prompt"
|
||||||
|
required
|
||||||
|
minLength={10}
|
||||||
|
defaultValue={entity}
|
||||||
|
placeholder={t("chat.prompt.publish.prompt_placeholder")}
|
||||||
|
className="w-full bg-theme-bg-secondary rounded-lg p-2 text-white text-sm focus:outline-primary-button active:outline-primary-button outline-none min-h-[300px] placeholder:text-theme-text-placeholder"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
className="w-full bg-cta-button hover:opacity-80 text-theme-text-primary font-medium py-2 px-4 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
{isSubmitting
|
||||||
|
? t("chat.prompt.publish.publishing")
|
||||||
|
: t("chat.prompt.publish.publish_button")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { X } from "@phosphor-icons/react";
|
||||||
|
import { useCommunityHubAuth } from "@/hooks/useCommunityHubAuth";
|
||||||
|
import UnauthenticatedHubModal from "@/components/CommunityHub/UnauthenticatedHubModal";
|
||||||
|
import SystemPrompts from "./SystemPrompts";
|
||||||
|
import ModalWrapper from "@/components/ModalWrapper";
|
||||||
|
|
||||||
|
export default function PublishEntityModal({
|
||||||
|
show,
|
||||||
|
onClose,
|
||||||
|
entityType,
|
||||||
|
entity,
|
||||||
|
}) {
|
||||||
|
const { isAuthenticated, loading } = useCommunityHubAuth();
|
||||||
|
if (!show || loading) return null;
|
||||||
|
if (!isAuthenticated)
|
||||||
|
return <UnauthenticatedHubModal show={show} onClose={onClose} />;
|
||||||
|
|
||||||
|
const renderEntityForm = () => {
|
||||||
|
switch (entityType) {
|
||||||
|
case "system-prompt":
|
||||||
|
return <SystemPrompts entity={entity} />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalWrapper isOpen={show}>
|
||||||
|
<div className="relative max-w-[900px] bg-theme-bg-primary rounded-lg shadow border border-theme-modal-border">
|
||||||
|
<div className="relative p-6">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
type="button"
|
||||||
|
className="absolute top-4 right-4 transition-all duration-300 bg-transparent rounded-lg text-sm p-1 inline-flex items-center hover:bg-theme-modal-border hover:border-theme-modal-border hover:border-opacity-50 border-transparent border"
|
||||||
|
>
|
||||||
|
<X size={18} weight="bold" className="text-white" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{renderEntityForm()}
|
||||||
|
</div>
|
||||||
|
</ModalWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { X } from "@phosphor-icons/react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import paths from "@/utils/paths";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import ModalWrapper from "@/components/ModalWrapper";
|
||||||
|
|
||||||
|
export default function UnauthenticatedHubModal({ show, onClose }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
if (!show) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalWrapper isOpen={show}>
|
||||||
|
<div className="relative w-[400px] max-w-full bg-theme-bg-primary rounded-lg shadow border border-theme-modal-border">
|
||||||
|
<div className="p-6">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
type="button"
|
||||||
|
className="absolute top-4 right-4 transition-all duration-300 bg-transparent rounded-lg text-sm p-1 inline-flex items-center hover:bg-theme-modal-border hover:border-theme-modal-border hover:border-opacity-50 border-transparent border"
|
||||||
|
>
|
||||||
|
<X size={18} weight="bold" className="text-white" />
|
||||||
|
</button>
|
||||||
|
<div className="flex flex-col items-center justify-center gap-y-4">
|
||||||
|
<h3 className="text-lg font-semibold text-white">
|
||||||
|
{t("chat.prompt.publish.unauthenticated.title")}
|
||||||
|
</h3>
|
||||||
|
<p className="text-lg text-white text-center max-w-[300px]">
|
||||||
|
{t("chat.prompt.publish.unauthenticated.description")}
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
to={paths.communityHub.authentication()}
|
||||||
|
className="w-[265px] bg-theme-bg-secondary hover:bg-theme-sidebar-item-hover text-theme-text-primary py-2 px-4 rounded-lg transition-colors mt-4 text-sm font-semibold text-center"
|
||||||
|
>
|
||||||
|
{t("chat.prompt.publish.unauthenticated.button")}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
30
frontend/src/hooks/useCommunityHubAuth.js
Normal file
30
frontend/src/hooks/useCommunityHubAuth.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import CommunityHub from "@/models/communityHub";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to check if the user is authenticated with the community hub by checking
|
||||||
|
* the user defined connection key in the settings.
|
||||||
|
* @returns {{isAuthenticated: boolean, loading: boolean}} An object containing the authentication status and loading state.
|
||||||
|
*/
|
||||||
|
export function useCommunityHubAuth() {
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function checkCommunityHubAuth() {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const { connectionKey } = await CommunityHub.getSettings();
|
||||||
|
setIsAuthenticated(!!connectionKey);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error checking hub auth:", error);
|
||||||
|
setIsAuthenticated(false);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCommunityHubAuth();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { isAuthenticated, loading };
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@
|
|||||||
--theme-bg-chat-input: #27282a;
|
--theme-bg-chat-input: #27282a;
|
||||||
--theme-text-primary: #ffffff;
|
--theme-text-primary: #ffffff;
|
||||||
--theme-text-secondary: rgba(255, 255, 255, 0.6);
|
--theme-text-secondary: rgba(255, 255, 255, 0.6);
|
||||||
|
--theme-placeholder: #57585a;
|
||||||
--theme-sidebar-item-default: rgba(255, 255, 255, 0.1);
|
--theme-sidebar-item-default: rgba(255, 255, 255, 0.1);
|
||||||
--theme-sidebar-item-selected: rgba(255, 255, 255, 0.3);
|
--theme-sidebar-item-selected: rgba(255, 255, 255, 0.3);
|
||||||
--theme-sidebar-item-hover: #3f3f42;
|
--theme-sidebar-item-hover: #3f3f42;
|
||||||
@ -116,6 +117,7 @@
|
|||||||
--theme-bg-chat-input: #eaeaea;
|
--theme-bg-chat-input: #eaeaea;
|
||||||
--theme-text-primary: #0e0f0f;
|
--theme-text-primary: #0e0f0f;
|
||||||
--theme-text-secondary: #7a7d7e;
|
--theme-text-secondary: #7a7d7e;
|
||||||
|
--theme-placeholder: #9ca3af;
|
||||||
--theme-sidebar-item-default: #ffffff;
|
--theme-sidebar-item-default: #ffffff;
|
||||||
--theme-sidebar-item-selected: #ffffff;
|
--theme-sidebar-item-selected: #ffffff;
|
||||||
--theme-sidebar-item-hover: #c8efff;
|
--theme-sidebar-item-hover: #c8efff;
|
||||||
|
|||||||
@ -240,6 +240,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -241,6 +241,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -233,6 +233,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -335,11 +335,45 @@ const TRANSLATIONS = {
|
|||||||
noHistory: "No system prompt history available",
|
noHistory: "No system prompt history available",
|
||||||
restore: "Restore",
|
restore: "Restore",
|
||||||
delete: "Delete",
|
delete: "Delete",
|
||||||
|
publish: "Publish to Community Hub",
|
||||||
deleteConfirm: "Are you sure you want to delete this history item?",
|
deleteConfirm: "Are you sure you want to delete this history item?",
|
||||||
clearAllConfirm:
|
clearAllConfirm:
|
||||||
"Are you sure you want to clear all history? This action cannot be undone.",
|
"Are you sure you want to clear all history? This action cannot be undone.",
|
||||||
expand: "Expand",
|
expand: "Expand",
|
||||||
},
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: "Public system prompts are visible to everyone.",
|
||||||
|
private_description: "Private system prompts are only visible to you.",
|
||||||
|
success_title: "Success!",
|
||||||
|
success_description:
|
||||||
|
"Your System Prompt has been published to the Community Hub!",
|
||||||
|
success_thank_you: "Thank you for sharing to the Community!",
|
||||||
|
view_on_hub: "View on Community Hub",
|
||||||
|
modal_title: "Publish System Prompt",
|
||||||
|
name_label: "Name",
|
||||||
|
name_description: "This is the display name of your system prompt.",
|
||||||
|
name_placeholder: "My System Prompt",
|
||||||
|
description_label: "Description",
|
||||||
|
description_description:
|
||||||
|
"This is the description of your system prompt. Use this to describe the purpose of your system prompt.",
|
||||||
|
tags_label: "Tags",
|
||||||
|
tags_description:
|
||||||
|
"Tags are used to label your system prompt for easier searching. You can add multiple tags. Max 5 tags. Max 20 characters per tag.",
|
||||||
|
tags_placeholder: "Type and press Enter to add tags",
|
||||||
|
visibility_label: "Visibility",
|
||||||
|
prompt_label: "Prompt",
|
||||||
|
prompt_description:
|
||||||
|
"This is the actual slash command that will be used to guide the LLM.",
|
||||||
|
prompt_placeholder: "Enter your system prompt here...",
|
||||||
|
publish_button: "Publish to Community Hub",
|
||||||
|
publishing: "Publishing...",
|
||||||
|
unauthenticated: {
|
||||||
|
title: "Authentication Required",
|
||||||
|
description:
|
||||||
|
"You need to authenticate with the AnythingLLM Community Hub before publishing prompts.",
|
||||||
|
button: "Connect to Community Hub",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
title: "Query mode refusal response",
|
title: "Query mode refusal response",
|
||||||
|
|||||||
@ -235,6 +235,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -231,6 +231,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -236,6 +236,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -229,6 +229,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -234,6 +234,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -240,6 +240,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -229,6 +229,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -325,6 +325,35 @@ const TRANSLATIONS = {
|
|||||||
clearAllConfirm:
|
clearAllConfirm:
|
||||||
"Vai tiešām vēlaties nodzēst visu vēsturi? Šo darbību nevar atsaukt.",
|
"Vai tiešām vēlaties nodzēst visu vēsturi? Šo darbību nevar atsaukt.",
|
||||||
expand: "Paplašināt",
|
expand: "Paplašināt",
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -233,6 +233,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -322,6 +322,35 @@ const TRANSLATIONS = {
|
|||||||
clearAllConfirm:
|
clearAllConfirm:
|
||||||
"Tem certeza que deseja limpar todo o histórico? Esta ação é irreversível.",
|
"Tem certeza que deseja limpar todo o histórico? Esta ação é irreversível.",
|
||||||
expand: "Expandir",
|
expand: "Expandir",
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -242,6 +242,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -233,6 +233,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -232,6 +232,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -312,6 +312,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: "您确定要删除此历史记录吗?",
|
deleteConfirm: "您确定要删除此历史记录吗?",
|
||||||
clearAllConfirm: "您确定要清除所有历史记录吗?此操作无法撤消。",
|
clearAllConfirm: "您确定要清除所有历史记录吗?此操作无法撤消。",
|
||||||
expand: "展开",
|
expand: "展开",
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -230,6 +230,35 @@ const TRANSLATIONS = {
|
|||||||
deleteConfirm: null,
|
deleteConfirm: null,
|
||||||
clearAllConfirm: null,
|
clearAllConfirm: null,
|
||||||
expand: null,
|
expand: null,
|
||||||
|
publish: null,
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
public_description: null,
|
||||||
|
private_description: null,
|
||||||
|
success_title: null,
|
||||||
|
success_description: null,
|
||||||
|
success_thank_you: null,
|
||||||
|
view_on_hub: null,
|
||||||
|
modal_title: null,
|
||||||
|
name_label: null,
|
||||||
|
name_description: null,
|
||||||
|
name_placeholder: null,
|
||||||
|
description_label: null,
|
||||||
|
description_description: null,
|
||||||
|
tags_label: null,
|
||||||
|
tags_description: null,
|
||||||
|
tags_placeholder: null,
|
||||||
|
visibility_label: null,
|
||||||
|
prompt_label: null,
|
||||||
|
prompt_description: null,
|
||||||
|
prompt_placeholder: null,
|
||||||
|
publish_button: null,
|
||||||
|
publishing: null,
|
||||||
|
unauthenticated: {
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
button: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refusal: {
|
refusal: {
|
||||||
|
|||||||
@ -153,6 +153,34 @@ const CommunityHub = {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new system prompt in the community hub
|
||||||
|
* @param {Object} data - The system prompt data
|
||||||
|
* @param {string} data.name - The name of the prompt
|
||||||
|
* @param {string} data.description - The description of the prompt
|
||||||
|
* @param {string} data.prompt - The actual system prompt text
|
||||||
|
* @param {string[]} data.tags - Array of tags
|
||||||
|
* @param {string} data.visibility - Either 'public' or 'private'
|
||||||
|
* @returns {Promise<{success: boolean, error: string | null}>}
|
||||||
|
*/
|
||||||
|
createSystemPrompt: async (data) => {
|
||||||
|
return await fetch(`${API_BASE}/community-hub/system-prompt/create`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
const response = await res.json();
|
||||||
|
if (!res.ok)
|
||||||
|
throw new Error(response.error || "Failed to create system prompt");
|
||||||
|
return { success: true, error: null, itemId: response.item?.id };
|
||||||
|
})
|
||||||
|
.catch((e) => ({
|
||||||
|
success: false,
|
||||||
|
error: e.message,
|
||||||
|
}));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CommunityHub;
|
export default CommunityHub;
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export default function PromptHistoryItem({
|
|||||||
user,
|
user,
|
||||||
onRestore,
|
onRestore,
|
||||||
setHistory,
|
setHistory,
|
||||||
|
onPublishClick,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
@ -82,11 +83,21 @@ export default function PromptHistoryItem({
|
|||||||
{showMenu && (
|
{showMenu && (
|
||||||
<div
|
<div
|
||||||
ref={menuRef}
|
ref={menuRef}
|
||||||
className="absolute right-0 top-6 bg-theme-bg-popup-menu rounded-lg z-50"
|
className="absolute right-0 top-6 bg-theme-bg-popup-menu rounded-lg z-50 min-w-[200px]"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="px-[10px] py-[6px] text-sm text-white hover:bg-theme-hover cursor-pointer border-none"
|
className="px-[10px] py-[6px] text-sm text-white hover:bg-theme-sidebar-item-hover rounded-t-lg cursor-pointer border-none w-full text-left whitespace-nowrap"
|
||||||
|
onClick={() => {
|
||||||
|
setShowMenu(false);
|
||||||
|
onPublishClick(prompt);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("chat.prompt.history.publish")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="px-[10px] py-[6px] text-sm text-white hover:bg-red-500/60 light:hover:bg-red-300/80 rounded-b-lg cursor-pointer border-none w-full text-left whitespace-nowrap"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
deleteHistory(id);
|
deleteHistory(id);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import * as Skeleton from "react-loading-skeleton";
|
|||||||
import "react-loading-skeleton/dist/skeleton.css";
|
import "react-loading-skeleton/dist/skeleton.css";
|
||||||
|
|
||||||
export default forwardRef(function ChatPromptHistory(
|
export default forwardRef(function ChatPromptHistory(
|
||||||
{ show, workspaceSlug, onRestore, onClose },
|
{ show, workspaceSlug, onRestore, onClose, onPublishClick },
|
||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -92,6 +92,7 @@ export default forwardRef(function ChatPromptHistory(
|
|||||||
id={item.id}
|
id={item.id}
|
||||||
{...item}
|
{...item}
|
||||||
onRestore={() => onRestore(item.prompt)}
|
onRestore={() => onRestore(item.prompt)}
|
||||||
|
onPublishClick={onPublishClick}
|
||||||
setHistory={setHistory}
|
setHistory={setHistory}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import Highlighter from "react-highlight-words";
|
|||||||
import { Link, useSearchParams } from "react-router-dom";
|
import { Link, useSearchParams } from "react-router-dom";
|
||||||
import paths from "@/utils/paths";
|
import paths from "@/utils/paths";
|
||||||
import ChatPromptHistory from "./ChatPromptHistory";
|
import ChatPromptHistory from "./ChatPromptHistory";
|
||||||
|
import PublishEntityModal from "@/components/CommunityHub/PublishEntityModal";
|
||||||
|
import { useModal } from "@/hooks/useModal";
|
||||||
|
|
||||||
// TODO: Move to backend and have user-language sensitive default prompt
|
// TODO: Move to backend and have user-language sensitive default prompt
|
||||||
const DEFAULT_PROMPT =
|
const DEFAULT_PROMPT =
|
||||||
@ -21,13 +23,12 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
|
|||||||
const promptHistoryRef = useRef(null);
|
const promptHistoryRef = useRef(null);
|
||||||
const historyButtonRef = useRef(null);
|
const historyButtonRef = useRef(null);
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
const {
|
||||||
const handleRestore = (prompt) => {
|
isOpen: showPublishModal,
|
||||||
setPrompt(prompt);
|
closeModal: closePublishModal,
|
||||||
setShowPromptHistory(false);
|
openModal: openPublishModal,
|
||||||
setHasChanges(true);
|
} = useModal();
|
||||||
// TODO: Autosave on restore
|
const [currentPrompt, setCurrentPrompt] = useState(chatPrompt(workspace));
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function setupVariableHighlighting() {
|
async function setupVariableHighlighting() {
|
||||||
@ -66,6 +67,18 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleRestore = (prompt) => {
|
||||||
|
setPrompt(prompt);
|
||||||
|
setShowPromptHistory(false);
|
||||||
|
setHasChanges(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePublishClick = (prompt) => {
|
||||||
|
setCurrentPrompt(prompt);
|
||||||
|
setShowPromptHistory(false);
|
||||||
|
openPublishModal();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ChatPromptHistory
|
<ChatPromptHistory
|
||||||
@ -73,6 +86,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
|
|||||||
workspaceSlug={workspace.slug}
|
workspaceSlug={workspace.slug}
|
||||||
show={showPromptHistory}
|
show={showPromptHistory}
|
||||||
onRestore={handleRestore}
|
onRestore={handleRestore}
|
||||||
|
onPublishClick={handlePublishClick}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setShowPromptHistory(false);
|
setShowPromptHistory(false);
|
||||||
}}
|
}}
|
||||||
@ -120,7 +134,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
|
|||||||
<button
|
<button
|
||||||
ref={historyButtonRef}
|
ref={historyButtonRef}
|
||||||
type="button"
|
type="button"
|
||||||
className="text-theme-text-secondary hover:text-white light:hover:text-black text-sm font-medium"
|
className="text-theme-text-secondary hover:text-white light:hover:text-black text-xs font-medium"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShowPromptHistory(!showPromptHistory);
|
setShowPromptHistory(!showPromptHistory);
|
||||||
@ -186,17 +200,49 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row items-center justify-between pt-2">
|
<div className="w-full flex flex-row items-center justify-between pt-2">
|
||||||
{prompt !== DEFAULT_PROMPT && (
|
{prompt !== DEFAULT_PROMPT && (
|
||||||
<button
|
<>
|
||||||
type="button"
|
<button
|
||||||
onClick={() => handleRestore(DEFAULT_PROMPT)}
|
type="button"
|
||||||
className="text-theme-text-primary hover:text-white light:hover:text-black text-sm font-medium"
|
onClick={() => handleRestore(DEFAULT_PROMPT)}
|
||||||
>
|
className="text-theme-text-primary hover:text-white light:hover:text-black text-xs font-medium"
|
||||||
Clear
|
>
|
||||||
</button>
|
Clear
|
||||||
|
</button>
|
||||||
|
<PublishPromptCTA
|
||||||
|
hidden={
|
||||||
|
isEditing ||
|
||||||
|
prompt === DEFAULT_PROMPT ||
|
||||||
|
prompt?.trim().length < 10
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentPrompt(prompt);
|
||||||
|
openPublishModal();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<PublishEntityModal
|
||||||
|
show={showPublishModal}
|
||||||
|
onClose={closePublishModal}
|
||||||
|
entityType="system-prompt"
|
||||||
|
entity={currentPrompt}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function PublishPromptCTA({ hidden = false, onClick }) {
|
||||||
|
if (hidden) return null;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onClick}
|
||||||
|
className="border-none text-primary-button hover:text-white light:hover:text-black text-xs font-medium"
|
||||||
|
>
|
||||||
|
Publish to Community Hub
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -184,6 +184,9 @@ export default {
|
|||||||
viewMoreOfType: function (type) {
|
viewMoreOfType: function (type) {
|
||||||
return `${this.website()}/list/${type}`;
|
return `${this.website()}/list/${type}`;
|
||||||
},
|
},
|
||||||
|
viewItem: function (type, id) {
|
||||||
|
return `${this.website()}/i/${type}/${id}`;
|
||||||
|
},
|
||||||
trending: () => {
|
trending: () => {
|
||||||
return `/settings/community-hub/trending`;
|
return `/settings/community-hub/trending`;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -61,6 +61,7 @@ export default {
|
|||||||
text: {
|
text: {
|
||||||
primary: 'var(--theme-text-primary)',
|
primary: 'var(--theme-text-primary)',
|
||||||
secondary: 'var(--theme-text-secondary)',
|
secondary: 'var(--theme-text-secondary)',
|
||||||
|
placeholder: 'var(--theme-placeholder)',
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
item: {
|
item: {
|
||||||
|
|||||||
@ -181,6 +181,39 @@ function communityHubEndpoints(app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
"/community-hub/:communityHubItemType/create",
|
||||||
|
[validatedRequest, flexUserRoleValid([ROLES.admin])],
|
||||||
|
async (request, response) => {
|
||||||
|
try {
|
||||||
|
const { communityHubItemType } = request.params;
|
||||||
|
const { connectionKey } = await SystemSettings.hubSettings();
|
||||||
|
if (!connectionKey)
|
||||||
|
throw new Error("Community Hub connection key not found");
|
||||||
|
|
||||||
|
const data = reqBody(request);
|
||||||
|
const { success, error, itemId } = await CommunityHub.createStaticItem(
|
||||||
|
communityHubItemType,
|
||||||
|
data,
|
||||||
|
connectionKey
|
||||||
|
);
|
||||||
|
if (!success) throw new Error(error);
|
||||||
|
|
||||||
|
await EventLogs.logEvent(
|
||||||
|
"community_hub_publish",
|
||||||
|
{ itemType: communityHubItemType },
|
||||||
|
response.locals?.user?.id
|
||||||
|
);
|
||||||
|
response
|
||||||
|
.status(200)
|
||||||
|
.json({ success: true, error: null, item: { id: itemId } });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
response.status(500).json({ success: false, error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { communityHubEndpoints };
|
module.exports = { communityHubEndpoints };
|
||||||
|
|||||||
@ -9,6 +9,7 @@ const CommunityHub = {
|
|||||||
process.env.NODE_ENV === "development"
|
process.env.NODE_ENV === "development"
|
||||||
? "http://127.0.0.1:5001/anythingllm-hub/us-central1/external/v1"
|
? "http://127.0.0.1:5001/anythingllm-hub/us-central1/external/v1"
|
||||||
: "https://hub.external.anythingllm.com/v1",
|
: "https://hub.external.anythingllm.com/v1",
|
||||||
|
supportedStaticItemTypes: ["system-prompt"],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate an import ID and return the entity type and ID.
|
* Validate an import ID and return the entity type and ID.
|
||||||
@ -172,6 +173,41 @@ const CommunityHub = {
|
|||||||
return { createdByMe: {}, teamItems: [] };
|
return { createdByMe: {}, teamItems: [] };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new item in the community hub - Only supports STATIC items for now.
|
||||||
|
* @param {string} itemType - The type of item to create
|
||||||
|
* @param {object} data - The item data
|
||||||
|
* @param {string} connectionKey - The hub connection key
|
||||||
|
* @returns {Promise<{success: boolean, error: string | null}>}
|
||||||
|
*/
|
||||||
|
createStaticItem: async function (itemType, data, connectionKey) {
|
||||||
|
if (!connectionKey)
|
||||||
|
return { success: false, error: "Connection key is required" };
|
||||||
|
if (!this.supportedStaticItemTypes.includes(itemType))
|
||||||
|
return { success: false, error: "Unsupported item type" };
|
||||||
|
|
||||||
|
// If the item has specical considerations or preprocessing, we can delegate that below before sending the request.
|
||||||
|
// eg: Agent flow files and such.
|
||||||
|
|
||||||
|
return await fetch(`${this.apiBase}/${itemType}/create`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${connectionKey}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((result) => {
|
||||||
|
if (!!result.error) throw new Error(result.error || "Unknown error");
|
||||||
|
return { success: true, error: null, itemId: result.item.id };
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(`Error creating ${itemType}:`, error);
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { CommunityHub };
|
module.exports = { CommunityHub };
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user