mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-29 12:09:31 +08:00
Fix: Unable to navigate from the agent list page to the compilation editing page. (#17460)
This commit is contained in:
@@ -4,24 +4,24 @@
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"plugins": ["@typescript-eslint", "react", "react-hooks"],
|
||||
"plugins": ["typescript", "react"],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "18.2.0"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-use-before-define": [
|
||||
"typescript/no-use-before-define": [
|
||||
"warn",
|
||||
{
|
||||
"functions": false,
|
||||
"variables": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"typescript/no-explicit-any": "off",
|
||||
"typescript/ban-ts-comment": "off",
|
||||
"typescript/no-empty-function": "off",
|
||||
"typescript/no-non-null-assertion": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/no-unescaped-entities": "warn",
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }]
|
||||
|
||||
@@ -18,7 +18,8 @@ RAGFlow frontend is a React/TypeScript application built with UmiJS:
|
||||
npm install
|
||||
npm run dev # Development server
|
||||
npm run build # Production build
|
||||
npm run lint # ESLint
|
||||
npm run lint # oxlint
|
||||
npm run format # oxfmt
|
||||
npm run test # Jest tests
|
||||
```
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { FormLayout } from '@/constants/form';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useFetchAgentList } from '@/hooks/use-agent-request';
|
||||
import { AgentListItem, AgentListItemType } from '@/interfaces/database/agent';
|
||||
import { buildSelectOptions } from '@/utils/component-util';
|
||||
import { ArrowUpRight } from 'lucide-react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
@@ -48,19 +49,25 @@ export function DataFlowSelect(props: IProps) {
|
||||
const { data: dataPipelineOptions } = useFetchAgentList({
|
||||
canvas_category: AgentCategory.DataflowCanvas,
|
||||
});
|
||||
|
||||
const canvasList = useMemo(
|
||||
() =>
|
||||
(dataPipelineOptions?.canvas ?? []).filter(
|
||||
(item): item is AgentListItem & { title: string; avatar?: string } =>
|
||||
item.type !== AgentListItemType.CompilationTemplateGroup,
|
||||
),
|
||||
[dataPipelineOptions?.canvas],
|
||||
);
|
||||
|
||||
const options = useMemo(() => {
|
||||
const option = buildSelectOptions(
|
||||
dataPipelineOptions?.canvas,
|
||||
'id',
|
||||
'title',
|
||||
);
|
||||
const option = buildSelectOptions(canvasList, 'id', 'title');
|
||||
|
||||
return option || [];
|
||||
}, [dataPipelineOptions]);
|
||||
}, [canvasList]);
|
||||
|
||||
const nodes = useMemo(() => {
|
||||
return (
|
||||
dataPipelineOptions?.canvas?.map((item) => {
|
||||
canvasList.map((item) => {
|
||||
return {
|
||||
id: item?.id,
|
||||
name: item?.title,
|
||||
@@ -68,7 +75,7 @@ export function DataFlowSelect(props: IProps) {
|
||||
};
|
||||
}) || []
|
||||
);
|
||||
}, [dataPipelineOptions]);
|
||||
}, [canvasList]);
|
||||
|
||||
useEffect(() => {
|
||||
setDataList?.(nodes);
|
||||
|
||||
@@ -132,7 +132,7 @@ export const useFetchExcel = (filePath: string) => {
|
||||
setStatus(true);
|
||||
})
|
||||
.catch((e) => {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.warn('failed', e);
|
||||
myExcelPreviewer.destroy();
|
||||
setStatus(false);
|
||||
|
||||
@@ -144,7 +144,7 @@ function UploadForm({
|
||||
setColumnRoles(roles);
|
||||
form.setValue('tableColumnRoles', roles);
|
||||
}
|
||||
}, [extractedColumns, columnMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [extractedColumns, columnMode]); // oxlint-disable-line react/exhaustive-deps
|
||||
|
||||
const showColumnConfig = isTableParser && extractedColumns.length > 0;
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ export function FileUploader(props: FileUploaderProps) {
|
||||
}
|
||||
});
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;
|
||||
|
||||
@@ -307,7 +307,7 @@ const FloatingChatWidgetMarkdown = ({
|
||||
'custom-typography': ({ children }: { children: string }) =>
|
||||
renderReference(children),
|
||||
code(props: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line typescript/no-unused-vars
|
||||
const { children, className, node, ...rest } = props;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
return match ? (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* oxlint-disable react/exhaustive-deps */
|
||||
|
||||
'use client';
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ export const useSendMessageWithSse = () => {
|
||||
.pipeThrough(new EventSourceParserStream())
|
||||
.getReader();
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
// oxlint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
try {
|
||||
const x = await reader?.read();
|
||||
|
||||
@@ -4,6 +4,7 @@ import message from '@/components/ui/message';
|
||||
import { AgentCategory, AgentGlobals } from '@/constants/agent';
|
||||
import { useFetchTenantInfo } from '@/hooks/use-user-setting-request';
|
||||
import {
|
||||
AgentListItem,
|
||||
IAgentLogResponse,
|
||||
IAgentLogsRequest,
|
||||
IAgentLogsResponse,
|
||||
@@ -154,7 +155,7 @@ export const useFetchAgentListByPage = () => {
|
||||
});
|
||||
|
||||
const { data, isFetching: loading } = useQuery<{
|
||||
canvas: IFlow[];
|
||||
canvas: AgentListItem[];
|
||||
total: number;
|
||||
}>({
|
||||
queryKey: [
|
||||
@@ -205,7 +206,7 @@ export const useFetchAgentListByPage = () => {
|
||||
};
|
||||
|
||||
export function useFetchAllAgentList() {
|
||||
const { data, isFetching: loading } = useQuery<IFlow[]>({
|
||||
const { data, isFetching: loading } = useQuery<AgentListItem[]>({
|
||||
queryKey: [AgentApiAction.FetchAllAgentList],
|
||||
queryFn: async () => {
|
||||
const { data } = await agentService.listAgents(
|
||||
@@ -853,7 +854,7 @@ export const useFetchAgentList = ({
|
||||
canvas_category,
|
||||
}: IPipeLineListRequest) => {
|
||||
const { data, isFetching: loading } = useQuery<{
|
||||
canvas: IFlow[];
|
||||
canvas: AgentListItem[];
|
||||
total: number;
|
||||
}>({
|
||||
queryKey: [AgentApiAction.FetchAgentList],
|
||||
|
||||
@@ -193,7 +193,7 @@ export const useSendMessageBySSE = (url: string) => {
|
||||
let lastEventData: ResponseType | undefined;
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
// oxlint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const x = await reader?.read();
|
||||
if (!x) {
|
||||
|
||||
@@ -67,7 +67,7 @@ function InitialContentPlugin({
|
||||
root.append($createParagraphNode());
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [editor]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -32,13 +32,13 @@ export class HorizontalRuleNode extends ElementNode {
|
||||
return new HorizontalRuleNode(node.__key);
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* oxlint-disable typescript/no-unused-vars */
|
||||
static importJSON(
|
||||
_serializedNode: SerializedHorizontalRuleNode,
|
||||
): HorizontalRuleNode {
|
||||
return $createHorizontalRuleNode();
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-enable typescript/no-unused-vars */
|
||||
|
||||
exportJSON(): SerializedHorizontalRuleNode {
|
||||
return {
|
||||
@@ -51,7 +51,7 @@ export class HorizontalRuleNode extends ElementNode {
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line typescript/no-unused-vars
|
||||
createDOM(_config: EditorConfig, _editor: any): HTMLElement {
|
||||
const element = document.createElement('hr');
|
||||
return element;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* - LINK, HR
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-object-type, no-useless-escape */
|
||||
/* oxlint-disable typescript/no-unused-vars, typescript/no-empty-object-type, no-useless-escape */
|
||||
|
||||
import { $createCodeNode, $isCodeNode, CodeNode } from '@lexical/code';
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Ported from Nimbalyst — supports click-to-edit source code.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* oxlint-disable typescript/no-unused-vars */
|
||||
|
||||
import { addClassNamesToElement } from '@lexical/utils';
|
||||
import type {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Ported from Nimbalyst. Creates MermaidNode instead of CodeNode.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
/* oxlint-disable no-console */
|
||||
|
||||
import type { MultilineElementTransformer } from '@lexical/markdown';
|
||||
import {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Table transformer for markdown import/export
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars, no-console, @typescript-eslint/no-use-before-define */
|
||||
/* oxlint-disable typescript/no-unused-vars, no-console, typescript/no-use-before-define */
|
||||
|
||||
import { ElementTransformer } from '@lexical/markdown';
|
||||
import {
|
||||
|
||||
@@ -43,7 +43,7 @@ export const ImportExcelForm = ({
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="file"
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line typescript/no-unused-vars
|
||||
render={({ field: { onChange, value, ...field } }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-sm font-medium">
|
||||
|
||||
@@ -15,7 +15,7 @@ export const OwnerTenantIdContext = createContext<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
// oxlint-disable-next-line react-refresh/only-export-components
|
||||
export const useOwnerTenantId = () => useContext(OwnerTenantIdContext);
|
||||
|
||||
type AgentInstanceContextType = Pick<
|
||||
|
||||
@@ -108,7 +108,7 @@ function useHandleSelectChange({ onChange, value }: ToolCommandProps) {
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
// oxlint-disable-next-line
|
||||
export function ToolCommand({ value, onChange }: ToolCommandProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -672,7 +672,7 @@ const useGraphStore = create<RFState>()(
|
||||
id: string,
|
||||
nodeOrNodeId?: RAGFlowNodeType | string,
|
||||
) => {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
// oxlint-disable-next-line eqeqeq
|
||||
const tools =
|
||||
nodeOrNodeId != null
|
||||
? getAgentNodeTools(
|
||||
|
||||
@@ -334,7 +334,7 @@ describe('dsl-bridge round-trip stability', () => {
|
||||
// state.
|
||||
const diff = diffDsl(v2BrowserLike.graph, exported.graph, 'graph');
|
||||
if (diff.warnings.length > 0) {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[v2 round-trip] React-Flow-internal mismatches (warnings, not failures):',
|
||||
diff.warnings,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { AgentCategory } from '@/constants/agent';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { AgentListItemType, IFlow } from '@/interfaces/database/agent';
|
||||
import { LucideIcon, Network, Route, Shapes } from 'lucide-react';
|
||||
import { CanvasCategoryToFlowType, FlowType, FlowTypeConfig } from './constant';
|
||||
import { AgentDropdown } from './agent-dropdown';
|
||||
import { useRenameAgent } from './use-rename-agent';
|
||||
|
||||
@@ -14,25 +14,24 @@ export type DatasetCardProps = {
|
||||
data: IFlow & { type?: AgentListItemType };
|
||||
} & Pick<ReturnType<typeof useRenameAgent>, 'showAgentRenameModal'>;
|
||||
|
||||
const CanvasCategoryIconMap: Record<string, LucideIcon> = {
|
||||
[AgentCategory.AgentCanvas]: Network,
|
||||
[AgentCategory.DataflowCanvas]: Route,
|
||||
};
|
||||
|
||||
function AgentTypeIcon({
|
||||
data,
|
||||
}: {
|
||||
data: IFlow & { type?: AgentListItemType };
|
||||
}) {
|
||||
const Icon =
|
||||
const flowType =
|
||||
data.type === AgentListItemType.CompilationTemplateGroup
|
||||
? Shapes
|
||||
: CanvasCategoryIconMap[data.canvas_category];
|
||||
? FlowType.Compiler
|
||||
: CanvasCategoryToFlowType[data.canvas_category ?? ''];
|
||||
|
||||
if (!Icon) {
|
||||
const icon = flowType ? FlowTypeConfig[flowType].icon : null;
|
||||
|
||||
if (!icon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const Icon = icon;
|
||||
|
||||
return (
|
||||
<Button variant={'ghost'} size={'sm'}>
|
||||
<Icon />
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { CompilationTemplateScope } from '@/constants/compilation';
|
||||
import { ICompilationTemplateGroup } from '@/interfaces/database/compilation-template';
|
||||
import { Database, FileText, LucideIcon } from 'lucide-react';
|
||||
import { formatDate } from '@/utils/date';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { formatKindLabel } from '@/utils/compilation-template-util';
|
||||
import { CompilationTemplateDropdown } from './compilation-template-dropdown';
|
||||
import { FlowType, FlowTypeConfig } from './constant';
|
||||
|
||||
type CompilationTemplateCardProps = {
|
||||
data: ICompilationTemplateGroup;
|
||||
@@ -17,16 +18,7 @@ type CompilationTemplateCardProps = {
|
||||
onDelete: (id: string) => void;
|
||||
};
|
||||
|
||||
const ScopeIconMap: Record<string, LucideIcon> = {
|
||||
[CompilationTemplateScope.File]: FileText,
|
||||
[CompilationTemplateScope.Dataset]: Database,
|
||||
};
|
||||
|
||||
function ScopeIcon({ scope }: { scope?: string }) {
|
||||
const Icon = scope ? ScopeIconMap[scope] : null;
|
||||
|
||||
return Icon ? <Icon className="size-4 text-text-secondary shrink-0" /> : null;
|
||||
}
|
||||
const CompilerIcon = FlowTypeConfig[FlowType.Compiler].icon;
|
||||
|
||||
export function CompilationTemplateCard({
|
||||
data,
|
||||
@@ -50,12 +42,13 @@ export function CompilationTemplateCard({
|
||||
|
||||
<div className="flex-1 min-w-0 flex flex-col gap-1">
|
||||
<section className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||
<h3 className="text-base font-normal truncate text-text-primary">
|
||||
{data.name}
|
||||
</h3>
|
||||
<ScopeIcon scope={data.scope} />
|
||||
</div>
|
||||
<h3 className="flex-1 min-w-0 text-base font-normal truncate text-text-primary">
|
||||
{data.name}
|
||||
</h3>
|
||||
|
||||
<Button variant="ghost" size="sm">
|
||||
<CompilerIcon />
|
||||
</Button>
|
||||
|
||||
<CompilationTemplateDropdown data={data} onDelete={onDelete}>
|
||||
<MoreButton />
|
||||
@@ -73,6 +66,11 @@ export function CompilationTemplateCard({
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 mt-1 min-w-0 text-sm text-text-secondary">
|
||||
<span className="whitespace-nowrap">{t('flow.lastSavedAt')}:</span>
|
||||
<p className="truncate">{formatDate(data.update_time)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
import { AgentCategory } from '@/constants/agent';
|
||||
import { LucideIcon, Network, Route, Shapes } from 'lucide-react';
|
||||
|
||||
export enum FlowType {
|
||||
Agent = 'agent',
|
||||
Compiler = 'compiler',
|
||||
Flow = 'flow',
|
||||
}
|
||||
|
||||
export const FlowTypeConfig: Record<
|
||||
FlowType,
|
||||
{ icon: LucideIcon; labelKey: string }
|
||||
> = {
|
||||
[FlowType.Agent]: { icon: Network, labelKey: 'tabList.workflow' },
|
||||
[FlowType.Compiler]: {
|
||||
icon: Shapes,
|
||||
labelKey: 'tabList.compilationOperator',
|
||||
},
|
||||
[FlowType.Flow]: { icon: Route, labelKey: 'tabList.ingestionPipeline' },
|
||||
};
|
||||
|
||||
/**
|
||||
* Map canvas_category → FlowType for resolving icons in agent cards.
|
||||
*/
|
||||
export const CanvasCategoryToFlowType: Record<string, FlowType> = {
|
||||
[AgentCategory.AgentCanvas]: FlowType.Agent,
|
||||
[AgentCategory.DataflowCanvas]: FlowType.Flow,
|
||||
};
|
||||
|
||||
@@ -13,11 +13,11 @@ import { TagRenameId } from '@/constants/knowledge';
|
||||
import { IModalProps } from '@/interfaces/common';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Routes } from '@/routes';
|
||||
import { BrainCircuit, Check, Route, Shapes } from 'lucide-react';
|
||||
import { Check } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { FlowType } from './constant';
|
||||
import { FlowType, FlowTypeConfig } from './constant';
|
||||
import { NameFormField, NameFormSchema } from './name-form-field';
|
||||
|
||||
export type CreateAgentFormProps = IModalProps<any> & {
|
||||
@@ -30,18 +30,6 @@ type FlowTypeCardProps = {
|
||||
onChange?: (value: FlowType) => void;
|
||||
};
|
||||
|
||||
const FLOW_TYPE_CONFIG: Record<
|
||||
FlowType,
|
||||
{ icon: typeof BrainCircuit; labelKey: string }
|
||||
> = {
|
||||
[FlowType.Flow]: { icon: Route, labelKey: 'tabList.ingestionPipeline' },
|
||||
[FlowType.Compiler]: {
|
||||
icon: Shapes,
|
||||
labelKey: 'tabList.compilationOperator',
|
||||
},
|
||||
[FlowType.Agent]: { icon: BrainCircuit, labelKey: 'tabList.workflow' },
|
||||
};
|
||||
|
||||
function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
||||
const { t } = useTranslation();
|
||||
const handleChange = useCallback(
|
||||
@@ -55,7 +43,7 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
||||
<section className="flex gap-10">
|
||||
{[FlowType.Flow, FlowType.Compiler, FlowType.Agent].map((val) => {
|
||||
const isActive = value === val;
|
||||
const config = FLOW_TYPE_CONFIG[val];
|
||||
const config = FlowTypeConfig[val];
|
||||
const Icon = config.icon;
|
||||
return (
|
||||
<Card
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useDeleteCompilationTemplateGroup } from '@/hooks/use-compilation-templ
|
||||
import { Routes } from '@/routes';
|
||||
import { pick } from 'lodash';
|
||||
import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useSearchParams } from 'react-router';
|
||||
import { AgentCard } from './agent-card';
|
||||
@@ -45,15 +45,6 @@ export default function Agents() {
|
||||
handleFilterSubmit,
|
||||
} = useFetchAgentListByPage();
|
||||
|
||||
const canvasCategory = useMemo(
|
||||
() =>
|
||||
Array.isArray(filterValue.canvasCategory)
|
||||
? (filterValue.canvasCategory[0] as string | undefined)
|
||||
: undefined,
|
||||
[filterValue.canvasCategory],
|
||||
);
|
||||
const isCompilation = canvasCategory === CompilationGroupCategory;
|
||||
|
||||
const { navigateToAgentTemplates } = useNavigatePage();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -92,10 +83,6 @@ export default function Agents() {
|
||||
[setPagination],
|
||||
);
|
||||
|
||||
const handleAddCompilation = useCallback(() => {
|
||||
navigate(`${Routes.CompilationTemplatesEditNext}?source=agents`);
|
||||
}, [navigate]);
|
||||
|
||||
const handleEditCompilation = useCallback(
|
||||
(id: string) => () => {
|
||||
navigate(`${Routes.CompilationTemplatesEditNext}/${id}?source=agents`);
|
||||
@@ -137,68 +124,59 @@ export default function Agents() {
|
||||
onChange={handleFilterSubmit}
|
||||
value={filterValue}
|
||||
>
|
||||
{isCompilation ? (
|
||||
<Button
|
||||
onClick={handleAddCompilation}
|
||||
data-testid="create-compilation-template"
|
||||
>
|
||||
<Plus className="size-[1em]" />
|
||||
</Button>
|
||||
) : (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger data-testid="create-agent" asChild>
|
||||
<Button>
|
||||
<Plus className="size-[1em]" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent data-testid="agent-create-menu">
|
||||
<DropdownMenuItem
|
||||
justifyBetween={false}
|
||||
onClick={showCreatingModal}
|
||||
>
|
||||
<Clipboard />
|
||||
{t('flow.createFromBlank')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
justifyBetween={false}
|
||||
onClick={() => navigateToAgentTemplates()}
|
||||
>
|
||||
<ClipboardPlus />
|
||||
{t('flow.createFromTemplate')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
data-testid="agent-import-json"
|
||||
justifyBetween={false}
|
||||
onClick={handleImportJson}
|
||||
>
|
||||
<FileInput />
|
||||
{t('flow.importJsonFile')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger data-testid="create-agent" asChild>
|
||||
<Button>
|
||||
<Plus className="size-[1em]" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent data-testid="agent-create-menu">
|
||||
<DropdownMenuItem
|
||||
justifyBetween={false}
|
||||
onClick={showCreatingModal}
|
||||
>
|
||||
<Clipboard />
|
||||
{t('flow.createFromBlank')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
justifyBetween={false}
|
||||
onClick={() => navigateToAgentTemplates()}
|
||||
>
|
||||
<ClipboardPlus />
|
||||
{t('flow.createFromTemplate')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
data-testid="agent-import-json"
|
||||
justifyBetween={false}
|
||||
onClick={handleImportJson}
|
||||
>
|
||||
<FileInput />
|
||||
{t('flow.importJsonFile')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ListFilterBar>
|
||||
</header>
|
||||
|
||||
{data.length ? (
|
||||
<>
|
||||
<CardContainer className="flex-1 overflow-auto px-5">
|
||||
{isCompilation
|
||||
? (data as any[]).map((item) => (
|
||||
<CompilationTemplateCard
|
||||
key={item.id}
|
||||
data={item}
|
||||
onClick={handleEditCompilation(item.id)}
|
||||
onDelete={handleDeleteCompilation}
|
||||
/>
|
||||
))
|
||||
: data.map((x) => (
|
||||
<AgentCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
showAgentRenameModal={showAgentRenameModal}
|
||||
/>
|
||||
))}
|
||||
{data.map((x) =>
|
||||
x.type === CompilationGroupCategory ? (
|
||||
<CompilationTemplateCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
onClick={handleEditCompilation(x.id)}
|
||||
onDelete={handleDeleteCompilation}
|
||||
/>
|
||||
) : (
|
||||
<AgentCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
showAgentRenameModal={showAgentRenameModal}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</CardContainer>
|
||||
|
||||
<footer className="mt-4 px-5 pb-5">
|
||||
|
||||
@@ -50,7 +50,7 @@ export function useWikiDetailContent({
|
||||
if (!currentEntry || !pageData) return;
|
||||
if (currentEntry.slug !== pageData.slug) return;
|
||||
updateCurrentTitle(pageData.title);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [currentEntry?.slug, pageData?.slug, pageData?.title, updateCurrentTitle]);
|
||||
|
||||
// When selectedArtifact changes from the left panel (not from our own
|
||||
@@ -66,7 +66,7 @@ export function useWikiDetailContent({
|
||||
title: selectedArtifact.title,
|
||||
pageType: selectedArtifact.page_type ?? '',
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [
|
||||
isVersionView,
|
||||
selectedArtifact?.slug,
|
||||
|
||||
@@ -22,7 +22,7 @@ export const KnowledgeBaseProvider: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
// oxlint-disable-next-line react-refresh/only-export-components
|
||||
export const useKnowledgeBaseContext = (): KnowledgeBaseContextType => {
|
||||
const context = useContext(KnowledgeBaseContext);
|
||||
if (context === undefined) {
|
||||
|
||||
@@ -3,7 +3,8 @@ import { MoreButton } from '@/components/more-button';
|
||||
import { RenameDialog } from '@/components/rename-dialog';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
|
||||
import { useEffect } from 'react';
|
||||
import { AgentListItem, AgentListItemType } from '@/interfaces/database/agent';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { AgentDropdown } from '../agents/agent-dropdown';
|
||||
import { useRenameAgent } from '../agents/use-rename-agent';
|
||||
|
||||
@@ -25,14 +26,23 @@ export function Agents({
|
||||
showAgentRenameModal,
|
||||
} = useRenameAgent();
|
||||
|
||||
const agentList = useMemo(
|
||||
() =>
|
||||
data.filter(
|
||||
(item): item is AgentListItem & { type: AgentListItemType.Agent } =>
|
||||
item.type !== AgentListItemType.CompilationTemplateGroup,
|
||||
),
|
||||
[data],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setListLength(data?.length || 0);
|
||||
setListLength(agentList?.length || 0);
|
||||
setLoading?.(loading || false);
|
||||
}, [data, setListLength, loading, setLoading]);
|
||||
}, [agentList, setListLength, loading, setLoading]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{data.slice(0, 10).map((x) => (
|
||||
{agentList.slice(0, 10).map((x) => (
|
||||
<HomeCard
|
||||
key={x.id}
|
||||
data={{ name: x.title, ...x } as any}
|
||||
|
||||
@@ -20,7 +20,7 @@ export const MemorySettingProvider: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
// oxlint-disable-next-line react-refresh/only-export-components
|
||||
export const useMemorySettingContext = (): MemorySettingContextType => {
|
||||
const context = useContext(MemorySettingContext);
|
||||
if (context === undefined) {
|
||||
|
||||
@@ -350,7 +350,7 @@ export const useRenameSearch = () => {
|
||||
});
|
||||
const detail = response.data?.data;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line typescript/no-unused-vars
|
||||
const { id, created_by, update_time, ...searchDataTemp } = detail;
|
||||
res = await updateSearch({
|
||||
...searchDataTemp,
|
||||
|
||||
@@ -201,7 +201,7 @@ export const useSkills = () => {
|
||||
|
||||
if (versionFolders.length === 0) {
|
||||
// No version folders found - fallback to legacy structure
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
// oxlint-disable-next-line typescript/no-use-before-define
|
||||
return fetchSkillDetailsLegacy(folderId, folderName, skillItems);
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ export const useSkills = () => {
|
||||
return { skills: [], total: 0 };
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
[ensureSkillSpaceFolder],
|
||||
);
|
||||
|
||||
@@ -697,7 +697,7 @@ export const useSkills = () => {
|
||||
}
|
||||
|
||||
// Search returned empty, fall back to file system
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(
|
||||
'[Skills] Search returned empty, falling back to file system',
|
||||
);
|
||||
@@ -714,7 +714,7 @@ export const useSkills = () => {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
[t, fetchSkillsFromFileSystem],
|
||||
);
|
||||
|
||||
@@ -1045,18 +1045,18 @@ export const useSkills = () => {
|
||||
// Delete search index for all versions
|
||||
// Backend uses skillName_version as doc_id (replacing '/' with '_')
|
||||
// We need to delete each version's index separately
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(
|
||||
`[deleteSkill] Starting index deletion for skillId: ${skillId}, spaceId: ${normalizedSpaceId}`,
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(`[deleteSkill] versionsToDelete:`, versionsToDelete);
|
||||
|
||||
for (const version of versionsToDelete) {
|
||||
const indexId =
|
||||
version === 'latest' ? skillId : `${skillId}/${version}`;
|
||||
try {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(
|
||||
`[deleteSkill] Deleting index: ${indexId} for space: ${normalizedSpaceId}`,
|
||||
);
|
||||
@@ -1064,10 +1064,10 @@ export const useSkills = () => {
|
||||
indexId,
|
||||
normalizedSpaceId,
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(`[deleteSkill] Successfully deleted index: ${indexId}`);
|
||||
} catch (indexError: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.warn(
|
||||
`[deleteSkill] Error deleting skill index for ${indexId}:`,
|
||||
indexError?.message || indexError,
|
||||
@@ -1082,7 +1082,7 @@ export const useSkills = () => {
|
||||
for (const version of commonVersions) {
|
||||
const indexId = `${skillId}/${version}`;
|
||||
try {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(
|
||||
`[deleteSkill] Trying to delete index with version: ${indexId}`,
|
||||
);
|
||||
@@ -1090,7 +1090,7 @@ export const useSkills = () => {
|
||||
indexId,
|
||||
normalizedSpaceId,
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log(
|
||||
`[deleteSkill] Successfully deleted index: ${indexId}`,
|
||||
);
|
||||
@@ -1116,7 +1116,7 @@ export const useSkills = () => {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
[t, fetchSkills, ensureSkillSpaceFolder, skills],
|
||||
);
|
||||
|
||||
@@ -1361,7 +1361,7 @@ export const useSkills = () => {
|
||||
async (folderId: string, folderName: string): Promise<Skill | null> => {
|
||||
return await fetchSkillDetails(folderId, folderName);
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ const SkillsPage: React.FC = () => {
|
||||
|
||||
useEffect(() => {
|
||||
loadSpaces();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Function to load skills with pagination and sorting
|
||||
@@ -259,14 +259,14 @@ const SkillsPage: React.FC = () => {
|
||||
fetchConfig(undefined, selectedSpaceId);
|
||||
// Use search API with pagination and sorting
|
||||
loadSkills();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [selectedSpaceId, selectedSpaceName]);
|
||||
|
||||
// Load skills when pagination or sorting changes
|
||||
useEffect(() => {
|
||||
if (!selectedSpaceId || !selectedSpaceName || hasSearched) return;
|
||||
loadSkills();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [currentPage, sortBy, sortOrder]);
|
||||
|
||||
const handleViewSkill = useCallback(
|
||||
|
||||
@@ -212,7 +212,7 @@ export const BedrockInstanceCard = forwardRef<
|
||||
useEffect(() => {
|
||||
// Reset form when initial values change (e.g. instance details load).
|
||||
form.reset(initialValues);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [initialValues]);
|
||||
|
||||
const authMode = useWatch({ control: form.control, name: 'auth_mode' });
|
||||
|
||||
@@ -704,7 +704,7 @@ export function useFormFields(
|
||||
{}) as Record<string, any>;
|
||||
void _ignored;
|
||||
return rest;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [defaultValuesKey]);
|
||||
|
||||
return { formFields, formDefaultValues };
|
||||
|
||||
@@ -188,7 +188,7 @@ export function useModelsCatalog({
|
||||
if (!credsReady) return;
|
||||
hasAutoFetchedRef.current = true;
|
||||
handleListModels();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [providerName, instanceName, hideActions, credsReady]);
|
||||
|
||||
// Mark `hasFetched` true once the per-instance query resolves — even if
|
||||
|
||||
@@ -239,7 +239,7 @@ export const SoMarkInstanceCard = forwardRef<
|
||||
useEffect(() => {
|
||||
// Reset form when initial values change (e.g. instance details load).
|
||||
form.reset(initialValues);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [initialValues]);
|
||||
|
||||
const imageFormatOptions = useMemo(
|
||||
|
||||
@@ -156,7 +156,7 @@ export const useListModelsPicker = ({
|
||||
];
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react/exhaustive-deps
|
||||
}, [visible, editMode, viewMode]);
|
||||
|
||||
// Triggered by ToggleList's onOpenChange — fires the API call with the
|
||||
|
||||
@@ -99,7 +99,7 @@ export const Default: Story = {
|
||||
className: 'rounded-md border',
|
||||
},
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [date, setDate] = useState<Date | undefined>(new Date());
|
||||
|
||||
return (
|
||||
@@ -143,7 +143,7 @@ export const RangeSelection: Story = {
|
||||
className: 'rounded-md border',
|
||||
},
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [range, setRange] = useState<{
|
||||
from: Date | undefined;
|
||||
to?: Date | undefined;
|
||||
@@ -206,7 +206,7 @@ export const WithoutOutsideDays: Story = {
|
||||
className: 'rounded-md border',
|
||||
},
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [date, setDate] = useState<Date | undefined>(new Date());
|
||||
|
||||
return (
|
||||
@@ -249,7 +249,7 @@ export const CustomStyling: Story = {
|
||||
showOutsideDays: true,
|
||||
},
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [date, setDate] = useState<Date | undefined>(new Date());
|
||||
|
||||
return (
|
||||
|
||||
@@ -169,7 +169,7 @@ export const Default: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -228,7 +228,7 @@ export const Small: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -297,7 +297,7 @@ export const Large: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -364,7 +364,7 @@ export const WithCustomFooter: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -448,7 +448,7 @@ export const WithoutFooter: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -515,7 +515,7 @@ export const FullScreen: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -581,9 +581,9 @@ export const LoadingState: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleOk = () => {
|
||||
@@ -668,7 +668,7 @@ export const Interactive: Story = {
|
||||
),
|
||||
},
|
||||
render: (args) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// oxlint-disable-next-line react/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable guard-for-in */
|
||||
/* oxlint-disable guard-for-in */
|
||||
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { isObject } from 'lodash';
|
||||
import omit from 'lodash/omit';
|
||||
|
||||
Reference in New Issue
Block a user