mirror of
https://github.com/RSSNext/Folo.git
synced 2026-10-29 12:12:59 +08:00
fix(ai): add shortcut to open this modal
- Integrated new hooks for creating and editing AI shortcuts, improving the user experience for managing shortcuts. - Adjusted layout styles in various components for better visual consistency, including padding and margin updates. - Removed deprecated modal handling for shortcuts, streamlining the codebase. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
+7
-1
@@ -1,10 +1,12 @@
|
||||
import { AIShortcutButton } from "@follow/components/ui/ai-shortcut-button/index.js"
|
||||
import { DEFAULT_SHORTCUT_TARGETS } from "@follow/shared/settings/interface"
|
||||
import { nextFrame } from "@follow/utils"
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { useAISettingValue } from "~/atoms/settings/ai"
|
||||
import { useSettingModal } from "~/modules/settings/modal/use-setting-modal-hack"
|
||||
import { useCreateAIShortcutModal } from "~/modules/settings/tabs/ai/shortcuts/hooks"
|
||||
|
||||
import { useMainEntryId } from "../../hooks/useMainEntryId"
|
||||
|
||||
@@ -40,9 +42,13 @@ export const ChatShortcutsRow: React.FC<ChatShortcutsRowProps> = ({ onSelect })
|
||||
return (mainEntryId ? entry : list) ?? []
|
||||
}, [aiSettings.shortcuts, mainEntryId])
|
||||
|
||||
const handleAddShortcut = useCreateAIShortcutModal()
|
||||
const handleCustomize = useCallback(() => {
|
||||
showSettings("ai")
|
||||
}, [showSettings])
|
||||
nextFrame(() => {
|
||||
handleAddShortcut()
|
||||
})
|
||||
}, [handleAddShortcut, showSettings])
|
||||
|
||||
return (
|
||||
<div className="mb-3 px-1">
|
||||
|
||||
@@ -220,7 +220,7 @@ export const TaskItem = memo(({ task }: { task: AITask }) => {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="hover:bg-material-medium border-border group rounded-lg border p-4 transition-colors">
|
||||
<div className="hover:bg-material-medium border-border group -ml-3 rounded-lg border p-3 transition-colors">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Divider } from "@follow/components/ui/divider/Divider.js"
|
||||
import { Label } from "@follow/components/ui/label/index.js"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
@@ -57,7 +56,7 @@ export const SettingAI = () => {
|
||||
value: t("integration.title"),
|
||||
},
|
||||
MCPServicesSection,
|
||||
<Divider key="task-scheduling-divider" />,
|
||||
|
||||
{
|
||||
type: "title",
|
||||
value: t("tasks.section.title"),
|
||||
|
||||
@@ -63,7 +63,7 @@ export const MCPServiceItem = ({
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="hover:bg-material-medium border-border group rounded-lg border p-4 transition-colors">
|
||||
<div className="hover:bg-material-medium border-border group -ml-3 rounded-lg border p-3 transition-colors">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
+22
-19
@@ -362,7 +362,7 @@ export const MCPServicesSection = () => {
|
||||
</div>
|
||||
|
||||
{mcpEnabled && (
|
||||
<div className="space-y-4">
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-text text-sm font-medium">
|
||||
{t("integration.mcp.services.title")}
|
||||
@@ -402,24 +402,27 @@ export const MCPServicesSection = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mcpServices.map((service) => (
|
||||
<MCPServiceItem
|
||||
key={service.id}
|
||||
service={service}
|
||||
onDelete={handleDeleteService}
|
||||
onRefresh={handleRefreshTools}
|
||||
onEdit={handleEditService}
|
||||
onToggleEnabled={handleToggleEnabled}
|
||||
isDeleting={
|
||||
deleteConnectionMutation.isPending &&
|
||||
deleteConnectionMutation.variables === service.id
|
||||
}
|
||||
isRefreshing={
|
||||
refreshToolsMutation.isPending && refreshToolsMutation.variables?.[0] === service.id
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="!mt-2 space-y-4">
|
||||
{mcpServices.map((service) => (
|
||||
<MCPServiceItem
|
||||
key={service.id}
|
||||
service={service}
|
||||
onDelete={handleDeleteService}
|
||||
onRefresh={handleRefreshTools}
|
||||
onEdit={handleEditService}
|
||||
onToggleEnabled={handleToggleEnabled}
|
||||
isDeleting={
|
||||
deleteConnectionMutation.isPending &&
|
||||
deleteConnectionMutation.variables === service.id
|
||||
}
|
||||
isRefreshing={
|
||||
refreshToolsMutation.isPending &&
|
||||
refreshToolsMutation.variables?.[0] === service.id
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
+4
-47
@@ -4,21 +4,18 @@ import {
|
||||
DEFAULT_SUMMARIZE_TIMELINE_SHORTCUT_ID,
|
||||
defaultAISettings,
|
||||
} from "@follow/shared/settings/defaults"
|
||||
import type { AIShortcut } from "@follow/shared/settings/interface"
|
||||
import { useEffect } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { setAISetting, useAISettingValue } from "~/atoms/settings/ai"
|
||||
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
|
||||
|
||||
import { useCreateAIShortcutModal, useEditAIShortcutModal } from "./hooks"
|
||||
import { ShortcutItem } from "./ShortcutItem"
|
||||
import { ShortcutModalContent } from "./ShortcutModalContent"
|
||||
|
||||
export const AIShortcutsSection = () => {
|
||||
const { t } = useTranslation("ai")
|
||||
const { shortcuts } = useAISettingValue()
|
||||
const { present } = useModalStack()
|
||||
|
||||
useEffect(() => {
|
||||
if (!shortcuts.some((shortcut) => shortcut.id === DEFAULT_SUMMARIZE_TIMELINE_SHORTCUT_ID)) {
|
||||
@@ -34,50 +31,10 @@ export const AIShortcutsSection = () => {
|
||||
|
||||
setAISetting("shortcuts", [...shortcuts, { ...defaultSummarizeShortcut }])
|
||||
}
|
||||
}, [shortcuts, setAISetting])
|
||||
}, [shortcuts])
|
||||
|
||||
const handleAddShortcut = () => {
|
||||
present({
|
||||
title: "Add AI Shortcut",
|
||||
content: ({ dismiss }: { dismiss: () => void }) => (
|
||||
<ShortcutModalContent
|
||||
shortcut={null}
|
||||
onSave={(shortcut) => {
|
||||
const newShortcut: AIShortcut = {
|
||||
...shortcut,
|
||||
id: Date.now().toString(),
|
||||
}
|
||||
setAISetting("shortcuts", [...shortcuts, newShortcut])
|
||||
toast.success(t("shortcuts.added"))
|
||||
dismiss()
|
||||
}}
|
||||
onCancel={dismiss}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
const handleEditShortcut = (shortcut: AIShortcut) => {
|
||||
present({
|
||||
title: "Edit AI Shortcut",
|
||||
content: ({ dismiss }: { dismiss: () => void }) => (
|
||||
<ShortcutModalContent
|
||||
shortcut={shortcut}
|
||||
onSave={(updatedShortcut) => {
|
||||
setAISetting(
|
||||
"shortcuts",
|
||||
shortcuts.map((s) =>
|
||||
s.id === shortcut.id ? { ...updatedShortcut, id: shortcut.id } : s,
|
||||
),
|
||||
)
|
||||
toast.success(t("shortcuts.updated"))
|
||||
dismiss()
|
||||
}}
|
||||
onCancel={dismiss}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}
|
||||
const handleAddShortcut = useCreateAIShortcutModal()
|
||||
const handleEditShortcut = useEditAIShortcutModal()
|
||||
|
||||
const handleDeleteShortcut = (id: string) => {
|
||||
setAISetting(
|
||||
|
||||
@@ -38,7 +38,7 @@ export const ShortcutItem = ({ shortcut, onDelete, onToggle, onEdit }: ShortcutI
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="hover:bg-material-medium border-border group rounded-lg border p-4 transition-colors">
|
||||
<div className="hover:bg-material-medium border-border group -ml-3 rounded-lg border p-3 transition-colors">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { AIShortcut } from "@follow/shared/settings/interface"
|
||||
import { useCallback } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { getAISettings, setAISetting } from "~/atoms/settings/ai"
|
||||
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
|
||||
|
||||
import { ShortcutModalContent } from "./ShortcutModalContent"
|
||||
|
||||
export const useCreateAIShortcutModal = () => {
|
||||
const { present } = useModalStack()
|
||||
const { t } = useTranslation("ai")
|
||||
return useCallback(() => {
|
||||
present({
|
||||
title: "Add AI Shortcut",
|
||||
content: ({ dismiss }: { dismiss: () => void }) => (
|
||||
<ShortcutModalContent
|
||||
shortcut={null}
|
||||
onSave={(shortcut) => {
|
||||
const newShortcut: AIShortcut = {
|
||||
...shortcut,
|
||||
id: Date.now().toString(),
|
||||
}
|
||||
const { shortcuts } = getAISettings()
|
||||
setAISetting("shortcuts", [...shortcuts, newShortcut])
|
||||
toast.success(t("shortcuts.added"))
|
||||
dismiss()
|
||||
}}
|
||||
onCancel={dismiss}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}, [present, t])
|
||||
}
|
||||
|
||||
export const useEditAIShortcutModal = () => {
|
||||
const { present } = useModalStack()
|
||||
const { t } = useTranslation("ai")
|
||||
return useCallback(
|
||||
(shortcut: AIShortcut) => {
|
||||
present({
|
||||
title: "Edit AI Shortcut",
|
||||
content: ({ dismiss }: { dismiss: () => void }) => (
|
||||
<ShortcutModalContent
|
||||
shortcut={shortcut}
|
||||
onSave={(updatedShortcut) => {
|
||||
const { shortcuts } = getAISettings()
|
||||
setAISetting(
|
||||
"shortcuts",
|
||||
shortcuts.map((s) =>
|
||||
s.id === shortcut.id ? { ...updatedShortcut, id: shortcut.id } : s,
|
||||
),
|
||||
)
|
||||
toast.success(t("shortcuts.updated"))
|
||||
dismiss()
|
||||
}}
|
||||
onCancel={dismiss}
|
||||
/>
|
||||
),
|
||||
})
|
||||
},
|
||||
[present, t],
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user