mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
Make textAtom and showTocAtom in Markdown element optional (#331)
Fix backwards-compatibility for the Markdown element by adding back the option to pass text directly to the element and make atom parameters optional.
This commit is contained in:
parent
fc5e53e476
commit
015ebf5dd5
@ -8,7 +8,8 @@ import ReactMarkdown from "react-markdown";
|
|||||||
import rehypeRaw from "rehype-raw";
|
import rehypeRaw from "rehype-raw";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
|
|
||||||
import { Atom, useAtomValue } from "jotai";
|
import { useAtomValueSafe } from "@/util/util";
|
||||||
|
import { Atom } from "jotai";
|
||||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
||||||
import RemarkFlexibleToc, { TocItem } from "remark-flexible-toc";
|
import RemarkFlexibleToc, { TocItem } from "remark-flexible-toc";
|
||||||
import { useHeight } from "../hook/useHeight";
|
import { useHeight } from "../hook/useHeight";
|
||||||
@ -75,17 +76,18 @@ const CodeBlock = ({ children, onClickExecute }: CodeBlockProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type MarkdownProps = {
|
type MarkdownProps = {
|
||||||
textAtom: Atom<string> | Atom<Promise<string>>;
|
text?: string;
|
||||||
showTocAtom: Atom<boolean>;
|
textAtom?: Atom<string> | Atom<Promise<string>>;
|
||||||
|
showTocAtom?: Atom<boolean>;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
className?: string;
|
className?: string;
|
||||||
onClickExecute?: (cmd: string) => void;
|
onClickExecute?: (cmd: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Markdown = ({ textAtom, showTocAtom, style, className, onClickExecute }: MarkdownProps) => {
|
const Markdown = ({ text, textAtom, showTocAtom, style, className, onClickExecute }: MarkdownProps) => {
|
||||||
const text = useAtomValue(textAtom);
|
const textAtomValue = useAtomValueSafe(textAtom);
|
||||||
const tocRef = useRef<TocItem[]>([]);
|
const tocRef = useRef<TocItem[]>([]);
|
||||||
const showToc = useAtomValue(showTocAtom);
|
const showToc = useAtomValueSafe(showTocAtom) ?? false;
|
||||||
const contentsRef = useRef<HTMLDivElement>(null);
|
const contentsRef = useRef<HTMLDivElement>(null);
|
||||||
const contentsHeight = useHeight(contentsRef, 200);
|
const contentsHeight = useHeight(contentsRef, 200);
|
||||||
|
|
||||||
@ -133,6 +135,8 @@ const Markdown = ({ textAtom, showTocAtom, style, className, onClickExecute }: M
|
|||||||
}
|
}
|
||||||
}, [showToc, tocRef]);
|
}, [showToc, tocRef]);
|
||||||
|
|
||||||
|
text = textAtomValue ?? text;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx("markdown", className)} style={style} ref={contentsRef}>
|
<div className={clsx("markdown", className)} style={style} ref={contentsRef}>
|
||||||
<OverlayScrollbarsComponent
|
<OverlayScrollbarsComponent
|
||||||
|
@ -5,17 +5,18 @@ import { Modal } from "@/app/modals/modal";
|
|||||||
import { Markdown } from "@/element/markdown";
|
import { Markdown } from "@/element/markdown";
|
||||||
import { modalsModel } from "@/store/modalmodel";
|
import { modalsModel } from "@/store/modalmodel";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
import * as React from "react";
|
|
||||||
import { UserInputService } from "../store/services";
|
import { UserInputService } from "../store/services";
|
||||||
|
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import "./userinputmodal.less";
|
import "./userinputmodal.less";
|
||||||
|
|
||||||
const UserInputModal = (userInputRequest: UserInputRequest) => {
|
const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||||
const [responseText, setResponseText] = React.useState("");
|
const [responseText, setResponseText] = useState("");
|
||||||
const [countdown, setCountdown] = React.useState(Math.floor(userInputRequest.timeoutms / 1000));
|
const [countdown, setCountdown] = useState(Math.floor(userInputRequest.timeoutms / 1000));
|
||||||
const checkboxStatus = React.useRef(false);
|
const checkboxStatus = useRef(false);
|
||||||
|
const queryTextAtom = useState;
|
||||||
|
|
||||||
const handleSendCancel = React.useCallback(() => {
|
const handleSendCancel = useCallback(() => {
|
||||||
UserInputService.SendUserInputResponse({
|
UserInputService.SendUserInputResponse({
|
||||||
type: "userinputresp",
|
type: "userinputresp",
|
||||||
requestid: userInputRequest.requestid,
|
requestid: userInputRequest.requestid,
|
||||||
@ -24,7 +25,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
modalsModel.popModal();
|
modalsModel.popModal();
|
||||||
}, [responseText, userInputRequest]);
|
}, [responseText, userInputRequest]);
|
||||||
|
|
||||||
const handleSendText = React.useCallback(() => {
|
const handleSendText = useCallback(() => {
|
||||||
UserInputService.SendUserInputResponse({
|
UserInputService.SendUserInputResponse({
|
||||||
type: "userinputresp",
|
type: "userinputresp",
|
||||||
requestid: userInputRequest.requestid,
|
requestid: userInputRequest.requestid,
|
||||||
@ -34,7 +35,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
modalsModel.popModal();
|
modalsModel.popModal();
|
||||||
}, [responseText, userInputRequest]);
|
}, [responseText, userInputRequest]);
|
||||||
|
|
||||||
const handleSendConfirm = React.useCallback(() => {
|
const handleSendConfirm = useCallback(() => {
|
||||||
UserInputService.SendUserInputResponse({
|
UserInputService.SendUserInputResponse({
|
||||||
type: "userinputresp",
|
type: "userinputresp",
|
||||||
requestid: userInputRequest.requestid,
|
requestid: userInputRequest.requestid,
|
||||||
@ -44,7 +45,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
modalsModel.popModal();
|
modalsModel.popModal();
|
||||||
}, [userInputRequest]);
|
}, [userInputRequest]);
|
||||||
|
|
||||||
const handleSubmit = React.useCallback(() => {
|
const handleSubmit = useCallback(() => {
|
||||||
switch (userInputRequest.responsetype) {
|
switch (userInputRequest.responsetype) {
|
||||||
case "text":
|
case "text":
|
||||||
handleSendText();
|
handleSendText();
|
||||||
@ -55,7 +56,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
}
|
}
|
||||||
}, [handleSendConfirm, handleSendText, userInputRequest.responsetype]);
|
}, [handleSendConfirm, handleSendText, userInputRequest.responsetype]);
|
||||||
|
|
||||||
const handleKeyDown = React.useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(waveEvent: WaveKeyboardEvent): boolean => {
|
(waveEvent: WaveKeyboardEvent): boolean => {
|
||||||
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
|
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
|
||||||
handleSendCancel();
|
handleSendCancel();
|
||||||
@ -69,14 +70,14 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
[handleSendCancel, handleSubmit]
|
[handleSendCancel, handleSubmit]
|
||||||
);
|
);
|
||||||
|
|
||||||
const queryText = React.useMemo(() => {
|
const queryText = useMemo(() => {
|
||||||
if (userInputRequest.markdown) {
|
if (userInputRequest.markdown) {
|
||||||
return <Markdown text={userInputRequest.querytext} className="userinput-markdown" />;
|
return <Markdown text={userInputRequest.querytext} className="userinput-markdown" />;
|
||||||
}
|
}
|
||||||
return <span className="userinput-text">{userInputRequest.querytext}</span>;
|
return <span className="userinput-text">{userInputRequest.querytext}</span>;
|
||||||
}, [userInputRequest.markdown, userInputRequest.querytext]);
|
}, [userInputRequest.markdown, userInputRequest.querytext]);
|
||||||
|
|
||||||
const inputBox = React.useMemo(() => {
|
const inputBox = useMemo(() => {
|
||||||
if (userInputRequest.responsetype === "confirm") {
|
if (userInputRequest.responsetype === "confirm") {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@ -93,7 +94,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
|||||||
);
|
);
|
||||||
}, [userInputRequest.responsetype, userInputRequest.publictext, responseText, handleKeyDown, setResponseText]);
|
}, [userInputRequest.responsetype, userInputRequest.publictext, responseText, handleKeyDown, setResponseText]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
let timeout: ReturnType<typeof setTimeout>;
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
if (countdown == 0) {
|
if (countdown == 0) {
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
|
@ -180,8 +180,6 @@ Other useful metadata values to override block titles, icons, colors, themes, et
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const helpTextAtom = atom(helpText);
|
|
||||||
|
|
||||||
class HelpViewModel implements ViewModel {
|
class HelpViewModel implements ViewModel {
|
||||||
viewType: string;
|
viewType: string;
|
||||||
showTocAtom: PrimitiveAtom<boolean>;
|
showTocAtom: PrimitiveAtom<boolean>;
|
||||||
@ -210,7 +208,7 @@ function makeHelpViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HelpView({ model }: { model: HelpViewModel }) {
|
function HelpView({ model }: { model: HelpViewModel }) {
|
||||||
return <Markdown textAtom={helpTextAtom} showTocAtom={model.showTocAtom} className="help-view" />;
|
return <Markdown text={helpText} showTocAtom={model.showTocAtom} className="help-view" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { HelpView, HelpViewModel, makeHelpViewModel };
|
export { HelpView, HelpViewModel, makeHelpViewModel };
|
||||||
|
@ -11,7 +11,7 @@ import { isBlank } from "@/util/util";
|
|||||||
import { atom, Atom, PrimitiveAtom, useAtomValue, useSetAtom, WritableAtom } from "jotai";
|
import { atom, Atom, PrimitiveAtom, useAtomValue, useSetAtom, WritableAtom } from "jotai";
|
||||||
import type { OverlayScrollbars } from "overlayscrollbars";
|
import type { OverlayScrollbars } from "overlayscrollbars";
|
||||||
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
|
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
|
||||||
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||||
import tinycolor from "tinycolor2";
|
import tinycolor from "tinycolor2";
|
||||||
import "./waveai.less";
|
import "./waveai.less";
|
||||||
|
|
||||||
@ -217,11 +217,8 @@ function makeWaveAiViewModel(blockId): WaveAiModel {
|
|||||||
return waveAiModel;
|
return waveAiModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const showTocAtomDummy = atom(false);
|
|
||||||
|
|
||||||
const ChatItem = ({ chatItem, itemCount }: ChatItemProps) => {
|
const ChatItem = ({ chatItem, itemCount }: ChatItemProps) => {
|
||||||
const { isAssistant, text, isError } = chatItem;
|
const { isAssistant, text, isError } = chatItem;
|
||||||
const textAtom = useMemo(() => atom(text), [text]);
|
|
||||||
const senderClassName = isAssistant ? "chat-msg-assistant" : "chat-msg-user";
|
const senderClassName = isAssistant ? "chat-msg-assistant" : "chat-msg-user";
|
||||||
const msgClassName = `chat-msg ${senderClassName}`;
|
const msgClassName = `chat-msg ${senderClassName}`;
|
||||||
const cssVar = "--panel-bg-color";
|
const cssVar = "--panel-bg-color";
|
||||||
@ -242,7 +239,7 @@ const ChatItem = ({ chatItem, itemCount }: ChatItemProps) => {
|
|||||||
<div className="chat-msg-header">
|
<div className="chat-msg-header">
|
||||||
<i className="fa-sharp fa-solid fa-sparkles"></i>
|
<i className="fa-sharp fa-solid fa-sparkles"></i>
|
||||||
</div>
|
</div>
|
||||||
<Markdown textAtom={textAtom} showTocAtom={showTocAtomDummy} />
|
<Markdown text={text} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@ -258,7 +255,7 @@ const ChatItem = ({ chatItem, itemCount }: ChatItemProps) => {
|
|||||||
<div className="chat-msg-header">
|
<div className="chat-msg-header">
|
||||||
<i className="fa-sharp fa-solid fa-user"></i>
|
<i className="fa-sharp fa-solid fa-user"></i>
|
||||||
</div>
|
</div>
|
||||||
<Markdown className="msg-text" textAtom={textAtom} showTocAtom={showTocAtomDummy} />
|
<Markdown className="msg-text" text={text} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -163,7 +163,7 @@ function jotaiLoadableValue<T>(value: Loadable<T>, def: T): T {
|
|||||||
|
|
||||||
const NullAtom = atom(null);
|
const NullAtom = atom(null);
|
||||||
|
|
||||||
function useAtomValueSafe<T>(atom: Atom<T>): T {
|
function useAtomValueSafe<T>(atom: Atom<T> | Atom<Promise<T>>): T {
|
||||||
if (atom == null) {
|
if (atom == null) {
|
||||||
return useAtomValue(NullAtom) as T;
|
return useAtomValue(NullAtom) as T;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user