Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): style polishing for the activities page #1960

Merged
merged 4 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 146 additions & 127 deletions ee/tabby-ui/app/(dashboard)/activities/components/activity.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import React from 'react'
import { capitalize } from 'lodash-es'
import moment from 'moment'
import { useTheme } from 'next-themes'
import { DateRange } from 'react-day-picker'
Expand Down Expand Up @@ -137,136 +138,155 @@ export default function Activity() {
}

return (
<LoadingWrapper loading={fetching}>
<>
<div className="flex w-full flex-col">
<div className="flex flex-col sm:gap-4 sm:py-4 sm:pl-14">
<main className="grid flex-1 items-start gap-4 p-4 sm:px-6 sm:py-0">
<div className="ml-auto flex items-center gap-2">
<Select
defaultValue={KEY_SELECT_ALL}
onValueChange={setSelectedMember}
>
<SelectTrigger className="w-auto py-0">
<div className="flex h-6 items-center">
<div className="w-[190px] overflow-hidden text-ellipsis text-left">
<SelectValue />
</div>
</div>
</SelectTrigger>
<SelectContent align="end">
<SelectGroup>
<SelectItem value={KEY_SELECT_ALL}>All members</SelectItem>
{members.map(member => (
<SelectItem value={member.id} key={member.id}>
{member.email}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<div className="flex flex-col sm:gap-4 sm:py-4">
<main className="grid flex-1 items-start gap-4 py-4 sm:py-0">
<div className="flex flex-col gap-y-2 xl:flex-row xl:items-center xl:justify-between">
<p className="text-sm text-muted-foreground">{`View raw events generated by team members' activities while interacting with Tabby.`}</p>

<DateRangePicker
options={[
{ label: 'Last 24 hours', value: '-24h' },
{ label: 'Last 7 days', value: '-7d' },
{ label: 'Last 14 days', value: '-14d' }
]}
defaultValue={DEFAULT_DATE_RANGE}
onSelect={updateDateRange}
hasToday
hasYesterday
/>
</div>
{!fetching && (
<div className="flex flex-col items-center gap-2 md:flex-row xl:ml-auto">
<Select
defaultValue={KEY_SELECT_ALL}
onValueChange={setSelectedMember}
>
<SelectTrigger className="w-[calc(100vw-2rem)] py-0 md:w-auto">
<div className="flex h-6 items-center">
<div className="overflow-hidden text-ellipsis text-left md:w-[190px]">
<SelectValue />
</div>
</div>
</SelectTrigger>
<SelectContent align="end">
<SelectGroup>
<SelectItem value={KEY_SELECT_ALL}>
All members
</SelectItem>
{members.map(member => (
<SelectItem value={member.id} key={member.id}>
{member.email}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>

<Card x-chunk="dashboard-06-chunk-0" className="bg-transparent">
{(!data?.userEvents.edges ||
data?.userEvents.edges.length === 0) && (
<CardContent className="flex flex-col items-center py-40 text-sm">
<IconFileSearch className="mb-2 h-10 w-10" />
<p className="font-semibold">
No data available for the chosen dates
</p>
<p className="text-muted-foreground">
Please try a different date range
</p>
</CardContent>
<DateRangePicker
className="w-[calc(100vw-2rem)] md:w-[240px]"
options={[
{ label: 'Last 24 hours', value: '-24h' },
{ label: 'Last 7 days', value: '-7d' },
{ label: 'Last 14 days', value: '-14d' }
]}
defaultValue={DEFAULT_DATE_RANGE}
onSelect={updateDateRange}
hasToday
hasYesterday
/>
</div>
)}
</div>
<LoadingWrapper loading={fetching}>
<>
<Card x-chunk="dashboard-06-chunk-0" className="bg-transparent">
{(!data?.userEvents.edges ||
data?.userEvents.edges.length === 0) && (
<CardContent className="flex flex-col items-center py-40 text-sm">
<IconFileSearch className="mb-2 h-10 w-10" />
<p className="font-semibold">
No data available for the chosen dates
</p>
<p className="text-muted-foreground">
Please try a different date range
</p>
</CardContent>
)}

{data?.userEvents.edges && data?.userEvents.edges.length > 0 && (
<>
<CardContent className="w-[calc(100vw-4rem)] overflow-x-auto pb-0 md:w-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead className="md:w-[30%]">Event</TableHead>
<TableHead className="md:w-[40%]">People</TableHead>
<TableHead className="md:w-[30%]">Time</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{userEvents?.edges
.sort(
(a, b) =>
new Date(b.node.createdAt).getTime() -
new Date(a.node.createdAt).getTime()
)
.map(userEvent => (
<ActivityRow
key={userEvent.cursor}
activity={userEvent.node}
members={members}
/>
))}
</TableBody>
</Table>
</CardContent>
</>
)}
</Card>
{data?.userEvents.edges &&
data?.userEvents.edges.length > 0 && (
<>
<CardContent className="w-[calc(100vw-2rem)] overflow-x-auto px-0 pb-0 md:w-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead className="pl-4 md:w-[30%] md:pl-8">
Event
</TableHead>
<TableHead className="md:w-[40%]">
User
</TableHead>
<TableHead className="pl-4 md:w-[30%] md:pr-8">
Time
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{userEvents?.edges
.sort(
(a, b) =>
new Date(b.node.createdAt).getTime() -
new Date(a.node.createdAt).getTime()
)
.map(userEvent => (
<ActivityRow
key={userEvent.cursor}
activity={userEvent.node}
members={members}
/>
))}
</TableBody>
</Table>
</CardContent>
</>
)}
</Card>

{(data?.userEvents.pageInfo?.hasNextPage ||
data?.userEvents.pageInfo?.hasPreviousPage) && (
<div className="flex justify-end">
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
{' '}
Page {page}
</div>
<div className="flex items-center space-x-2">
<Button
variant="outline"
className="h-8 w-8 p-0"
disabled={!data?.userEvents.pageInfo?.hasNextPage}
onClick={e => {
setQueryVariables({
first: DEFAULT_PAGE_SIZE,
after: data?.userEvents.pageInfo?.endCursor
})
setPage(page - 1)
}}
>
<IconChevronLeft className="h-4 w-4" />
</Button>
<Button
variant="outline"
className="h-8 w-8 p-0"
disabled={!data?.userEvents.pageInfo?.hasPreviousPage}
onClick={e => {
setQueryVariables({
last: DEFAULT_PAGE_SIZE,
before: data?.userEvents.pageInfo?.startCursor
})
setPage(page + 1)
}}
>
<IconChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
)}
{(data?.userEvents.pageInfo?.hasNextPage ||
data?.userEvents.pageInfo?.hasPreviousPage) && (
<div className="flex justify-end">
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
{' '}
Page {page}
</div>
<div className="flex items-center space-x-2">
<Button
variant="outline"
className="h-8 w-8 p-0"
disabled={!data?.userEvents.pageInfo?.hasNextPage}
onClick={e => {
setQueryVariables({
first: DEFAULT_PAGE_SIZE,
after: data?.userEvents.pageInfo?.endCursor
})
setPage(page - 1)
}}
>
<IconChevronLeft className="h-4 w-4" />
</Button>
<Button
variant="outline"
className="h-8 w-8 p-0"
disabled={!data?.userEvents.pageInfo?.hasPreviousPage}
onClick={e => {
setQueryVariables({
last: DEFAULT_PAGE_SIZE,
before: data?.userEvents.pageInfo?.startCursor
})
setPage(page + 1)
}}
>
<IconChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
)}
</>
</LoadingWrapper>
</main>
</div>
</div>
</LoadingWrapper>
</>
)
}

Expand All @@ -278,7 +298,6 @@ function ActivityRow({
members: Member[]
}) {
const { theme } = useTheme()
// const [members] = useAllMembers()
const [isExpanded, setIsExpanded] = React.useState(false)

let payloadJson
Expand Down Expand Up @@ -321,19 +340,19 @@ function ActivityRow({
className="cursor-pointer text-sm"
onClick={() => setIsExpanded(!isExpanded)}
>
<TableCell className="py-3 font-medium">
<TableCell className="pl-4 font-medium md:pl-8">
<Tooltip>
<TooltipTrigger>{activity.kind}</TooltipTrigger>
<TooltipTrigger>{capitalize(activity.kind)}</TooltipTrigger>
<TooltipContent>
<p>{tooltip}</p>
</TooltipContent>
</Tooltip>
</TableCell>
<TableCell className="py-3">
<TableCell>
{members.find(user => user.id === activity.userId)?.email ||
activity.userId}
</TableCell>
<TableCell className="py-3">
<TableCell className="pl-4 md:pr-8">
{moment(activity.createdAt).isBefore(moment().subtract(1, 'days'))
? moment(activity.createdAt).format('YYYY-MM-DD HH:mm')
: moment(activity.createdAt).fromNow()}
Expand All @@ -342,7 +361,7 @@ function ActivityRow({

{isExpanded && (
<TableRow key={`${activity.id}-2`} className="w-full bg-muted/30">
<TableCell className="font-medium" colSpan={4}>
<TableCell className="px-8 font-medium" colSpan={4}>
<ReactJson
src={payloadJson}
name={false}
Expand Down
6 changes: 4 additions & 2 deletions ee/tabby-ui/components/date-range-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ export default function DateRangePicker({
onSelect,
defaultValue,
hasToday,
hasYesterday
hasYesterday,
className
}: {
options: { label: string; value: string }[]
onSelect?: (range: DateRange) => void
defaultValue?: string
hasToday?: boolean
hasYesterday?: boolean
className?: string
}) {
defaultValue = defaultValue || options[0].value
const defaultDate = parseDateValue(defaultValue)
Expand Down Expand Up @@ -146,7 +148,7 @@ export default function DateRangePicker({
onOpenChange={onDateFilterOpenChange}
>
<SelectTrigger
className="w-[240px]"
className={cn('w-[240px]', className)}
onClick={() => setShowDateFilter(!showDateFilter)}
>
<SelectValue placeholder="Date range" />
Expand Down
Loading