balibabu commited on
Commit
ccb514f
·
1 Parent(s): 9a73da2

Feat: Add dataset sidebar #3221 (#3683)

Browse files

### What problem does this PR solve?

Feat: Add dataset sidebar #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/src/constants/knowledge.ts CHANGED
@@ -4,6 +4,8 @@ export enum KnowledgeRouteKey {
4
  Configuration = 'configuration',
5
  }
6
 
 
 
7
  export enum RunningStatus {
8
  UNSTART = '0', // need to run
9
  RUNNING = '1', // need to cancel
 
4
  Configuration = 'configuration',
5
  }
6
 
7
+ export const DatasetBaseKey = 'dataset';
8
+
9
  export enum RunningStatus {
10
  UNSTART = '0', // need to run
11
  RUNNING = '1', // need to cancel
web/src/layouts/next-header.tsx ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
2
+ import { Button } from '@/components/ui/button';
3
+ import { Container } from '@/components/ui/container';
4
+ import { Segmented, SegmentedValue } from '@/components/ui/segmented ';
5
+ import { useTranslate } from '@/hooks/common-hooks';
6
+ import { useNavigateWithFromState } from '@/hooks/route-hook';
7
+ import {
8
+ ChevronDown,
9
+ Cpu,
10
+ Github,
11
+ Library,
12
+ MessageSquareText,
13
+ Search,
14
+ Star,
15
+ Zap,
16
+ } from 'lucide-react';
17
+ import { useCallback, useMemo, useState } from 'react';
18
+ import { useLocation } from 'umi';
19
+
20
+ export function Header() {
21
+ const { t } = useTranslate('header');
22
+ const { pathname } = useLocation();
23
+ const navigate = useNavigateWithFromState();
24
+ const [currentPath, setCurrentPath] = useState('/home');
25
+
26
+ const tagsData = useMemo(
27
+ () => [
28
+ { path: '/home', name: t('knowledgeBase'), icon: Library },
29
+ { path: '/chat', name: t('chat'), icon: MessageSquareText },
30
+ { path: '/search', name: t('search'), icon: Search },
31
+ { path: '/flow', name: t('flow'), icon: Cpu },
32
+ // { path: '/file', name: t('fileManager'), icon: FileIcon },
33
+ ],
34
+ [t],
35
+ );
36
+
37
+ const options = useMemo(() => {
38
+ return tagsData.map((tag) => {
39
+ const HeaderIcon = tag.icon;
40
+
41
+ return {
42
+ label: (
43
+ <div className="flex items-center gap-1">
44
+ <HeaderIcon className="size-5"></HeaderIcon>
45
+ <span>{tag.name}</span>
46
+ </div>
47
+ ),
48
+ value: tag.path,
49
+ };
50
+ });
51
+ }, [tagsData]);
52
+
53
+ // const currentPath = useMemo(() => {
54
+ // return tagsData.find((x) => pathname.startsWith(x.path))?.name || 'home';
55
+ // }, [pathname, tagsData]);
56
+
57
+ const handleChange = (path: SegmentedValue) => {
58
+ // navigate(path as string);
59
+ setCurrentPath(path as string);
60
+ };
61
+
62
+ const handleLogoClick = useCallback(() => {
63
+ navigate('/');
64
+ }, [navigate]);
65
+
66
+ return (
67
+ <section className="py-6 px-10 flex justify-between items-center border-b">
68
+ <div className="flex items-center gap-4">
69
+ <img
70
+ src={'/logo.svg'}
71
+ alt="logo"
72
+ className="w-[100] h-[100] mr-[12]"
73
+ onClick={handleLogoClick}
74
+ />
75
+ <Button variant="secondary">
76
+ <Github />
77
+ 21.5k stars
78
+ <Star />
79
+ </Button>
80
+ </div>
81
+ <div>
82
+ <Segmented
83
+ options={options}
84
+ value={currentPath}
85
+ onChange={handleChange}
86
+ className="bg-colors-background-inverse-standard text-backgroundInverseStandard-foreground"
87
+ ></Segmented>
88
+ </div>
89
+ <div className="flex items-center gap-4">
90
+ <Container>
91
+ V 0.13.0
92
+ <Button variant="secondary" className="size-8">
93
+ <ChevronDown />
94
+ </Button>
95
+ </Container>
96
+ <Container className="px-3 py-2">
97
+ <Avatar className="w-[30px] h-[30px]">
98
+ <AvatarImage src="https://github.com/shadcn.png" />
99
+ <AvatarFallback>CN</AvatarFallback>
100
+ </Avatar>
101
102
+ <Button
103
+ variant="destructive"
104
+ className="py-[2px] px-[8px] h-[23px] rounded-[4px]"
105
+ >
106
+ <Zap />
107
+ Pro
108
+ </Button>
109
+ </Container>
110
+ </div>
111
+ </section>
112
+ );
113
+ }
web/src/layouts/next.tsx ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Outlet } from 'umi';
2
+ import { Header } from './next-header';
3
+
4
+ export default function NextLayout() {
5
+ return (
6
+ <section>
7
+ <Header></Header>
8
+ <Outlet />
9
+ </section>
10
+ );
11
+ }
web/src/pages/dataset/dataset/index.tsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export default function Dataset() {
2
+ return <div>Outset</div>;
3
+ }
web/src/pages/dataset/index.tsx ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Outlet } from 'umi';
2
+ import { SideBar } from './sidebar';
3
+
4
+ export default function DatasetWrapper() {
5
+ return (
6
+ <div className="text-foreground flex">
7
+ <SideBar></SideBar>
8
+ <div className="p-6">
9
+ <Outlet />
10
+ </div>
11
+ </div>
12
+ );
13
+ }
web/src/pages/dataset/settings/index.tsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export default function DatasetSettings() {
2
+ return <div>DatasetSettings</div>;
3
+ }
web/src/pages/dataset/sidebar/hooks.tsx ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { DatasetBaseKey, KnowledgeRouteKey } from '@/constants/knowledge';
2
+ import { useCallback } from 'react';
3
+ import { useNavigate } from 'umi';
4
+
5
+ export const useHandleMenuClick = () => {
6
+ const navigate = useNavigate();
7
+
8
+ const handleMenuClick = useCallback(
9
+ (key: KnowledgeRouteKey) => () => {
10
+ navigate(`/${DatasetBaseKey}/${key}`);
11
+ },
12
+ [navigate],
13
+ );
14
+
15
+ return { handleMenuClick };
16
+ };
web/src/pages/dataset/sidebar/index.tsx ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Button } from '@/components/ui/button';
2
+ import { KnowledgeRouteKey } from '@/constants/knowledge';
3
+ import { useSecondPathName } from '@/hooks/route-hook';
4
+ import { cn } from '@/lib/utils';
5
+ import { Banknote, LayoutGrid, User } from 'lucide-react';
6
+ import { useHandleMenuClick } from './hooks';
7
+
8
+ const items = [
9
+ { icon: User, label: 'Dataset', key: KnowledgeRouteKey.Dataset },
10
+ {
11
+ icon: LayoutGrid,
12
+ label: 'Retrieval testing',
13
+ key: KnowledgeRouteKey.Testing,
14
+ },
15
+ { icon: Banknote, label: 'Settings', key: KnowledgeRouteKey.Configuration },
16
+ ];
17
+
18
+ const dataset = {
19
+ id: 1,
20
+ title: 'Legal knowledge base',
21
+ files: '1,242 files',
22
+ size: '152 MB',
23
+ created: '12.02.2024',
24
+ image: 'https://github.com/shadcn.png',
25
+ };
26
+
27
+ export function SideBar() {
28
+ const pathName = useSecondPathName();
29
+ const { handleMenuClick } = useHandleMenuClick();
30
+
31
+ return (
32
+ <aside className="w-[303px]">
33
+ <div className="p-6 space-y-2 border-b">
34
+ <div
35
+ className="w-[70px] h-[70px] rounded-xl bg-cover"
36
+ style={{ backgroundImage: `url(${dataset.image})` }}
37
+ />
38
+
39
+ <h3 className="text-lg font-semibold mb-2">{dataset.title}</h3>
40
+ <div className="text-sm opacity-80">
41
+ {dataset.files} | {dataset.size}
42
+ </div>
43
+ <div className="text-sm opacity-80">Created {dataset.created}</div>
44
+ </div>
45
+ <div className="mt-4">
46
+ {items.map((item, itemIdx) => {
47
+ const active = pathName === item.key;
48
+ return (
49
+ <Button
50
+ key={itemIdx}
51
+ variant={active ? 'secondary' : 'ghost'}
52
+ className={cn('w-full justify-start gap-2.5 p-6 relative')}
53
+ onClick={handleMenuClick(item.key)}
54
+ >
55
+ <item.icon className="w-6 h-6" />
56
+ <span>{item.label}</span>
57
+ {active && (
58
+ <div className="absolute right-0 w-[5px] h-[66px] bg-primary rounded-l-xl shadow-[0_0_5.94px_#7561ff,0_0_11.88px_#7561ff,0_0_41.58px_#7561ff,0_0_83.16px_#7561ff,0_0_142.56px_#7561ff,0_0_249.48px_#7561ff]" />
59
+ )}
60
+ </Button>
61
+ );
62
+ })}
63
+ </div>
64
+ </aside>
65
+ );
66
+ }
web/src/pages/dataset/testing/index.tsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export default function RetrievalTesting() {
2
+ return <div>Retrieval testing</div>;
3
+ }
web/src/routes.ts CHANGED
@@ -134,7 +134,39 @@ const routes = [
134
  {
135
  path: '/datasets',
136
  layout: false,
137
- component: '@/pages/datasets',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  },
139
  {
140
  path: '/profile-setting',
 
134
  {
135
  path: '/datasets',
136
  layout: false,
137
+ component: '@/layouts/next',
138
+ routes: [
139
+ {
140
+ path: '/datasets',
141
+ component: '@/pages/datasets',
142
+ },
143
+ ],
144
+ },
145
+ {
146
+ path: '/dataset',
147
+ layout: false,
148
+ component: '@/layouts/next',
149
+ routes: [
150
+ { path: '/dataset', redirect: '/dataset/dataset' },
151
+ {
152
+ path: '/dataset',
153
+ component: '@/pages/dataset',
154
+ routes: [
155
+ {
156
+ path: '/dataset/dataset',
157
+ component: '@/pages/dataset/dataset',
158
+ },
159
+ {
160
+ path: '/dataset/configuration',
161
+ component: '@/pages/dataset/settings',
162
+ },
163
+ {
164
+ path: '/dataset/testing',
165
+ component: '@/pages/dataset/testing',
166
+ },
167
+ ],
168
+ },
169
+ ],
170
  },
171
  {
172
  path: '/profile-setting',