mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 04:15:53 +08:00
### What problem does this PR solve? Feat: Modify the style of the dataset page #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
fc379e90d1
commit
cb37f00a8f
@ -19,6 +19,7 @@ import weekYear from 'dayjs/plugin/weekYear';
|
|||||||
import weekday from 'dayjs/plugin/weekday';
|
import weekday from 'dayjs/plugin/weekday';
|
||||||
import React, { ReactNode, useEffect, useState } from 'react';
|
import React, { ReactNode, useEffect, useState } from 'react';
|
||||||
import { ThemeProvider, useTheme } from './components/theme-provider';
|
import { ThemeProvider, useTheme } from './components/theme-provider';
|
||||||
|
import { SidebarProvider } from './components/ui/sidebar';
|
||||||
import { TooltipProvider } from './components/ui/tooltip';
|
import { TooltipProvider } from './components/ui/tooltip';
|
||||||
import storage from './utils/authorization-util';
|
import storage from './utils/authorization-util';
|
||||||
|
|
||||||
@ -68,7 +69,9 @@ function Root({ children }: React.PropsWithChildren) {
|
|||||||
}}
|
}}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
>
|
>
|
||||||
<App>{children}</App>
|
<SidebarProvider>
|
||||||
|
<App>{children}</App>
|
||||||
|
</SidebarProvider>
|
||||||
<Sonner position={'top-right'} expand richColors closeButton></Sonner>
|
<Sonner position={'top-right'} expand richColors closeButton></Sonner>
|
||||||
<Toaster />
|
<Toaster />
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import { FileIconMap } from '@/constants/file';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { getExtension } from '@/utils/document-util';
|
||||||
|
|
||||||
type IconFontType = {
|
type IconFontType = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -10,3 +12,18 @@ export const IconFont = ({ name, className }: IconFontType) => (
|
|||||||
<use xlinkHref={`#icon-${name}`} />
|
<use xlinkHref={`#icon-${name}`} />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export function FileIcon({
|
||||||
|
name,
|
||||||
|
className,
|
||||||
|
type,
|
||||||
|
}: IconFontType & { type?: string }) {
|
||||||
|
const isFolder = type === 'folder';
|
||||||
|
return (
|
||||||
|
<span className={cn('size-4', className)}>
|
||||||
|
<IconFont
|
||||||
|
name={isFolder ? 'file' : FileIconMap[getExtension(name)]}
|
||||||
|
></IconFont>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { cn } from '@/lib/utils';
|
||||||
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
||||||
import { random } from 'lodash';
|
import { random } from 'lodash';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
@ -15,16 +16,24 @@ export const RAGFlowAvatar = forwardRef<
|
|||||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & {
|
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & {
|
||||||
name?: string;
|
name?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
|
isPerson?: boolean;
|
||||||
}
|
}
|
||||||
>(({ name, avatar, ...props }, ref) => {
|
>(({ name, avatar, isPerson = false, className, ...props }, ref) => {
|
||||||
const index = random(0, 3);
|
const index = random(0, 3);
|
||||||
console.log('🚀 ~ index:', index);
|
console.log('🚀 ~ index:', index);
|
||||||
const value = Colors[index];
|
const value = Colors[index];
|
||||||
return (
|
return (
|
||||||
<Avatar ref={ref} {...props}>
|
<Avatar
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
className={cn(className, { 'rounded-md': !isPerson })}
|
||||||
|
>
|
||||||
<AvatarImage src={avatar} />
|
<AvatarImage src={avatar} />
|
||||||
<AvatarFallback
|
<AvatarFallback
|
||||||
className={`bg-gradient-to-b from-[${value.from}] to-[${value.to}]`}
|
className={cn(
|
||||||
|
`bg-gradient-to-b from-[${value.from}] to-[${value.to}]`,
|
||||||
|
{ 'rounded-md': !isPerson },
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{name?.slice(0, 1)}
|
{name?.slice(0, 1)}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
|
@ -11,7 +11,7 @@ const Switch = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SwitchPrimitives.Root
|
<SwitchPrimitives.Root
|
||||||
className={cn(
|
className={cn(
|
||||||
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-colors-background-core-standard data-[state=unchecked]:bg-colors-background-inverse-standard',
|
'peer inline-flex h-3.5 w-6 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-background-checked data-[state=unchecked]:bg-text-sub-title',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@ -19,7 +19,7 @@ const Switch = React.forwardRef<
|
|||||||
>
|
>
|
||||||
<SwitchPrimitives.Thumb
|
<SwitchPrimitives.Thumb
|
||||||
className={cn(
|
className={cn(
|
||||||
'pointer-events-none block h-5 w-5 rounded-full bg-colors-text-neutral-strong shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
|
'pointer-events-none block size-3 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-2 data-[state=unchecked]:translate-x-0',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</SwitchPrimitives.Root>
|
</SwitchPrimitives.Root>
|
||||||
|
@ -6,10 +6,10 @@ const Table = React.forwardRef<
|
|||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
React.HTMLAttributes<HTMLTableElement>
|
React.HTMLAttributes<HTMLTableElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div className="relative w-full overflow-auto">
|
<div className="relative w-full overflow-auto rounded-2xl bg-background-card">
|
||||||
<table
|
<table
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('w-full caption-bottom text-sm', className)}
|
className={cn('w-full caption-bottom text-sm ', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -73,7 +73,7 @@ const TableHead = React.forwardRef<
|
|||||||
<th
|
<th
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
'h-12 px-4 text-left align-middle font-normal text-text-sub-title [&:has([role=checkbox])]:pr-0',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@ -87,7 +87,10 @@ const TableCell = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<td
|
<td
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
|
className={cn(
|
||||||
|
'p-4 align-middle [&:has([role=checkbox])]:pr-0 text-text-title font-normal',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
15
web/src/constants/file.ts
Normal file
15
web/src/constants/file.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export const FileIconMap = {
|
||||||
|
doc: 'doc',
|
||||||
|
docx: 'doc',
|
||||||
|
pdf: 'pdf',
|
||||||
|
xls: 'excel',
|
||||||
|
xlsx: 'excel',
|
||||||
|
ppt: 'ppt',
|
||||||
|
pptx: 'ppt',
|
||||||
|
jpg: 'jpg',
|
||||||
|
jpeg: 'jpg',
|
||||||
|
png: 'png',
|
||||||
|
txt: 'text',
|
||||||
|
csv: 'pdf',
|
||||||
|
md: 'md',
|
||||||
|
};
|
@ -17,6 +17,7 @@ body {
|
|||||||
|
|
||||||
.ant-app {
|
.ant-app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scroll bar stylings */
|
/* Scroll bar stylings */
|
||||||
|
@ -25,6 +25,7 @@ export interface IKnowledge {
|
|||||||
embd_id: string;
|
embd_id: string;
|
||||||
nickname: string;
|
nickname: string;
|
||||||
operator_permission: number;
|
operator_permission: number;
|
||||||
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IKnowledgeResult {
|
export interface IKnowledgeResult {
|
||||||
|
@ -119,59 +119,51 @@ export function DatasetTable({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="rounded-md border">
|
<Table>
|
||||||
<Table>
|
<TableHeader>
|
||||||
<TableHeader>
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
<TableRow key={headerGroup.id}>
|
||||||
<TableRow key={headerGroup.id}>
|
{headerGroup.headers.map((header) => {
|
||||||
{headerGroup.headers.map((header) => {
|
return (
|
||||||
return (
|
<TableHead key={header.id}>
|
||||||
<TableHead key={header.id}>
|
{header.isPlaceholder
|
||||||
{header.isPlaceholder
|
? null
|
||||||
? null
|
: flexRender(
|
||||||
: flexRender(
|
header.column.columnDef.header,
|
||||||
header.column.columnDef.header,
|
header.getContext(),
|
||||||
header.getContext(),
|
)}
|
||||||
)}
|
</TableHead>
|
||||||
</TableHead>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody className="relative">
|
||||||
|
{table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
data-state={row.getIsSelected() && 'selected'}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell
|
||||||
|
key={cell.id}
|
||||||
|
className={cell.column.columnDef.meta?.cellClassName}
|
||||||
|
>
|
||||||
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))
|
||||||
</TableHeader>
|
) : (
|
||||||
<TableBody className="relative">
|
<TableRow>
|
||||||
{table.getRowModel().rows?.length ? (
|
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||||
table.getRowModel().rows.map((row) => (
|
No results.
|
||||||
<TableRow
|
</TableCell>
|
||||||
key={row.id}
|
</TableRow>
|
||||||
data-state={row.getIsSelected() && 'selected'}
|
)}
|
||||||
>
|
</TableBody>
|
||||||
{row.getVisibleCells().map((cell) => (
|
</Table>
|
||||||
<TableCell
|
|
||||||
key={cell.id}
|
|
||||||
className={cell.column.columnDef.meta?.cellClassName}
|
|
||||||
>
|
|
||||||
{flexRender(
|
|
||||||
cell.column.columnDef.cell,
|
|
||||||
cell.getContext(),
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell
|
|
||||||
colSpan={columns.length}
|
|
||||||
className="h-24 text-center"
|
|
||||||
>
|
|
||||||
No results.
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
<div className="flex items-center justify-end space-x-2 py-4">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="flex-1 text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{' '}
|
{table.getFilteredSelectedRowModel().rows.length} of{' '}
|
||||||
|
@ -60,7 +60,7 @@ export default function Dataset() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-8">
|
<section className="p-5">
|
||||||
<ListFilterBar
|
<ListFilterBar
|
||||||
title="Dataset"
|
title="Dataset"
|
||||||
onSearchChange={handleInputChange}
|
onSearchChange={handleInputChange}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import SvgIcon from '@/components/svg-icon';
|
import { FileIcon } from '@/components/icon-font';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
@ -12,7 +12,6 @@ import { useSetDocumentStatus } from '@/hooks/use-document-request';
|
|||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { getExtension } from '@/utils/document-util';
|
|
||||||
import { ColumnDef } from '@tanstack/table-core';
|
import { ColumnDef } from '@tanstack/table-core';
|
||||||
import { ArrowUpDown } from 'lucide-react';
|
import { ArrowUpDown } from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -88,10 +87,7 @@ export function useDatasetTableColumns({
|
|||||||
row.original.kb_id,
|
row.original.kb_id,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<SvgIcon
|
<FileIcon name={name}></FileIcon>
|
||||||
name={`file-icon/${getExtension(name)}`}
|
|
||||||
width={24}
|
|
||||||
></SvgIcon>
|
|
||||||
<span className={cn('truncate')}>{name}</span>
|
<span className={cn('truncate')}>{name}</span>
|
||||||
</div>
|
</div>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
|
@ -1,55 +1,78 @@
|
|||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useSecondPathName } from '@/hooks/route-hook';
|
import { useSecondPathName } from '@/hooks/route-hook';
|
||||||
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn, formatBytes } from '@/lib/utils';
|
||||||
import { Routes } from '@/routes';
|
import { Routes } from '@/routes';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatPureDate } from '@/utils/date';
|
||||||
import { Banknote, LayoutGrid, User } from 'lucide-react';
|
import { Banknote, Database, FileSearch2 } from 'lucide-react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHandleMenuClick } from './hooks';
|
import { useHandleMenuClick } from './hooks';
|
||||||
|
|
||||||
const items = [
|
|
||||||
{ icon: User, label: 'Dataset', key: Routes.DatasetBase },
|
|
||||||
{
|
|
||||||
icon: LayoutGrid,
|
|
||||||
label: 'Retrieval testing',
|
|
||||||
key: Routes.DatasetTesting,
|
|
||||||
},
|
|
||||||
{ icon: Banknote, label: 'Settings', key: Routes.DatasetSetting },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function SideBar() {
|
export function SideBar() {
|
||||||
const pathName = useSecondPathName();
|
const pathName = useSecondPathName();
|
||||||
const { handleMenuClick } = useHandleMenuClick();
|
const { handleMenuClick } = useHandleMenuClick();
|
||||||
const { data } = useFetchKnowledgeBaseConfiguration();
|
const { data } = useFetchKnowledgeBaseConfiguration();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const items = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
icon: Database,
|
||||||
|
label: t(`knowledgeDetails.dataset`),
|
||||||
|
key: Routes.DatasetBase,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: FileSearch2,
|
||||||
|
label: t(`knowledgeDetails.testing`),
|
||||||
|
key: Routes.DatasetTesting,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Banknote,
|
||||||
|
label: t(`knowledgeDetails.configuration`),
|
||||||
|
key: Routes.DatasetSetting,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-60 relative border-r ">
|
<aside className="relative p-5 space-y-8">
|
||||||
<div className="p-6 space-y-2 border-b">
|
<div className="flex gap-2.5 max-w-[200px] items-center">
|
||||||
<Avatar className="size-20 rounded-lg">
|
<RAGFlowAvatar
|
||||||
<AvatarImage src={data.avatar} />
|
avatar={data.avatar}
|
||||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
name={data.name}
|
||||||
</Avatar>
|
className="size-16"
|
||||||
|
></RAGFlowAvatar>
|
||||||
<h3 className="text-lg font-semibold mb-2 line-clamp-1">{data.name}</h3>
|
<div className=" text-text-sub-title text-xs space-y-1">
|
||||||
<div className="text-sm opacity-80">
|
<h3 className="text-lg font-semibold line-clamp-1 text-text-title">
|
||||||
{data.doc_num} files | {data.chunk_num} chunks
|
{data.name}
|
||||||
</div>
|
</h3>
|
||||||
<div className="text-sm opacity-80">
|
<div className="flex justify-between">
|
||||||
Created {formatDate(data.create_time)}
|
<span>{data.doc_num} files</span>
|
||||||
|
<span>{formatBytes(data.size)}</span>
|
||||||
|
</div>
|
||||||
|
<div>Created {formatPureDate(data.create_time)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4">
|
|
||||||
|
<div className="w-[200px] flex flex-col gap-5">
|
||||||
{items.map((item, itemIdx) => {
|
{items.map((item, itemIdx) => {
|
||||||
const active = '/' + pathName === item.key;
|
const active = '/' + pathName === item.key;
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
key={itemIdx}
|
key={itemIdx}
|
||||||
variant={active ? 'secondary' : 'ghost'}
|
variant={active ? 'secondary' : 'ghost'}
|
||||||
className={cn('w-full justify-start gap-2.5 p-6 relative')}
|
className={cn(
|
||||||
|
'w-full justify-start gap-2.5 px-3 relative h-10 text-text-sub-title-invert',
|
||||||
|
{
|
||||||
|
'bg-background-card': active,
|
||||||
|
'text-text-title': active,
|
||||||
|
},
|
||||||
|
)}
|
||||||
onClick={handleMenuClick(item.key)}
|
onClick={handleMenuClick(item.key)}
|
||||||
>
|
>
|
||||||
<item.icon className="w-6 h-6" />
|
<item.icon className="size-4" />
|
||||||
<span>{item.label}</span>
|
<span>{item.label}</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -14,8 +14,8 @@ import {
|
|||||||
import { ArrowUpDown } from 'lucide-react';
|
import { ArrowUpDown } from 'lucide-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { FileIcon } from '@/components/icon-font';
|
||||||
import { RenameDialog } from '@/components/rename-dialog';
|
import { RenameDialog } from '@/components/rename-dialog';
|
||||||
import SvgIcon from '@/components/svg-icon';
|
|
||||||
import { TableEmpty, TableSkeleton } from '@/components/table-skeleton';
|
import { TableEmpty, TableSkeleton } from '@/components/table-skeleton';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
@ -39,7 +39,6 @@ import { IFile } from '@/interfaces/database/file-manager';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { formatFileSize } from '@/utils/common-util';
|
import { formatFileSize } from '@/utils/common-util';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { getExtension } from '@/utils/document-util';
|
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -148,10 +147,9 @@ export function FilesTable({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<SvgIcon
|
<span className="size-4">
|
||||||
name={`file-icon/${isFolder ? 'folder' : getExtension(name)}`}
|
<FileIcon name={name} type={type}></FileIcon>
|
||||||
width={24}
|
</span>
|
||||||
></SvgIcon>
|
|
||||||
<span
|
<span
|
||||||
className={cn('truncate', { ['cursor-pointer']: isFolder })}
|
className={cn('truncate', { ['cursor-pointer']: isFolder })}
|
||||||
onClick={handleNameClick}
|
onClick={handleNameClick}
|
||||||
@ -262,54 +260,50 @@ export function FilesTable({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="rounded-md border">
|
<Table>
|
||||||
<Table>
|
<TableHeader>
|
||||||
<TableHeader>
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
<TableRow key={headerGroup.id}>
|
||||||
<TableRow key={headerGroup.id}>
|
{headerGroup.headers.map((header) => {
|
||||||
{headerGroup.headers.map((header) => {
|
return (
|
||||||
return (
|
<TableHead key={header.id}>
|
||||||
<TableHead key={header.id}>
|
{header.isPlaceholder
|
||||||
{header.isPlaceholder
|
? null
|
||||||
? null
|
: flexRender(
|
||||||
: flexRender(
|
header.column.columnDef.header,
|
||||||
header.column.columnDef.header,
|
header.getContext(),
|
||||||
header.getContext(),
|
)}
|
||||||
)}
|
</TableHead>
|
||||||
</TableHead>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{loading ? (
|
||||||
|
<TableSkeleton columnsLength={columns.length}></TableSkeleton>
|
||||||
|
) : table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
data-state={row.getIsSelected() && 'selected'}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell
|
||||||
|
key={cell.id}
|
||||||
|
className={cell.column.columnDef.meta?.cellClassName}
|
||||||
|
>
|
||||||
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))
|
||||||
</TableHeader>
|
) : (
|
||||||
<TableBody>
|
<TableEmpty columnsLength={columns.length}></TableEmpty>
|
||||||
{loading ? (
|
)}
|
||||||
<TableSkeleton columnsLength={columns.length}></TableSkeleton>
|
</TableBody>
|
||||||
) : table.getRowModel().rows?.length ? (
|
</Table>
|
||||||
table.getRowModel().rows.map((row) => (
|
|
||||||
<TableRow
|
|
||||||
key={row.id}
|
|
||||||
data-state={row.getIsSelected() && 'selected'}
|
|
||||||
>
|
|
||||||
{row.getVisibleCells().map((cell) => (
|
|
||||||
<TableCell
|
|
||||||
key={cell.id}
|
|
||||||
className={cell.column.columnDef.meta?.cellClassName}
|
|
||||||
>
|
|
||||||
{flexRender(
|
|
||||||
cell.column.columnDef.cell,
|
|
||||||
cell.getContext(),
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<TableEmpty columnsLength={columns.length}></TableEmpty>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
<div className="flex items-center justify-end space-x-2 py-4">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="flex-1 text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of {total} row(s)
|
{table.getFilteredSelectedRowModel().rows.length} of {total} row(s)
|
||||||
|
@ -88,7 +88,7 @@ export default function Files() {
|
|||||||
>
|
>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant={'tertiary'} size={'sm'}>
|
<Button>
|
||||||
<Upload />
|
<Upload />
|
||||||
{t('knowledgeDetails.addFile')}
|
{t('knowledgeDetails.addFile')}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -50,6 +50,7 @@ module.exports = {
|
|||||||
'text-title-invert': 'var(--text-title-invert)',
|
'text-title-invert': 'var(--text-title-invert)',
|
||||||
'background-header-bar': 'var(--background-header-bar)',
|
'background-header-bar': 'var(--background-header-bar)',
|
||||||
'background-card': 'var(--background-card)',
|
'background-card': 'var(--background-card)',
|
||||||
|
'background-checked': 'var(--background-checked)',
|
||||||
|
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: 'hsl(var(--primary))',
|
DEFAULT: 'hsl(var(--primary))',
|
||||||
|
@ -84,6 +84,8 @@
|
|||||||
--background-header-bar: rgba(11, 11, 12, 1);
|
--background-header-bar: rgba(11, 11, 12, 1);
|
||||||
--text-title-invert: rgba(255, 255, 255, 1);
|
--text-title-invert: rgba(255, 255, 255, 1);
|
||||||
--background-card: rgba(22, 22, 24, 0.05);
|
--background-card: rgba(22, 22, 24, 0.05);
|
||||||
|
|
||||||
|
--background-checked: rgba(76, 164, 231, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
@ -189,6 +191,7 @@
|
|||||||
--text-title-invert: rgba(22, 22, 24, 1);
|
--text-title-invert: rgba(22, 22, 24, 1);
|
||||||
|
|
||||||
--background-card: rgba(255, 255, 255, 0.05);
|
--background-card: rgba(255, 255, 255, 0.05);
|
||||||
|
--background-checked: rgba(76, 164, 231, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user