Spaces:
Sleeping
Sleeping
MingruiZhang
commited on
Commit
•
cb6fbf2
1
Parent(s):
96ac62a
feat: project card more info (#28)
Browse files<img width="1904" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/5669963/8a2ed136-fab5-4a44-9fb9-0ffad32cbc15">
- app/project/layout.tsx +8 -0
- components/project-sidebar/ProjectCard.tsx +32 -11
- components/ui/Chip.tsx +6 -8
- lib/fetch/index.ts +3 -4
- lib/hooks/useVisionAgent.tsx +14 -5
app/project/layout.tsx
CHANGED
@@ -1,12 +1,20 @@
|
|
1 |
import ProjectListSideBar from '@/components/project-sidebar/ProjectListSideBar';
|
2 |
import { Suspense } from 'react';
|
3 |
import Loading from '@/components/ui/Loading';
|
|
|
|
|
4 |
|
5 |
interface ChatLayoutProps {
|
6 |
children: React.ReactNode;
|
7 |
}
|
8 |
|
9 |
export default async function Layout({ children }: ChatLayoutProps) {
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
return (
|
11 |
<div className="relative flex h-[calc(100vh_-_theme(spacing.16))] overflow-hidden">
|
12 |
<div
|
|
|
1 |
import ProjectListSideBar from '@/components/project-sidebar/ProjectListSideBar';
|
2 |
import { Suspense } from 'react';
|
3 |
import Loading from '@/components/ui/Loading';
|
4 |
+
import { authEmail } from '@/auth';
|
5 |
+
import { redirect } from 'next/navigation';
|
6 |
|
7 |
interface ChatLayoutProps {
|
8 |
children: React.ReactNode;
|
9 |
}
|
10 |
|
11 |
export default async function Layout({ children }: ChatLayoutProps) {
|
12 |
+
const { isAdmin } = await authEmail();
|
13 |
+
|
14 |
+
if (!isAdmin) {
|
15 |
+
redirect('/');
|
16 |
+
}
|
17 |
+
|
18 |
return (
|
19 |
<div className="relative flex h-[calc(100vh_-_theme(spacing.16))] overflow-hidden">
|
20 |
<div
|
components/project-sidebar/ProjectCard.tsx
CHANGED
@@ -11,14 +11,25 @@ export interface ProjectCardProps {
|
|
11 |
projectInfo: ProjectBaseInfo;
|
12 |
}
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
const ProjectCard: React.FC<ProjectCardProps> = ({ projectInfo }) => {
|
15 |
-
const {
|
16 |
-
|
17 |
-
name,
|
18 |
-
created_at,
|
19 |
-
label_type,
|
20 |
-
organization: { name: orgName },
|
21 |
-
} = projectInfo;
|
22 |
|
23 |
const { projectId: projectIdFromParam } = useParams();
|
24 |
|
@@ -31,10 +42,20 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ projectInfo }) => {
|
|
31 |
)}
|
32 |
href={`/project/${id}`}
|
33 |
>
|
34 |
-
<div className="overflow-hidden">
|
35 |
-
<
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
</div>
|
39 |
</Link>
|
40 |
);
|
|
|
11 |
projectInfo: ProjectBaseInfo;
|
12 |
}
|
13 |
|
14 |
+
export enum LabelType {
|
15 |
+
BoundingBox = 'bounding_box',
|
16 |
+
Segmentation = 'segmentation',
|
17 |
+
Classification = 'classification',
|
18 |
+
AnomalyDetection = 'anomaly_detection',
|
19 |
+
SegmentationInstantLearning = 'segmentation_instant_learning',
|
20 |
+
}
|
21 |
+
|
22 |
+
const LabelTypeDisplayText: { [key: string]: string } = {
|
23 |
+
[LabelType.BoundingBox]: 'detection',
|
24 |
+
[LabelType.Segmentation]: 'segmentation',
|
25 |
+
[LabelType.Classification]: 'classification',
|
26 |
+
[LabelType.AnomalyDetection]: 'anomaly',
|
27 |
+
[LabelType.SegmentationInstantLearning]: 'vp',
|
28 |
+
};
|
29 |
+
|
30 |
const ProjectCard: React.FC<ProjectCardProps> = ({ projectInfo }) => {
|
31 |
+
const { id, name, created_at, label_type, orgName, subscription } =
|
32 |
+
projectInfo;
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
const { projectId: projectIdFromParam } = useParams();
|
35 |
|
|
|
42 |
)}
|
43 |
href={`/project/${id}`}
|
44 |
>
|
45 |
+
<div className="overflow-hidden w-full">
|
46 |
+
<div className="flex items-center justify-between w-full">
|
47 |
+
<p className="text-xs text-gray-500 truncate mr-2 truncate">
|
48 |
+
{orgName}
|
49 |
+
</p>
|
50 |
+
<p className="text-xs text-gray-500 italic">{subscription}</p>
|
51 |
+
</div>
|
52 |
+
<div className="flex mb-1 items-center">
|
53 |
+
<p className="text-sm font-medium text-gray mr-2 truncate">{name}</p>
|
54 |
+
<Chip value={LabelTypeDisplayText[label_type]} />
|
55 |
+
</div>
|
56 |
+
<div className="flex items-center truncate">
|
57 |
+
<p className="text-xs text-gray-500">{formattedDate}</p>
|
58 |
+
</div>
|
59 |
</div>
|
60 |
</Link>
|
61 |
);
|
components/ui/Chip.tsx
CHANGED
@@ -3,20 +3,18 @@ import { cn } from '@/lib/utils';
|
|
3 |
export interface ChipProps {
|
4 |
label?: string;
|
5 |
value: string;
|
6 |
-
color?: 'gray' | 'blue';
|
7 |
className?: string;
|
8 |
}
|
9 |
|
10 |
-
const Chip: React.FC<ChipProps> = ({
|
11 |
-
label,
|
12 |
-
value,
|
13 |
-
color = 'gray',
|
14 |
-
className,
|
15 |
-
}) => {
|
16 |
return (
|
17 |
<div
|
18 |
className={cn(
|
19 |
-
`inline-flex items-center px-
|
|
|
|
|
|
|
20 |
className,
|
21 |
)}
|
22 |
>
|
|
|
3 |
export interface ChipProps {
|
4 |
label?: string;
|
5 |
value: string;
|
6 |
+
color?: 'gray' | 'blue' | 'yellow' | 'purple';
|
7 |
className?: string;
|
8 |
}
|
9 |
|
10 |
+
const Chip: React.FC<ChipProps> = ({ label, value, className, color }) => {
|
|
|
|
|
|
|
|
|
|
|
11 |
return (
|
12 |
<div
|
13 |
className={cn(
|
14 |
+
`inline-flex items-center px-1.5 rounded-full text-xs bg-gray-100 text-gray-500 mr-2`,
|
15 |
+
color === 'blue' && 'bg-blue-100 text-blue-500',
|
16 |
+
color === 'yellow' && 'bg-yellow-100 text-yellow-500',
|
17 |
+
color === 'purple' && 'bg-purple-100 text-purple-500',
|
18 |
className,
|
19 |
)}
|
20 |
>
|
lib/fetch/index.ts
CHANGED
@@ -83,10 +83,9 @@ export type ProjectBaseInfo = {
|
|
83 |
name: string;
|
84 |
created_at: Date;
|
85 |
label_type: string;
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
};
|
90 |
};
|
91 |
/**
|
92 |
* Fetch recent projects from all organizations from past 30 days, excluding
|
|
|
83 |
name: string;
|
84 |
created_at: Date;
|
85 |
label_type: string;
|
86 |
+
orgName: string;
|
87 |
+
orgId: number;
|
88 |
+
subscription: string;
|
|
|
89 |
};
|
90 |
/**
|
91 |
* Fetch recent projects from all organizations from past 30 days, excluding
|
lib/hooks/useVisionAgent.tsx
CHANGED
@@ -82,13 +82,22 @@ const useVisionAgent = (chat: ChatEntity) => {
|
|
82 |
...message,
|
83 |
content: logs + CLEANED_SEPARATOR + newContent,
|
84 |
};
|
85 |
-
/**
|
86 |
-
* A workaround to fix the issue of the message not being appended to the chat
|
87 |
-
* https://github.com/vercel/ai/issues/550#issuecomment-1712693371
|
88 |
-
*/
|
89 |
setMessages([
|
90 |
...messages,
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
newMessage,
|
93 |
]);
|
94 |
if (id) {
|
|
|
82 |
...message,
|
83 |
content: logs + CLEANED_SEPARATOR + newContent,
|
84 |
};
|
|
|
|
|
|
|
|
|
85 |
setMessages([
|
86 |
...messages,
|
87 |
+
/**
|
88 |
+
* A workaround to fix the issue of the messages been stale state when appending a new message
|
89 |
+
* https://github.com/vercel/ai/issues/550#issuecomment-1712693371
|
90 |
+
*/
|
91 |
+
...(input
|
92 |
+
? [
|
93 |
+
{
|
94 |
+
id: nanoid(),
|
95 |
+
role: 'user',
|
96 |
+
content: input,
|
97 |
+
createdAt: new Date(),
|
98 |
+
} satisfies Message,
|
99 |
+
]
|
100 |
+
: []),
|
101 |
newMessage,
|
102 |
]);
|
103 |
if (id) {
|