diff --git a/client/packages/lowcoder-design/src/components/ExternalLink.tsx b/client/packages/lowcoder-design/src/components/ExternalLink.tsx index 51fcb3c8ed..f22da58a78 100644 --- a/client/packages/lowcoder-design/src/components/ExternalLink.tsx +++ b/client/packages/lowcoder-design/src/components/ExternalLink.tsx @@ -1,9 +1,11 @@ import { ActiveTextColor, GreyTextColor } from "constants/style"; import { DocIcon } from "icons"; import styled from "styled-components"; +import { ToolTipLabel } from "./toolTip"; export const ExternalLink = styled.a` font-size: 13px; + font-weight: 400; line-height: 13px; color: ${GreyTextColor}; display: inline-flex; @@ -20,14 +22,27 @@ const StyledDocIcon = styled(DocIcon)` margin-right: 4px; `; -export function DocLink(props: React.AnchorHTMLAttributes) { +type DocLinkProps = React.AnchorHTMLAttributes & { + tooltipZIndex?: number; +}; + +export function DocLink(props: DocLinkProps) { if (!props.href) { return <>; } - return ( - + const { title, children, rel, tooltipZIndex, ...rest } = props; + const link = ( + - {props.children} + {children} ); + if (!title) { + return link; + } + return ( + + {link} + + ); } diff --git a/client/packages/lowcoder/src/components/ai-helper/AIHelperModal.tsx b/client/packages/lowcoder/src/components/ai-helper/AIHelperModal.tsx index 64bbee42f9..b44374a65d 100644 --- a/client/packages/lowcoder/src/components/ai-helper/AIHelperModal.tsx +++ b/client/packages/lowcoder/src/components/ai-helper/AIHelperModal.tsx @@ -7,7 +7,9 @@ import { SparklesIcon, XIcon } from "lucide-react"; import { useSelector } from "react-redux"; import styled from "styled-components"; +import { DocLink } from "lowcoder-design"; import { EditorContext } from "comps/editorState"; +import { trans } from "i18n"; import { getDataSourceStructures } from "redux/selectors/datasourceSelectors"; import { getSelectedAIQueryName } from "util/localStorageUtil"; @@ -175,6 +177,13 @@ export function AIHelperModal() { AI Helper + + {trans("comp.menuViewDocs")} + {target?.label && ( {target.label} diff --git a/client/packages/lowcoder/src/comps/comps/chatBoxComponent/chatBoxComp.tsx b/client/packages/lowcoder/src/comps/comps/chatBoxComponent/chatBoxComp.tsx index 9c293f1e37..af256c502f 100644 --- a/client/packages/lowcoder/src/comps/comps/chatBoxComponent/chatBoxComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/chatBoxComponent/chatBoxComp.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { Section, sectionNames, controlItem } from "lowcoder-design"; +import { PropertyViewDocLink } from "comps/utils/propertyViewDocLink"; import { default as Segmented } from "antd/es/segmented"; import { UICompBuilder, withDefault, stateComp } from "../../generators"; import { changeValueAction, multiChangeAction } from "lowcoder-core"; @@ -193,6 +194,7 @@ const ChatBoxPropertyView = React.memo((props: { children: any }) => { return ( <> +
{children.chatTitle.propertyView({ label: trans("chatBox.chatTitleLabel"), diff --git a/client/packages/lowcoder/src/comps/comps/chatComp/chatPropertyView.tsx b/client/packages/lowcoder/src/comps/comps/chatComp/chatPropertyView.tsx index b12aafd41d..d6d44f1e67 100644 --- a/client/packages/lowcoder/src/comps/comps/chatComp/chatPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/comps/chatComp/chatPropertyView.tsx @@ -1,10 +1,9 @@ // client/packages/lowcoder/src/comps/comps/chatComp/chatPropertyView.tsx import React, { useMemo } from "react"; -import { Section, sectionNames, DocLink } from "lowcoder-design"; +import { Section, sectionNames, controlItem } from "lowcoder-design"; import { trans } from "i18n"; -import { hiddenPropertyView } from "comps/utils/propertyUtils"; -import { controlItem } from "lowcoder-design"; +import { PropertyViewDocLink } from "comps/utils/propertyViewDocLink"; // ============================================================================ // PROPERTY VIEW @@ -15,16 +14,7 @@ export const ChatPropertyView = React.memo((props: any) => { return useMemo(() => ( <> - {/* Help & Documentation - Outside of Section */} -
- - 📖 View Documentation - -
+ {/* Message Handler Configuration */}
diff --git a/client/packages/lowcoder/src/comps/hooks/chatControllerComp.tsx b/client/packages/lowcoder/src/comps/hooks/chatControllerComp.tsx index 07c2efb460..1b220cf40f 100644 --- a/client/packages/lowcoder/src/comps/hooks/chatControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/hooks/chatControllerComp.tsx @@ -1,5 +1,6 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react"; import { Section, sectionNames } from "lowcoder-design"; +import { PropertyViewDocLink } from "comps/utils/propertyViewDocLink"; import { simpleMultiComp, stateComp, @@ -486,6 +487,7 @@ const ChatControllerWithProps = withPropertyViewFn( ChatControllerBase, (comp) => ( <> +
{comp.children.applicationId.propertyView({ label: trans("chatController.applicationIdLabel"), diff --git a/client/packages/lowcoder/src/comps/utils/compDocUtil.ts b/client/packages/lowcoder/src/comps/utils/compDocUtil.ts index edb1bb42bc..27d1c1e892 100644 --- a/client/packages/lowcoder/src/comps/utils/compDocUtil.ts +++ b/client/packages/lowcoder/src/comps/utils/compDocUtil.ts @@ -8,6 +8,12 @@ export function getComponentDocUrl(compType: UICompType) { switch (compType) { case "module": return trans("docUrls.module"); + case "chat": + return trans("docUrls.githubAiChat"); + case "chatBox": + return trans("docUrls.githubChatBox"); + case "chatController": + return trans("docUrls.githubChatController"); default: return trans("docUrls.components", { compType }); } diff --git a/client/packages/lowcoder/src/comps/utils/propertyViewDocLink.tsx b/client/packages/lowcoder/src/comps/utils/propertyViewDocLink.tsx new file mode 100644 index 0000000000..2cdec5ce3b --- /dev/null +++ b/client/packages/lowcoder/src/comps/utils/propertyViewDocLink.tsx @@ -0,0 +1,12 @@ +import { DocLink } from "lowcoder-design"; +import { trans } from "i18n"; + +export function PropertyViewDocLink(props: { href: string }) { + return ( +
+ + {trans("comp.menuViewDocs")} + +
+ ); +} diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 76728b41e0..a26e439cb9 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1823,6 +1823,7 @@ export const en = { "comp": { "menuViewDocs": "View Documentation", + "menuViewDocsTooltip": "Open documentation on GitHub", "menuViewPlayground": "View interactive Playground", "menuUpgradeToLatest": "Upgrade to Latest Version", "nameNotEmpty": "Cannot Be Empty", @@ -5302,6 +5303,11 @@ export const en = { eventHandlerSlowdown: "https://docs.lowcoder.cloud/build-applications/app-interaction/event-handlers", thirdLib: "https://docs.lowcoder.cloud/lowcoder-extension/use-third-party-libraries-in-apps", thirdLibUrlText: "Use third-party libraries", + githubAiChat: "https://github.com/lowcoder-org/lowcoder/blob/main/docs/build-applications/app-editor/visual-components/ai-chat.md", + githubChatBox: "https://github.com/lowcoder-org/lowcoder/blob/main/docs/build-applications/app-editor/visual-components/chat-box.md", + githubAutomator: "https://github.com/lowcoder-org/lowcoder/blob/main/docs/build-applications/app-editor/automator.md", + githubAiHelp: "https://github.com/lowcoder-org/lowcoder/blob/main/docs/build-applications/app-editor/ai-help.md", + githubChatController: "https://github.com/lowcoder-org/lowcoder/blob/main/docs/build-applications/app-editor/visual-components/chat-controller.md", }, datasourceTutorial: { mysql: "", diff --git a/client/packages/lowcoder/src/pages/editor/bottom/BottomPanel.tsx b/client/packages/lowcoder/src/pages/editor/bottom/BottomPanel.tsx index 1d65c44925..aa6609377c 100644 --- a/client/packages/lowcoder/src/pages/editor/bottom/BottomPanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/bottom/BottomPanel.tsx @@ -1,26 +1,27 @@ import { BottomContent } from "pages/editor/bottom/BottomContent"; -import { ResizableBox, ResizeCallbackData } from "react-resizable"; -import styled from "styled-components"; -import * as React from "react"; -import { useContext, useEffect, useMemo, useState } from "react"; -import { - getSelectedAIQueryName, - saveSelectedAIQueryName, -} from "util/localStorageUtil"; -import { useEditorLayoutStore } from "pages/editor/editorLayoutStore"; +import { ResizableBox, ResizeCallbackData } from "react-resizable"; +import styled from "styled-components"; +import * as React from "react"; +import { useContext, useEffect, useMemo, useState } from "react"; +import { + getSelectedAIQueryName, + saveSelectedAIQueryName, +} from "util/localStorageUtil"; +import { useEditorLayoutStore } from "pages/editor/editorLayoutStore"; import { BottomResultPanel } from "../../../components/resultPanel/BottomResultPanel"; import { AppState } from "../../../redux/reducers"; import { getUser } from "../../../redux/selectors/usersSelectors"; -import { connect } from "react-redux"; -import { Layers } from "constants/Layers"; -import Flex from "antd/es/flex"; -import type { MenuProps } from 'antd/es/menu'; -import { DatabaseOutlined } from "@ant-design/icons"; -import Menu from "antd/es/menu/menu"; -import Select from "antd/es/select"; -import { AIGenerate } from "lowcoder-design"; -import { ChatPanel } from "@lowcoder-ee/comps/comps/chatComp/components/ChatPanel"; -import { EditorContext } from "comps/editorState"; +import { connect } from "react-redux"; +import { Layers } from "constants/Layers"; +import Flex from "antd/es/flex"; +import type { MenuProps } from 'antd/es/menu'; +import { DatabaseOutlined } from "@ant-design/icons"; +import Menu from "antd/es/menu/menu"; +import Select from "antd/es/select"; +import { AIGenerate, DocLink } from "lowcoder-design"; +import { ChatPanel } from "@lowcoder-ee/comps/comps/chatComp/components/ChatPanel"; +import { EditorContext } from "comps/editorState"; +import { trans } from "i18n"; type MenuItem = Required['items'][number]; @@ -40,12 +41,12 @@ const StyledResizableBox = styled(ResizableBox)` } `; -const StyledMenu = styled(Menu)` - flex: 0 0 40px; - width: 40px; - padding: 6px 0; - - .ant-menu-item { +const StyledMenu = styled(Menu)` + flex: 0 0 40px; + width: 40px; + padding: 6px 0; + + .ant-menu-item { height: 30px; line-height: 30px; } @@ -62,6 +63,9 @@ const ChatHeader = styled.div` `; const ChatTitle = styled.h3` margin: 0; + display: flex; + align-items: center; + gap: 12px; font-size: 14px; font-weight: 500; color: #222222; @@ -73,25 +77,25 @@ const QuerySelectorWrapper = styled.div` gap: 12px; `; -const QueryLabel = styled.span` - font-size: 12px; - color: #8b8fa3; - white-space: nowrap; -`; - -const PanelBody = styled.div` - display: flex; - height: 100%; - min-width: 0; -`; - -const PanelContent = styled.div` - flex: 1 1 0; - min-width: 0; - height: 100%; -`; - -const preventDefault = (e: any) => { +const QueryLabel = styled.span` + font-size: 12px; + color: #8b8fa3; + white-space: nowrap; +`; + +const PanelBody = styled.div` + display: flex; + height: 100%; + min-width: 0; +`; + +const PanelContent = styled.div` + flex: 1 1 0; + min-width: 0; + height: 100%; +`; + +const preventDefault = (e: any) => { e.preventDefault(); }; @@ -112,17 +116,17 @@ function Bottom(props: any) { setBottomHeight(data.size.height); removeListener(); }; - - const [currentOption, setCurrentOption] = useState("data"); - const [selectedQuery, setSelectedQuery] = useState(() => getSelectedAIQueryName()); - - const editorState = useContext(EditorContext); - - useEffect(() => { - if (currentOption === "ai") { - setSelectedQuery(getSelectedAIQueryName()); - } - }, [currentOption]); + + const [currentOption, setCurrentOption] = useState("data"); + const [selectedQuery, setSelectedQuery] = useState(() => getSelectedAIQueryName()); + + const editorState = useContext(EditorContext); + + useEffect(() => { + if (currentOption === "ai") { + setSelectedQuery(getSelectedAIQueryName()); + } + }, [currentOption]); const queryOptions = useMemo(() => { if (!editorState) return []; @@ -149,50 +153,58 @@ function Bottom(props: any) { onResizeStart={addListener} onResizeStop={resizeStop} > - - + { - setCurrentOption(key); - }} - /> - - {currentOption === "data" ? ( - - ) : ( - - - Lowcoder Automator - - Query: - { + const nextQuery = value || ""; + setSelectedQuery(nextQuery); + saveSelectedAIQueryName(nextQuery); + }} + options={queryOptions} + style={{ width: 200 }} + size="small" + /> + + + + + )} + + + ); }