Feat: Add an update button to the graph page of the dataset. (#17571)

### Summary

Feat: Add an update button to the graph page of the dataset.
This commit is contained in:
balibabu
2026-07-30 18:40:29 +08:00
committed by GitHub
parent 3f8a3dfcff
commit 5ac8d92d2e
23 changed files with 355 additions and 252 deletions

View File

@@ -1,12 +1,12 @@
import { Button } from '@/components/ui/button';
import { Modal } from '@/components/ui/modal/modal';
import { GenerateType, GenerateTypeMap } from '@/constants/knowledge';
import { useUnBindTask } from '@/hooks/use-dataset-generate';
import { cn } from '@/lib/utils';
import { formatDate } from '@/utils/date';
import { lowerFirst } from 'lodash';
import { Trash2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { GenerateType, GenerateTypeMap } from './constants';
import { useUnBindTask } from './hook';
export type IGenerateLogButtonProps = {
finish_at: string;
@@ -112,5 +112,3 @@ export function GenerateLogButton(props: IGenerateLogProps) {
</div>
);
}
export default GenerateLogButton;

View File

@@ -1,19 +1,18 @@
import { FormLayout } from '@/constants/form';
import { DocumentParserType } from '@/constants/knowledge';
import { DocumentParserType, GenerateType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { cn } from '@/lib/utils';
import { useKnowledgeBaseContext } from '@/pages/dataset/contexts/knowledge-base-context';
import { LLMModelItem } from '@/pages/dataset/dataset-setting/configuration/common-item';
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
import {
GenerateLogButton,
IGenerateLogButtonProps,
} from '@/pages/dataset/dataset/generate-button/generate-log-button';
import { upperFirst } from 'lodash';
import { useCallback, useMemo } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { EntityTypesFormField } from '../entity-types-form-field';
import { FormContainer } from '../form-container';
import {
GenerateLogButton,
IGenerateLogButtonProps,
} from '../generate-log-button';
import { SliderInputFormField } from '../slider-input-form-field';
import {
FormControl,

View File

@@ -1,15 +1,14 @@
import { FormLayout } from '@/constants/form';
import { DocumentParserType } from '@/constants/knowledge';
import { DocumentParserType, GenerateType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
import {
GenerateLogButton,
IGenerateLogButtonProps,
} from '@/pages/dataset/dataset/generate-button/generate-log-button';
import random from 'lodash/random';
import { Shuffle } from 'lucide-react';
import { useCallback, useEffect, useMemo } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import {
GenerateLogButton,
IGenerateLogButtonProps,
} from '../generate-log-button';
import { SliderInputFormField } from '../slider-input-form-field';
import {
FormControl,

View File

@@ -116,3 +116,66 @@ export enum ParseType {
BuiltIn = 1,
Pipeline = 2,
}
export enum ProcessingType {
knowledgeGraph = 'Graph',
raptor = 'RAPTOR',
artifact = 'Artifact',
skill = 'Skill',
mindmap = 'Mindmap',
timeline = 'Timeline',
sessionEssence = 'Session_Essence',
sessionGraph = 'Session_Graph',
}
export const ProcessingTypeMap = {
[ProcessingType.knowledgeGraph]: 'Knowledge Graph',
[ProcessingType.raptor]: 'RAPTOR',
[ProcessingType.artifact]: 'Artifact',
[ProcessingType.skill]: 'Skill',
[ProcessingType.mindmap]: 'Mind Map',
[ProcessingType.timeline]: 'Timeline',
[ProcessingType.sessionEssence]: 'Session Essence',
[ProcessingType.sessionGraph]: 'Session Graph',
GraphRAG: 'Knowledge Graph',
};
export enum GenerateStatus {
Running = 'running',
Completed = 'completed',
Start = 'start',
Failed = 'failed',
}
export enum GenerateType {
KnowledgeGraph = 'KnowledgeGraph',
Raptor = 'Raptor',
Artifact = 'Artifact',
ToSkills = 'ToSkills',
MindMap = 'MindMap',
Timeline = 'Timeline',
SessionEssence = 'SessionEssence',
SessionGraph = 'SessionGraph',
}
export enum TraceType {
Graph = 'graph',
Raptor = 'raptor',
Artifact = 'artifact',
Skill = 'skill',
MindMap = 'mindmap',
Timeline = 'timeline',
SessionEssence = 'session_essence',
SessionGraph = 'session_graph',
}
export const GenerateTypeMap = {
[GenerateType.KnowledgeGraph]: ProcessingType.knowledgeGraph,
[GenerateType.Raptor]: ProcessingType.raptor,
[GenerateType.Artifact]: ProcessingType.artifact,
[GenerateType.ToSkills]: ProcessingType.skill,
[GenerateType.MindMap]: ProcessingType.mindmap,
[GenerateType.Timeline]: ProcessingType.timeline,
[GenerateType.SessionEssence]: ProcessingType.sessionEssence,
[GenerateType.SessionGraph]: ProcessingType.sessionGraph,
};

View File

@@ -1,4 +1,11 @@
import message from '@/components/ui/message';
import {
GenerateStatus,
GenerateType,
GenerateTypeMap,
ProcessingType,
TraceType,
} from '@/constants/knowledge';
import agentService from '@/services/agent-service';
import {
deletePipelineTask,
@@ -6,10 +13,9 @@ import {
traceIndex,
} from '@/services/knowledge-service';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router';
import { ProcessingType } from '../../dataset-overview/dataset-common';
import { GenerateType, GenerateTypeMap, TraceType } from './constants';
enum DatasetKey {
generate = 'generate',
@@ -111,6 +117,7 @@ export const useUnBindTask = () => {
});
return { handleUnbindTask };
};
export const useDatasetGenerate = () => {
const queryClient = useQueryClient();
const { id } = useParams();
@@ -164,3 +171,32 @@ export const useDatasetGenerate = () => {
});
return { runGenerate: mutateAsync, pauseGenerate, data, loading };
};
export function useGenerateStatus(data?: ITraceInfo) {
const status = useMemo(() => {
if (!data) {
return GenerateStatus.Start;
}
if (data.progress >= 1) {
return GenerateStatus.Completed;
} else if (!data.progress && data.progress !== 0) {
return GenerateStatus.Start;
} else if (data.progress < 0) {
return GenerateStatus.Failed;
} else if (data.progress < 1) {
return GenerateStatus.Running;
}
return GenerateStatus.Start;
}, [data]);
const percent = useMemo(() => {
if (status === GenerateStatus.Failed) {
return 100;
} else if (status === GenerateStatus.Running) {
return data!.progress * 100;
}
return 0;
}, [status, data]);
return { status, percent };
}

View File

@@ -1,9 +1,7 @@
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
import message from '@/components/ui/message';
import { ParseType } from '@/constants/knowledge';
import { GenerateType, ParseType } from '@/constants/knowledge';
import { ResponsePostType, ResponseType } from '@/interfaces/database/base';
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
import { DatasetGenerateKeys } from '@/pages/dataset/dataset/generate-button/hook';
import {
IArtifact,
IArtifactAlteration,
@@ -73,6 +71,7 @@ import {
isPipelineParserConfig,
} from './parser-config-utils';
import { useSetPaginationParams } from './route-hook';
import { DatasetGenerateKeys } from './use-dataset-generate';
export const enum KnowledgeApiAction {
FetchKnowledgeListByPage = 'fetchKnowledgeListByPage',
@@ -450,20 +449,20 @@ export const ArtifactTopicKeys = {
};
export const ArtifactAlterationKeys = {
detail: (datasetId: string) =>
[KnowledgeApiAction.FetchArtifactAlteration, datasetId] as const,
detail: (datasetId: string, kind: string) =>
[KnowledgeApiAction.FetchArtifactAlteration, datasetId, kind] as const,
};
export function useFetchArtifactAlteration() {
export function useFetchArtifactAlteration(kind: string) {
const knowledgeBaseId = useKnowledgeBaseId();
const { data, isFetching: loading } = useQuery<IArtifactAlteration | null>({
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId),
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId, kind),
initialData: null,
enabled: !!knowledgeBaseId,
enabled: !!knowledgeBaseId && !!kind,
gcTime: 0,
queryFn: async () => {
const { data } = await getArtifactsAlteration(knowledgeBaseId);
const { data } = await getArtifactsAlteration(knowledgeBaseId, kind);
return data?.data ?? null;
},
});
@@ -953,7 +952,7 @@ export const useClearWiki = () => {
return { data, loading, clearWiki: mutateAsync };
};
export const useRunArtifactIndex = () => {
export const useRunArtifactIndex = (kind: string) => {
const knowledgeBaseId = useKnowledgeBaseId();
const queryClient = useQueryClient();
@@ -968,7 +967,7 @@ export const useRunArtifactIndex = () => {
if (data?.code === 0) {
message.success(i18n.t('message.operated'));
queryClient.invalidateQueries({
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId),
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId, kind),
});
queryClient.invalidateQueries({
queryKey: ArtifactKeys.listByDataset(knowledgeBaseId),

View File

@@ -469,6 +469,9 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim
updateTooltip:
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
updateSheetTitle: 'Update Wiki',
updateStructureSheetTitle: 'Update {{name}}',
updateStructureTooltip:
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to update the {{name}}.',
viewUpdateLogs: 'View update logs',
log: 'Log',
noSkills: 'No skills yet',

View File

@@ -419,6 +419,9 @@ export default {
updateTooltip:
'发现 {{newlyUploaded}} 个新文档,{{removed}} 个已移除文档。点击编译并合并到当前 Wiki。',
updateSheetTitle: '更新 Wiki',
updateStructureSheetTitle: '更新{{name}}',
updateStructureTooltip:
'发现 {{newlyUploaded}} 个新文档,{{removed}} 个已移除文档。点击更新{{name}}。',
viewUpdateLogs: '查看更新日志',
log: '日志',
noSkills: '暂无技能',

View File

@@ -1,4 +1,4 @@
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
import { GenerateType } from '@/constants/knowledge';
export enum ViewMode {
LlmWiki = 'llm-wiki',

View File

@@ -7,16 +7,20 @@ import { getEntityDisplayName } from '@/components/structure-graph/adapters';
import { RepresentationRenderer } from '@/components/structure-graph/representation-renderer';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { GenerateStatus } from '@/constants/knowledge';
import {
useDatasetGenerate,
useGenerateStatus,
useTraceRunData,
} from '@/hooks/use-dataset-generate';
import {
DatasetStructureKeys,
useDeleteDatasetStructure,
useFetchArtifactAlteration,
useFetchDatasetStructureGraph,
useFetchKnowledgeBaseConfiguration,
useKnowledgeBaseId,
} from '@/hooks/use-knowledge-request';
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
import { useQueryClient } from '@tanstack/react-query';
import { Trash2 } from 'lucide-react';
import { useCallback, useEffect, useMemo, useState } from 'react';
@@ -30,6 +34,8 @@ import {
} from './constants';
import CompilationEmptyState from './empty-state';
import { CompilationLoadingCard } from './loading-card';
import { CompilationUpdateButton } from './update-button';
import { UpdateLogSheet } from './update-log-sheet';
interface DatasetStructureViewProps {
kind: StructureKind;
@@ -47,13 +53,21 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
const { deleteDatasetStructure, loading: deleting } =
useDeleteDatasetStructure();
const { data: structureRunData } = useTraceRunData(
ViewModeGenerateTypeMap[kind],
);
const generateType = ViewModeGenerateTypeMap[kind];
const { data: structureRunData } = useTraceRunData(generateType);
const { status: structureStatus } = useGenerateStatus(structureRunData);
const { data: alteration, loading: alterationLoading } =
useFetchArtifactAlteration(kind);
const { runGenerate, loading: runLoading } = useDatasetGenerate();
const [updateSheetOpen, setUpdateSheetOpen] = useState(false);
const newlyUploaded = alteration?.newly_uploaded ?? 0;
const removed = alteration?.removed ?? 0;
const hasChanges = newlyUploaded > 0 || removed > 0;
useEffect(() => {
if (structureStatus === GenerateStatus.completed) {
if (structureStatus === GenerateStatus.Completed) {
queryClient.invalidateQueries({
queryKey: DatasetStructureKeys.kind(knowledgeBaseId, kind),
});
@@ -105,6 +119,14 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
}
}, [deleteDatasetStructure, kind]);
const handleUpdateClick = useCallback(async () => {
setUpdateSheetOpen(true);
if (structureStatus === GenerateStatus.Running) {
return;
}
await runGenerate({ type: generateType }).catch(() => {});
}, [structureStatus, runGenerate, generateType]);
const canGenerate = (knowledgeBase?.chunk_count ?? 0) > 0;
if (loading && !data) {
@@ -124,16 +146,32 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
return (
<Card className="flex-1 min-h-0 overflow-hidden flex border-border-button rounded-xl flex-col">
<div className="flex justify-between gap-4 px-4 pt-4">
<ConfirmDeleteDialog
title={t('knowledgeDetails.deleteStructureConfirm', {
name: t(ViewModeLabelKeyMap[kind]),
})}
onOk={handleDeleteStructure}
>
<Button variant="outline" size="sm" disabled={deleting}>
<Trash2 />
</Button>
</ConfirmDeleteDialog>
<div className="flex items-center gap-2">
<ConfirmDeleteDialog
title={t('knowledgeDetails.deleteStructureConfirm', {
name: t(ViewModeLabelKeyMap[kind]),
})}
onOk={handleDeleteStructure}
>
<Button variant="outline" size="sm" disabled={deleting}>
<Trash2 />
</Button>
</ConfirmDeleteDialog>
<CompilationUpdateButton
traceData={structureRunData}
generateType={generateType}
hasChanges={hasChanges}
newlyUploaded={newlyUploaded}
removed={removed}
loading={alterationLoading || runLoading}
tooltip={t('knowledgeDetails.updateStructureTooltip', {
newlyUploaded,
removed,
name: t(ViewModeLabelKeyMap[kind]),
})}
onClick={handleUpdateClick}
/>
</div>
{kind === ViewMode.Graph && (
<SelectWithSearch
options={entityOptions}
@@ -151,6 +189,14 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
template={template}
highlightNodeId={selectedEntityName || null}
/>
<UpdateLogSheet
open={updateSheetOpen}
onOpenChange={setUpdateSheetOpen}
data={structureRunData}
title={t('knowledgeDetails.updateStructureSheetTitle', {
name: t(ViewModeLabelKeyMap[kind]),
})}
/>
</Card>
);
}

View File

@@ -7,8 +7,8 @@ import { Button } from '@/components/ui/button';
import {
ITraceInfo,
useDatasetGenerate,
} from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
useGenerateStatus,
} from '@/hooks/use-dataset-generate';
import {
GenerableViewMode,

View File

@@ -4,18 +4,17 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from '@/components/ui/resizable';
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
import {
useGenerateStatus,
useTraceRunData,
} from '@/hooks/use-dataset-generate';
import {
ArtifactKeys,
ArtifactTopicKeys,
useFetchArtifactTopicList,
useFetchKnowledgeBaseConfiguration,
} from '@/hooks/use-knowledge-request';
import {
GenerateStatus,
GenerateType,
} from '@/pages/dataset/dataset/generate-button/constants';
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
import { useQueryClient } from '@tanstack/react-query';
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router';
@@ -46,7 +45,7 @@ export function LlmWikiView() {
const [updateSheetOpen, setUpdateSheetOpen] = useState(false);
useEffect(() => {
if (artifactStatus === GenerateStatus.completed) {
if (artifactStatus === GenerateStatus.Completed) {
setUpdateSheetOpen(false);
queryClient.invalidateQueries({
queryKey: ArtifactKeys.listByDataset(id!),

View File

@@ -5,14 +5,13 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from '@/components/ui/resizable';
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
import {
useGenerateStatus,
useTraceRunData,
} from '@/hooks/use-dataset-generate';
import { DatasetSkillKeys } from '@/hooks/use-dataset-skill-request';
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
import {
GenerateStatus,
GenerateType,
} from '@/pages/dataset/dataset/generate-button/constants';
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
import { useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';
import { useParams } from 'react-router';
@@ -39,7 +38,7 @@ export function SkillsView() {
const { status: skillStatus } = useGenerateStatus(skillRunData);
useEffect(() => {
if (skillStatus === GenerateStatus.completed) {
if (skillStatus === GenerateStatus.Completed) {
queryClient.invalidateQueries({
queryKey: DatasetSkillKeys.tree(id!),
});

View File

@@ -0,0 +1,88 @@
import { WandSparkles } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
import {
ITraceInfo,
useGenerateStatus,
} from '@/hooks/use-dataset-generate';
import { UpdateRunProgress } from './update-run-progress';
type CompilationUpdateButtonProps = {
traceData?: ITraceInfo;
generateType: GenerateType;
hasChanges: boolean;
newlyUploaded: number;
removed: number;
loading: boolean;
tooltip: string;
onClick: () => void;
};
export function CompilationUpdateButton({
traceData,
generateType,
hasChanges,
newlyUploaded,
removed,
loading,
tooltip,
onClick,
}: CompilationUpdateButtonProps) {
const { t } = useTranslation();
const { status } = useGenerateStatus(traceData);
const isRunning = status === GenerateStatus.Running;
const isGenerating = isRunning || status === GenerateStatus.Failed;
// A failed trace persists (progress stays < 0) until the next run, so it
// must not keep the button visible on its own — only real changes or a
// live run should.
if (!hasChanges && !isRunning) {
return null;
}
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant={'outline'} onClick={onClick} disabled={loading}>
{isGenerating ? (
<UpdateRunProgress data={traceData} generateType={generateType} />
) : (
<>
{t('knowledgeDetails.update', { defaultValue: 'Update' })}
{newlyUploaded > 0 && (
<Badge variant="success" className="ml-1">
{newlyUploaded}
</Badge>
)}
{removed > 0 && (
<Badge variant="destructive" className="ml-1">
{removed}
</Badge>
)}
<WandSparkles />
</>
)}
</Button>
</TooltipTrigger>
<TooltipContent>
{isGenerating
? t('knowledgeDetails.viewUpdateLogs', {
defaultValue: 'View update logs',
})
: tooltip}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

View File

@@ -1,5 +1,4 @@
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import {
Sheet,
@@ -7,28 +6,28 @@ import {
SheetHeader,
SheetTitle,
} from '@/components/ui/sheet';
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
import { ITraceInfo } from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
import { GenerateStatus } from '@/constants/knowledge';
import { ITraceInfo, useGenerateStatus } from '@/hooks/use-dataset-generate';
import { ProgressLogPanel } from '../progress-log-panel';
import { ProgressLogPanel } from './progress-log-panel';
type WikiUpdateSheetProps = {
type UpdateLogSheetProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
data?: ITraceInfo;
title: string;
};
export function WikiUpdateSheet({
export function UpdateLogSheet({
open,
onOpenChange,
data,
}: WikiUpdateSheetProps) {
const { t } = useTranslation();
title,
}: UpdateLogSheetProps) {
const { status } = useGenerateStatus(data);
useEffect(() => {
if (status === GenerateStatus.completed) {
if (status === GenerateStatus.Completed) {
onOpenChange(false);
}
}, [status, onOpenChange]);
@@ -37,11 +36,7 @@ export function WikiUpdateSheet({
<Sheet open={open} onOpenChange={onOpenChange} modal={false}>
<SheetContent className="flex flex-col">
<SheetHeader>
<SheetTitle>
{t('knowledgeDetails.updateSheetTitle', {
defaultValue: 'Update Wiki',
})}
</SheetTitle>
<SheetTitle>{title}</SheetTitle>
</SheetHeader>
<div className="flex-1 min-h-0 flex flex-col pt-4">
<ProgressLogPanel

View File

@@ -2,20 +2,24 @@ import { CircleX } from 'lucide-react';
import { useCallback, type MouseEvent } from 'react';
import { IconFontFill } from '@/components/icon-font';
import { cn } from '@/lib/utils';
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
import { GenerateType } from '@/constants/knowledge';
import {
ITraceInfo,
useDatasetGenerate,
} from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
useGenerateStatus,
} from '@/hooks/use-dataset-generate';
import { cn } from '@/lib/utils';
import { toFixed } from '@/utils/common-util';
type WikiUpdateProgressProps = {
type UpdateRunProgressProps = {
data?: ITraceInfo;
generateType: GenerateType;
};
export function WikiUpdateProgress({ data }: WikiUpdateProgressProps) {
export function UpdateRunProgress({
data,
generateType,
}: UpdateRunProgressProps) {
const { pauseGenerate } = useDatasetGenerate();
const { status, percent } = useGenerateStatus(data);
@@ -23,12 +27,10 @@ export function WikiUpdateProgress({ data }: WikiUpdateProgressProps) {
(e: MouseEvent) => {
e.stopPropagation();
if (data?.id) {
pauseGenerate({ task_id: data.id, type: GenerateType.Artifact }).catch(
() => {},
);
pauseGenerate({ task_id: data.id, type: generateType }).catch(() => {});
}
},
[pauseGenerate, data?.id],
[pauseGenerate, data?.id, generateType],
);
return (

View File

@@ -9,8 +9,8 @@ type UseWikiUpdateOptions = {
};
export function useWikiUpdate({ onUpdate }: UseWikiUpdateOptions = {}) {
const { data, loading: queryLoading } = useFetchArtifactAlteration();
const { runArtifactIndex, loading: mutationLoading } = useRunArtifactIndex();
const { data, loading: queryLoading } = useFetchArtifactAlteration('wiki');
const { runArtifactIndex, loading: mutationLoading } = useRunArtifactIndex('wiki');
const newlyUploaded = data?.newly_uploaded ?? 0;
const removed = data?.removed ?? 0;

View File

@@ -1,28 +1,23 @@
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';
ITraceInfo,
useGenerateStatus,
} from '@/hooks/use-dataset-generate';
import { IArtifact } from '@/interfaces/database/dataset';
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
import { ITraceInfo } from '@/pages/dataset/dataset/generate-button/hook';
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
import { Trash2, WandSparkles } from 'lucide-react';
import { Trash2 } from 'lucide-react';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { LeftPanelTab } from '../constants';
import { CompilationUpdateButton } from '../update-button';
import { UpdateLogSheet } from '../update-log-sheet';
import { useWikiClear } from './hooks/use-wiki-clear';
import { useWikiUpdate } from './hooks/use-wiki-update';
import { WikiGraphPanel } from './wiki-graph-panel';
import { WikiNavBar } from './wiki-nav-bar';
import { WikiUpdateProgress } from './wiki-update-progress';
import { WikiUpdateSheet } from './wiki-update-sheet';
type WikiLeftPanelProps = {
tab: LeftPanelTab;
@@ -62,12 +57,10 @@ export function WikiLeftPanel({
} = useWikiUpdate();
const { status } = useGenerateStatus(traceData);
const isGenerating =
status === GenerateStatus.running || status === GenerateStatus.failed;
const handleUpdateClick = useCallback(async () => {
onUpdateSheetOpenChange(true);
if (status === GenerateStatus.running) {
if (status === GenerateStatus.Running) {
return;
}
await handleUpdate();
@@ -76,50 +69,21 @@ export function WikiLeftPanel({
return (
<aside className="size-full flex flex-col p-5">
<div className="flex items-center justify-between pb-5">
{(hasChanges || isGenerating) && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={'outline'}
onClick={handleUpdateClick}
disabled={updateLoading}
>
{isGenerating ? (
<WikiUpdateProgress data={traceData} />
) : (
<>
{t('knowledgeDetails.update', { defaultValue: 'Update' })}
{newlyUploaded > 0 && (
<Badge variant="success" className="ml-1">
{newlyUploaded}
</Badge>
)}
{removed > 0 && (
<Badge variant="destructive" className="ml-1">
{removed}
</Badge>
)}
<WandSparkles />
</>
)}
</Button>
</TooltipTrigger>
<TooltipContent>
{isGenerating
? t('knowledgeDetails.viewUpdateLogs', {
defaultValue: 'View update logs',
})
: t('knowledgeDetails.updateTooltip', {
newlyUploaded,
removed,
defaultValue:
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
})}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
<CompilationUpdateButton
traceData={traceData}
generateType={GenerateType.Artifact}
hasChanges={hasChanges}
newlyUploaded={newlyUploaded}
removed={removed}
loading={updateLoading}
tooltip={t('knowledgeDetails.updateTooltip', {
newlyUploaded,
removed,
defaultValue:
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
})}
onClick={handleUpdateClick}
/>
<ConfirmDeleteDialog
open={open}
onOpenChange={setOpen}
@@ -164,10 +128,13 @@ export function WikiLeftPanel({
)}
</div>
<WikiUpdateSheet
<UpdateLogSheet
open={updateSheetOpen}
onOpenChange={onUpdateSheetOpenChange}
data={traceData}
title={t('knowledgeDetails.updateSheetTitle', {
defaultValue: 'Update Wiki',
})}
/>
</aside>
);

View File

@@ -2,26 +2,3 @@ export enum LogTabs {
FILE_LOGS = 'fileLogs',
DATASET_LOGS = 'datasetLogs',
}
export enum ProcessingType {
knowledgeGraph = 'Graph',
raptor = 'RAPTOR',
artifact = 'Artifact',
skill = 'Skill',
mindmap = 'Mindmap',
timeline = 'Timeline',
sessionEssence = 'Session_Essence',
sessionGraph = 'Session_Graph',
}
export const ProcessingTypeMap = {
[ProcessingType.knowledgeGraph]: 'Knowledge Graph',
[ProcessingType.raptor]: 'RAPTOR',
[ProcessingType.artifact]: 'Artifact',
[ProcessingType.skill]: 'Skill',
[ProcessingType.mindmap]: 'Mind Map',
[ProcessingType.timeline]: 'Timeline',
[ProcessingType.sessionEssence]: 'Session Essence',
[ProcessingType.sessionGraph]: 'Session Graph',
GraphRAG: 'Knowledge Graph',
};

View File

@@ -18,7 +18,11 @@ import {
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { RunningStatusMap } from '@/constants/knowledge';
import {
ProcessingType,
ProcessingTypeMap,
RunningStatusMap,
} from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { cn } from '@/lib/utils';
@@ -45,7 +49,7 @@ import { FC, useMemo, useState } from 'react';
import { useParams } from 'react-router';
import { RunningStatus } from '../dataset/constant';
import ProcessLogModal, { ILogInfo } from '../process-log-modal';
import { LogTabs, ProcessingType, ProcessingTypeMap } from './dataset-common';
import { LogTabs } from './dataset-common';
import { DocumentLog, FileLogsTableProps, IFileLogItem } from './interface';
export const getFileLogsTableColumns = (

View File

@@ -1,41 +0,0 @@
import { ProcessingType } from '../../dataset-overview/dataset-common';
export const GenerateStatus = {
running: 'running',
completed: 'completed',
start: 'start',
failed: 'failed',
};
export enum GenerateType {
KnowledgeGraph = 'KnowledgeGraph',
Raptor = 'Raptor',
Artifact = 'Artifact',
ToSkills = 'ToSkills',
MindMap = 'MindMap',
Timeline = 'Timeline',
SessionEssence = 'SessionEssence',
SessionGraph = 'SessionGraph',
}
export enum TraceType {
Graph = 'graph',
Raptor = 'raptor',
Artifact = 'artifact',
Skill = 'skill',
MindMap = 'mindmap',
Timeline = 'timeline',
SessionEssence = 'session_essence',
SessionGraph = 'session_graph',
}
export const GenerateTypeMap = {
[GenerateType.KnowledgeGraph]: ProcessingType.knowledgeGraph,
[GenerateType.Raptor]: ProcessingType.raptor,
[GenerateType.Artifact]: ProcessingType.artifact,
[GenerateType.ToSkills]: ProcessingType.skill,
[GenerateType.MindMap]: ProcessingType.mindmap,
[GenerateType.Timeline]: ProcessingType.timeline,
[GenerateType.SessionEssence]: ProcessingType.sessionEssence,
[GenerateType.SessionGraph]: ProcessingType.sessionGraph,
};

View File

@@ -1,33 +0,0 @@
import { useMemo } from 'react';
import { GenerateStatus } from './constants';
import { ITraceInfo } from './hook';
export function useGenerateStatus(data?: ITraceInfo) {
const status = useMemo(() => {
if (!data) {
return GenerateStatus.start;
}
if (data.progress >= 1) {
return GenerateStatus.completed;
} else if (!data.progress && data.progress !== 0) {
return GenerateStatus.start;
} else if (data.progress < 0) {
return GenerateStatus.failed;
} else if (data.progress < 1) {
return GenerateStatus.running;
}
return GenerateStatus.start;
}, [data]);
const percent = useMemo(() => {
if (status === GenerateStatus.failed) {
return 100;
} else if (status === GenerateStatus.running) {
return data!.progress * 100;
}
return 0;
}, [status, data]);
return { status, percent };
}

View File

@@ -1,3 +1,4 @@
import { ProcessingType } from '@/constants/knowledge';
import { IRenameTag } from '@/interfaces/database/dataset';
import {
IFetchArtifactGraphRequestParams,
@@ -7,7 +8,6 @@ import {
IFetchKnowledgeListRequestParams,
IUpdateArtifactPageRequestBody,
} from '@/interfaces/request/knowledge';
import { ProcessingType } from '@/pages/dataset/dataset-overview/dataset-common';
import api from '@/utils/api';
import nextRequest from '@/utils/next-request';
import registerServer from '@/utils/register-server';
@@ -419,8 +419,8 @@ export const getArtifactGraph = (
params?: IFetchArtifactGraphRequestParams,
) => request.get(api.getArtifactGraph(datasetId), { params });
export const getArtifactsAlteration = (datasetId: string) =>
request.get(api.artifactsAlteration(datasetId));
export const getArtifactsAlteration = (datasetId: string, kind: string) =>
request.get(api.artifactsAlteration(datasetId), { params: { kind } });
export const getArtifactsStructure = (
datasetId: string,