add Plugin page
This commit is contained in:
parent
571ce11e53
commit
cac99e3908
|
@ -59,6 +59,10 @@ const MaskPage = dynamic(async () => (await import("./mask")).MaskPage, {
|
||||||
loading: () => <Loading noLogo />,
|
loading: () => <Loading noLogo />,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const PluginPage = dynamic(async () => (await import("./plugin")).PluginPage, {
|
||||||
|
loading: () => <Loading noLogo />,
|
||||||
|
});
|
||||||
|
|
||||||
const SearchChat = dynamic(
|
const SearchChat = dynamic(
|
||||||
async () => (await import("./search-chat")).SearchChatPage,
|
async () => (await import("./search-chat")).SearchChatPage,
|
||||||
{
|
{
|
||||||
|
@ -181,6 +185,7 @@ function Screen() {
|
||||||
<Route path={Path.Home} element={<Chat />} />
|
<Route path={Path.Home} element={<Chat />} />
|
||||||
<Route path={Path.NewChat} element={<NewChat />} />
|
<Route path={Path.NewChat} element={<NewChat />} />
|
||||||
<Route path={Path.Masks} element={<MaskPage />} />
|
<Route path={Path.Masks} element={<MaskPage />} />
|
||||||
|
<Route path={Path.Plugins} element={<PluginPage />} />
|
||||||
<Route path={Path.SearchChat} element={<SearchChat />} />
|
<Route path={Path.SearchChat} element={<SearchChat />} />
|
||||||
<Route path={Path.Chat} element={<Chat />} />
|
<Route path={Path.Chat} element={<Chat />} />
|
||||||
<Route path={Path.Settings} element={<Settings />} />
|
<Route path={Path.Settings} element={<Settings />} />
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
import { IconButton } from "./button";
|
||||||
|
import { ErrorBoundary } from "./error";
|
||||||
|
|
||||||
|
import styles from "./mask.module.scss";
|
||||||
|
|
||||||
|
import DownloadIcon from "../icons/download.svg";
|
||||||
|
import EditIcon from "../icons/edit.svg";
|
||||||
|
import AddIcon from "../icons/add.svg";
|
||||||
|
import CloseIcon from "../icons/close.svg";
|
||||||
|
import DeleteIcon from "../icons/delete.svg";
|
||||||
|
import EyeIcon from "../icons/eye.svg";
|
||||||
|
import CopyIcon from "../icons/copy.svg";
|
||||||
|
|
||||||
|
import { Plugin, usePluginStore } from "../store/plugin";
|
||||||
|
import {
|
||||||
|
Input,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
Modal,
|
||||||
|
Popover,
|
||||||
|
Select,
|
||||||
|
showConfirm,
|
||||||
|
} from "./ui-lib";
|
||||||
|
import Locale from "../locales";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Path } from "../constant";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
|
export function PluginPage() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const pluginStore = usePluginStore();
|
||||||
|
const plugins = pluginStore.getAll();
|
||||||
|
|
||||||
|
const [editingPluginId, setEditingPluginId] = useState<string | undefined>();
|
||||||
|
const editingPlugin = pluginStore.get(editingPluginId);
|
||||||
|
const closePluginModal = () => setEditingPluginId(undefined);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<div className={styles["mask-page"]}>
|
||||||
|
<div className="window-header">
|
||||||
|
<div className="window-header-title">
|
||||||
|
<div className="window-header-main-title">
|
||||||
|
{Locale.Plugin.Page.Title}
|
||||||
|
</div>
|
||||||
|
<div className="window-header-submai-title">
|
||||||
|
{Locale.Plugin.Page.SubTitle(plugins.length)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="window-actions">
|
||||||
|
<div className="window-action-button">
|
||||||
|
<IconButton
|
||||||
|
icon={<CloseIcon />}
|
||||||
|
bordered
|
||||||
|
onClick={() => navigate(-1)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles["mask-page-body"]}>
|
||||||
|
<div>
|
||||||
|
{plugins.map((m) => (
|
||||||
|
<div className={styles["mask-item"]} key={m.id}>
|
||||||
|
<div className={styles["mask-header"]}>
|
||||||
|
<div className={styles["mask-icon"]}></div>
|
||||||
|
<div className={styles["mask-title"]}>
|
||||||
|
<div className={styles["mask-name"]}>
|
||||||
|
{m.title}@<small>{m.version}</small>
|
||||||
|
</div>
|
||||||
|
<div className={styles["mask-info"] + " one-line"}>
|
||||||
|
{`${Locale.Plugin.Item.Info(m.content.length)} / / `}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles["mask-actions"]}>
|
||||||
|
{m.builtin ? (
|
||||||
|
<IconButton
|
||||||
|
icon={<EyeIcon />}
|
||||||
|
text={Locale.Plugin.Item.View}
|
||||||
|
onClick={() => setEditingPluginId(m.id)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<IconButton
|
||||||
|
icon={<EditIcon />}
|
||||||
|
text={Locale.Plugin.Item.Edit}
|
||||||
|
onClick={() => setEditingPluginId(m.id)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!m.builtin && (
|
||||||
|
<IconButton
|
||||||
|
icon={<DeleteIcon />}
|
||||||
|
text={Locale.Plugin.Item.Delete}
|
||||||
|
onClick={async () => {
|
||||||
|
if (
|
||||||
|
await showConfirm(Locale.Plugin.Item.DeleteConfirm)
|
||||||
|
) {
|
||||||
|
pluginStore.delete(m.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{editingPlugin && (
|
||||||
|
<div className="modal-mask">
|
||||||
|
<Modal
|
||||||
|
title={Locale.Plugin.EditModal.Title(editingPlugin?.builtin)}
|
||||||
|
onClose={closePluginModal}
|
||||||
|
actions={[
|
||||||
|
<IconButton
|
||||||
|
icon={<DownloadIcon />}
|
||||||
|
text={Locale.Plugin.EditModal.Download}
|
||||||
|
key="export"
|
||||||
|
bordered
|
||||||
|
onClick={() =>
|
||||||
|
downloadAs(
|
||||||
|
JSON.stringify(editingPlugin),
|
||||||
|
`${editingPlugin.name}.json`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
<IconButton
|
||||||
|
key="copy"
|
||||||
|
icon={<CopyIcon />}
|
||||||
|
bordered
|
||||||
|
text={Locale.Plugin.EditModal.Clone}
|
||||||
|
onClick={() => {
|
||||||
|
navigate(Path.Plugins);
|
||||||
|
pluginStore.create(editingPlugin);
|
||||||
|
setEditingPluginId(undefined);
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
PluginConfig
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ export enum Path {
|
||||||
Settings = "/settings",
|
Settings = "/settings",
|
||||||
NewChat = "/new-chat",
|
NewChat = "/new-chat",
|
||||||
Masks = "/masks",
|
Masks = "/masks",
|
||||||
|
Plugins = "/plugins",
|
||||||
Auth = "/auth",
|
Auth = "/auth",
|
||||||
Sd = "/sd",
|
Sd = "/sd",
|
||||||
SdNew = "/sd-new",
|
SdNew = "/sd-new",
|
||||||
|
@ -480,6 +481,7 @@ export const internalAllowedWebDavEndpoints = [
|
||||||
|
|
||||||
export const DEFAULT_GA_ID = "G-89WN60ZK2E";
|
export const DEFAULT_GA_ID = "G-89WN60ZK2E";
|
||||||
export const PLUGINS = [
|
export const PLUGINS = [
|
||||||
|
{ name: "Plugins", path: Path.Plugins },
|
||||||
{ name: "Stable Diffusion", path: Path.Sd },
|
{ name: "Stable Diffusion", path: Path.Sd },
|
||||||
{ name: "Search Chat", path: Path.SearchChat },
|
{ name: "Search Chat", path: Path.SearchChat },
|
||||||
];
|
];
|
||||||
|
|
|
@ -542,6 +542,47 @@ const en: LocaleType = {
|
||||||
View: "View",
|
View: "View",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Plugin: {
|
||||||
|
Name: "Plugin",
|
||||||
|
Page: {
|
||||||
|
Title: "Plugins",
|
||||||
|
SubTitle: (count: number) => `${count} plugins`,
|
||||||
|
Search: "Search Plugin",
|
||||||
|
Create: "Create",
|
||||||
|
},
|
||||||
|
Item: {
|
||||||
|
Info: (count: number) => `${count} plugins`,
|
||||||
|
Chat: "Chat",
|
||||||
|
View: "View",
|
||||||
|
Edit: "Edit",
|
||||||
|
Delete: "Delete",
|
||||||
|
DeleteConfirm: "Confirm to delete?",
|
||||||
|
},
|
||||||
|
EditModal: {
|
||||||
|
Title: (readonly: boolean) =>
|
||||||
|
`Edit Plugin ${readonly ? "(readonly)" : ""}`,
|
||||||
|
Download: "Download",
|
||||||
|
Clone: "Clone",
|
||||||
|
},
|
||||||
|
Config: {
|
||||||
|
Avatar: "Bot Avatar",
|
||||||
|
Name: "Bot Name",
|
||||||
|
Sync: {
|
||||||
|
Title: "Use Global Config",
|
||||||
|
SubTitle: "Use global config in this chat",
|
||||||
|
Confirm: "Confirm to override custom config with global config?",
|
||||||
|
},
|
||||||
|
HideContext: {
|
||||||
|
Title: "Hide Context Prompts",
|
||||||
|
SubTitle: "Do not show in-context prompts in chat",
|
||||||
|
},
|
||||||
|
Share: {
|
||||||
|
Title: "Share This Plugin",
|
||||||
|
SubTitle: "Generate a link to this mask",
|
||||||
|
Action: "Copy Link",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
Mask: {
|
Mask: {
|
||||||
Name: "Mask",
|
Name: "Mask",
|
||||||
Page: {
|
Page: {
|
||||||
|
|
Loading…
Reference in New Issue