balibabu commited on
Commit
2d64850
·
1 Parent(s): 07ea629

Feat: Add ProfileSetting page #3221 (#3588)

Browse files

### What problem does this PR solve?

Feat: Add ProfileSetting page #3221
### Type of change


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

web/src/components/ui/button.tsx CHANGED
@@ -13,7 +13,7 @@ const buttonVariants = cva(
13
  destructive:
14
  'bg-destructive text-destructive-foreground hover:bg-destructive/90',
15
  outline:
16
- 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
17
  secondary:
18
  'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19
  ghost: 'hover:bg-accent hover:text-accent-foreground',
 
13
  destructive:
14
  'bg-destructive text-destructive-foreground hover:bg-destructive/90',
15
  outline:
16
+ 'border border-colors-outline-sentiment-primary bg-background hover:bg-accent hover:text-accent-foreground',
17
  secondary:
18
  'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19
  ghost: 'hover:bg-accent hover:text-accent-foreground',
web/src/constants/setting.ts CHANGED
@@ -10,14 +10,19 @@ export enum UserSettingRouteKey {
10
  Logout = 'logout',
11
  }
12
 
13
- export const UserSettingRouteMap = {
14
- [UserSettingRouteKey.Profile]: 'Profile',
15
- [UserSettingRouteKey.Password]: 'Password',
16
- [UserSettingRouteKey.Model]: 'Model Providers',
17
- [UserSettingRouteKey.System]: 'System Version',
18
- [UserSettingRouteKey.Team]: 'Team',
19
- [UserSettingRouteKey.Logout]: 'Log out',
20
- };
 
 
 
 
 
21
 
22
  // Please lowercase the file name
23
  export const IconMap = {
 
10
  Logout = 'logout',
11
  }
12
 
13
+ export const ProfileSettingBaseKey = 'profile-setting';
14
+
15
+ export enum ProfileSettingRouteKey {
16
+ Profile = 'profile',
17
+ Plan = 'plan',
18
+ Model = 'model',
19
+ System = 'system',
20
+ Api = 'api',
21
+ Team = 'team',
22
+ Prompt = 'prompt',
23
+ Chunk = 'chunk',
24
+ Logout = 'logout',
25
+ }
26
 
27
  // Please lowercase the file name
28
  export const IconMap = {
web/src/pages/home/applications.tsx CHANGED
@@ -1,6 +1,8 @@
1
  import { Button } from '@/components/ui/button';
2
  import { Card, CardContent } from '@/components/ui/card';
 
3
  import { ChevronRight, Cpu, MessageSquare, Search } from 'lucide-react';
 
4
 
5
  const applications = [
6
  {
@@ -34,24 +36,42 @@ const applications = [
34
  ];
35
 
36
  export function Applications() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  return (
38
  <section className="mt-12">
39
  <div className="flex justify-between items-center mb-6">
40
  <h2 className="text-2xl font-bold">Applications</h2>
41
- <div className="flex bg-colors-background-inverse-standard rounded-lg p-1">
42
- <Button variant="default" size="sm">
43
- All
44
- </Button>
45
- <Button variant="ghost" size="sm">
46
- Chat
47
- </Button>
48
- <Button variant="ghost" size="sm">
49
- Search
50
- </Button>
51
- <Button variant="ghost" size="sm">
52
- Agents
53
- </Button>
54
- </div>
55
  </div>
56
  <div className="grid grid-cols-4 gap-6">
57
  {[...Array(12)].map((_, i) => {
 
1
  import { Button } from '@/components/ui/button';
2
  import { Card, CardContent } from '@/components/ui/card';
3
+ import { Segmented, SegmentedValue } from '@/components/ui/segmented ';
4
  import { ChevronRight, Cpu, MessageSquare, Search } from 'lucide-react';
5
+ import { useMemo, useState } from 'react';
6
 
7
  const applications = [
8
  {
 
36
  ];
37
 
38
  export function Applications() {
39
+ const [val, setVal] = useState('all');
40
+ const options = useMemo(() => {
41
+ return [
42
+ {
43
+ label: 'All',
44
+ value: 'all',
45
+ },
46
+ {
47
+ label: 'Chat',
48
+ value: 'chat',
49
+ },
50
+ {
51
+ label: 'Search',
52
+ value: 'search',
53
+ },
54
+ {
55
+ label: 'Agent',
56
+ value: 'agent',
57
+ },
58
+ ];
59
+ }, []);
60
+
61
+ const handleChange = (path: SegmentedValue) => {
62
+ setVal(path as string);
63
+ };
64
+
65
  return (
66
  <section className="mt-12">
67
  <div className="flex justify-between items-center mb-6">
68
  <h2 className="text-2xl font-bold">Applications</h2>
69
+ <Segmented
70
+ options={options}
71
+ value={val}
72
+ onChange={handleChange}
73
+ className="bg-colors-background-inverse-standard"
74
+ ></Segmented>
 
 
 
 
 
 
 
 
75
  </div>
76
  <div className="grid grid-cols-4 gap-6">
77
  {[...Array(12)].map((_, i) => {
web/src/pages/home/datasets.tsx CHANGED
@@ -9,7 +9,7 @@ const datasets = [
9
  files: '1,242 files',
10
  size: '152 MB',
11
  created: '12.02.2024',
12
- image: '/image-3.png',
13
  },
14
  {
15
  id: 2,
@@ -17,7 +17,7 @@ const datasets = [
17
  files: '1,242 files',
18
  size: '152 MB',
19
  created: '12.02.2024',
20
- image: '/image.png',
21
  },
22
  {
23
  id: 3,
@@ -25,7 +25,7 @@ const datasets = [
25
  files: '1,242 files',
26
  size: '152 MB',
27
  created: '12.02.2024',
28
- image: '/rectangle-86.png',
29
  },
30
  {
31
  id: 4,
@@ -33,7 +33,7 @@ const datasets = [
33
  files: '1,242 files',
34
  size: '152 MB',
35
  created: '12.02.2024',
36
- image: '/image-2.png',
37
  },
38
  ];
39
 
 
9
  files: '1,242 files',
10
  size: '152 MB',
11
  created: '12.02.2024',
12
+ image: 'https://github.com/shadcn.png',
13
  },
14
  {
15
  id: 2,
 
17
  files: '1,242 files',
18
  size: '152 MB',
19
  created: '12.02.2024',
20
+ image: 'https://github.com/shadcn.png',
21
  },
22
  {
23
  id: 3,
 
25
  files: '1,242 files',
26
  size: '152 MB',
27
  created: '12.02.2024',
28
+ image: 'https://github.com/shadcn.png',
29
  },
30
  {
31
  id: 4,
 
33
  files: '1,242 files',
34
  size: '152 MB',
35
  created: '12.02.2024',
36
+ image: 'https://github.com/shadcn.png',
37
  },
38
  ];
39
 
web/src/pages/home/header.tsx CHANGED
@@ -83,7 +83,7 @@ export function HomeHeader() {
83
  options={options}
84
  value={currentPath}
85
  onChange={handleChange}
86
- className="bg-backgroundInverseStandard text-backgroundInverseStandard-foreground"
87
  ></Segmented>
88
  </div>
89
  <div className="flex items-center gap-4">
 
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">
web/src/pages/profile-setting/hooks.tsx ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ProfileSettingRouteKey } from '@/constants/setting';
2
+ import { useSecondPathName } from '@/hooks/route-hook';
3
+
4
+ export const useGetPageTitle = (): string => {
5
+ const pathName = useSecondPathName();
6
+
7
+ const LabelMap = {
8
+ [ProfileSettingRouteKey.Profile]: 'User profile',
9
+ [ProfileSettingRouteKey.Plan]: 'Plan & balance',
10
+ [ProfileSettingRouteKey.Model]: 'Model management',
11
+ [ProfileSettingRouteKey.System]: 'System',
12
+ [ProfileSettingRouteKey.Api]: 'Api',
13
+ [ProfileSettingRouteKey.Team]: 'Team management',
14
+ [ProfileSettingRouteKey.Prompt]: 'Prompt management',
15
+ [ProfileSettingRouteKey.Chunk]: 'Chunk method',
16
+ [ProfileSettingRouteKey.Logout]: 'Logout',
17
+ };
18
+
19
+ return LabelMap[pathName as ProfileSettingRouteKey];
20
+ };
web/src/pages/profile-setting/index.tsx ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Button } from '@/components/ui/button';
2
+ import { ArrowLeft } from 'lucide-react';
3
+ import { Outlet } from 'umi';
4
+ import { useGetPageTitle } from './hooks';
5
+ import { SideBar } from './sidebar';
6
+
7
+ export default function ProfileSetting() {
8
+ const title = useGetPageTitle();
9
+ return (
10
+ <div className="flex flex-col w-full h-screen bg-background text-foreground">
11
+ <header className="flex items-center border-b">
12
+ <div className="flex items-center border-r p-1.5">
13
+ <Button variant="ghost" size="icon">
14
+ <ArrowLeft className="w-5 h-5" />
15
+ </Button>
16
+ </div>
17
+ <div className="p-4">
18
+ <h1 className="text-2xl font-semibold tracking-tight">
19
+ Profile & settings
20
+ </h1>
21
+ </div>
22
+ </header>
23
+
24
+ <div className="flex flex-1 bg-muted/50">
25
+ <SideBar></SideBar>
26
+
27
+ <main className="flex-1 p-10">
28
+ <h1 className="text-3xl font-bold mb-6"> {title}</h1>
29
+ <Outlet></Outlet>
30
+ </main>
31
+ </div>
32
+ </div>
33
+ );
34
+ }
web/src/pages/profile-setting/plan/index.tsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export default function Plan() {
2
+ return <div>plan</div>;
3
+ }
web/src/pages/profile-setting/profile/index.tsx ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
2
+ import { Button } from '@/components/ui/button';
3
+ import { Input } from '@/components/ui/input';
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from '@/components/ui/select';
11
+
12
+ export default function Profile() {
13
+ return (
14
+ <section>
15
+ <Avatar className="w-[120px] h-[120px] mb-6">
16
+ <AvatarImage
17
+ src={
18
+ 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg'
19
+ }
20
+ alt="Profile"
21
+ />
22
+ <AvatarFallback>YW</AvatarFallback>
23
+ </Avatar>
24
+
25
+ <div className="space-y-6 max-w-[600px]">
26
+ <div className="space-y-2">
27
+ <label className="text-sm text-muted-foreground">User name</label>
28
+ <Input
29
+ defaultValue="yifanwu92"
30
+ className="bg-colors-background-inverse-weak"
31
+ />
32
+ </div>
33
+
34
+ <div className="space-y-2">
35
+ <label className="text-sm text-muted-foreground">Email</label>
36
+ <Input
37
+ defaultValue="[email protected]"
38
+ className="bg-colors-background-inverse-weak"
39
+ />
40
+ </div>
41
+
42
+ <div className="space-y-2">
43
+ <label className="text-sm text-muted-foreground">Language</label>
44
+ <Select defaultValue="english">
45
+ <SelectTrigger className="bg-colors-background-inverse-weak">
46
+ <SelectValue />
47
+ </SelectTrigger>
48
+ <SelectContent>
49
+ <SelectItem value="english">English</SelectItem>
50
+ </SelectContent>
51
+ </Select>
52
+ </div>
53
+
54
+ <div className="space-y-2">
55
+ <label className="text-sm text-muted-foreground">Timezone</label>
56
+ <Select defaultValue="utc9">
57
+ <SelectTrigger className="bg-colors-background-inverse-weak">
58
+ <SelectValue />
59
+ </SelectTrigger>
60
+ <SelectContent>
61
+ <SelectItem value="utc9">UTC+9 Asia/Shanghai</SelectItem>
62
+ </SelectContent>
63
+ </Select>
64
+ </div>
65
+
66
+ <Button variant="outline" className="mt-4">
67
+ Change password
68
+ </Button>
69
+ </div>
70
+ </section>
71
+ );
72
+ }
web/src/pages/profile-setting/sidebar/hooks.tsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ ProfileSettingBaseKey,
3
+ ProfileSettingRouteKey,
4
+ } from '@/constants/setting';
5
+ import { useLogout } from '@/hooks/login-hooks';
6
+ import { useCallback } from 'react';
7
+ import { useNavigate } from 'umi';
8
+
9
+ export const useHandleMenuClick = () => {
10
+ const navigate = useNavigate();
11
+ const { logout } = useLogout();
12
+
13
+ const handleMenuClick = useCallback(
14
+ (key: ProfileSettingRouteKey) => () => {
15
+ if (key === ProfileSettingRouteKey.Logout) {
16
+ logout();
17
+ } else {
18
+ navigate(`/${ProfileSettingBaseKey}/${key}`);
19
+ }
20
+ },
21
+ [logout, navigate],
22
+ );
23
+
24
+ return { handleMenuClick };
25
+ };
web/src/pages/profile-setting/sidebar/index.tsx ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Button } from '@/components/ui/button';
2
+ import { Label } from '@/components/ui/label';
3
+ import { Switch } from '@/components/ui/switch';
4
+ import { ProfileSettingRouteKey } from '@/constants/setting';
5
+ import { useSecondPathName } from '@/hooks/route-hook';
6
+ import { cn } from '@/lib/utils';
7
+ import {
8
+ AlignEndVertical,
9
+ Banknote,
10
+ Box,
11
+ FileCog,
12
+ LayoutGrid,
13
+ LogOut,
14
+ User,
15
+ } from 'lucide-react';
16
+ import { useHandleMenuClick } from './hooks';
17
+
18
+ const menuItems = [
19
+ {
20
+ section: 'Account & collaboration',
21
+ items: [
22
+ { icon: User, label: 'Profile', key: ProfileSettingRouteKey.Profile },
23
+ { icon: LayoutGrid, label: 'Team', key: ProfileSettingRouteKey.Team },
24
+ { icon: Banknote, label: 'Plan', key: ProfileSettingRouteKey.Plan },
25
+ ],
26
+ },
27
+ {
28
+ section: 'System configurations',
29
+ items: [
30
+ {
31
+ icon: Box,
32
+ label: 'Model management',
33
+ key: ProfileSettingRouteKey.Model,
34
+ },
35
+ {
36
+ icon: FileCog,
37
+ label: 'Prompt management',
38
+ key: ProfileSettingRouteKey.Prompt,
39
+ },
40
+ {
41
+ icon: AlignEndVertical,
42
+ label: 'Chunking method',
43
+ key: ProfileSettingRouteKey.Chunk,
44
+ },
45
+ ],
46
+ },
47
+ ];
48
+
49
+ export function SideBar() {
50
+ const pathName = useSecondPathName();
51
+ const { handleMenuClick } = useHandleMenuClick();
52
+
53
+ return (
54
+ <aside className="w-[303px] bg-background border-r">
55
+ {menuItems.map((section, idx) => (
56
+ <div key={idx}>
57
+ <h2 className="p-6 text-sm font-semibold">{section.section}</h2>
58
+ {section.items.map((item, itemIdx) => {
59
+ const active = pathName === item.key;
60
+ return (
61
+ <Button
62
+ key={itemIdx}
63
+ variant={active ? 'secondary' : 'ghost'}
64
+ className={cn('w-full justify-start gap-2.5 p-6 relative')}
65
+ onClick={handleMenuClick(item.key)}
66
+ >
67
+ <item.icon className="w-6 h-6" />
68
+ <span>{item.label}</span>
69
+ {active && (
70
+ <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]" />
71
+ )}
72
+ </Button>
73
+ );
74
+ })}
75
+ </div>
76
+ ))}
77
+
78
+ <div className="p-6 mt-auto border-t">
79
+ <div className="flex items-center gap-2 mb-6">
80
+ <Switch id="dark-mode" />
81
+ <Label htmlFor="dark-mode" className="text-sm">
82
+ Dark
83
+ </Label>
84
+ </div>
85
+ <Button variant="outline" className="w-full gap-3">
86
+ <LogOut className="w-6 h-6" />
87
+ Logout
88
+ </Button>
89
+ </div>
90
+ </aside>
91
+ );
92
+ }
web/src/pages/profile-setting/team/index.tsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export default function Team() {
2
+ return <div>team</div>;
3
+ }
web/src/routes.ts CHANGED
@@ -131,6 +131,26 @@ const routes = [
131
  layout: false,
132
  component: '@/pages/home',
133
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  ];
135
 
136
  export default routes;
 
131
  layout: false,
132
  component: '@/pages/home',
133
  },
134
+ {
135
+ path: '/profile-setting',
136
+ layout: false,
137
+ component: '@/pages/profile-setting',
138
+ routes: [
139
+ { path: '/profile-setting', redirect: '/profile-setting/profile' },
140
+ {
141
+ path: '/profile-setting/profile',
142
+ component: '@/pages/profile-setting/profile',
143
+ },
144
+ {
145
+ path: '/profile-setting/team',
146
+ component: '@/pages/profile-setting/team',
147
+ },
148
+ {
149
+ path: '/profile-setting/plan',
150
+ component: '@/pages/profile-setting/plan',
151
+ },
152
+ ],
153
+ },
154
  ];
155
 
156
  export default routes;
web/tailwind.config.js CHANGED
@@ -25,6 +25,10 @@ module.exports = {
25
  background: 'var(--background)',
26
  foreground: 'hsl(var(--foreground))',
27
  buttonBlueText: 'var(--button-blue-text)',
 
 
 
 
28
  primary: {
29
  DEFAULT: 'hsl(var(--primary))',
30
  foreground: 'hsl(var(--primary-foreground))',
 
25
  background: 'var(--background)',
26
  foreground: 'hsl(var(--foreground))',
27
  buttonBlueText: 'var(--button-blue-text)',
28
+
29
+ 'colors-outline-sentiment-primary':
30
+ 'var(--colors-outline-sentiment-primary)',
31
+
32
  primary: {
33
  DEFAULT: 'hsl(var(--primary))',
34
  foreground: 'hsl(var(--primary-foreground))',
web/tailwind.css CHANGED
@@ -39,6 +39,10 @@
39
  --background-inverse-standard-foreground: rgb(92, 81, 81);
40
 
41
  --button-blue-text: rgb(22, 119, 255);
 
 
 
 
42
  }
43
 
44
  .dark {
@@ -108,6 +112,10 @@
108
  --colors-background-neutral-standard: rgba(11, 10, 18, 1);
109
  --colors-background-neutral-strong: rgba(29, 26, 44, 1);
110
  --colors-background-neutral-weak: rgba(17, 16, 23, 1);
 
 
 
 
111
  }
112
  }
113
 
 
39
  --background-inverse-standard-foreground: rgb(92, 81, 81);
40
 
41
  --button-blue-text: rgb(22, 119, 255);
42
+
43
+ --colors-outline-sentiment-primary: rgba(127, 105, 255, 1);
44
+
45
+ --colors-text-core-standard: rgba(127, 105, 255, 1);
46
  }
47
 
48
  .dark {
 
112
  --colors-background-neutral-standard: rgba(11, 10, 18, 1);
113
  --colors-background-neutral-strong: rgba(29, 26, 44, 1);
114
  --colors-background-neutral-weak: rgba(17, 16, 23, 1);
115
+
116
+ --colors-outline-sentiment-primary: rgba(146, 118, 255, 1);
117
+
118
+ --colors-text-core-standard: rgba(137, 126, 255, 1);
119
  }
120
  }
121