diff --git a/ee/tabby-ui/app/(dashboard)/activities/components/activity.tsx b/ee/tabby-ui/app/(dashboard)/activities/components/activity.tsx
new file mode 100644
index 000000000000..61345a6a3296
--- /dev/null
+++ b/ee/tabby-ui/app/(dashboard)/activities/components/activity.tsx
@@ -0,0 +1,358 @@
+'use client'
+
+import React from 'react'
+import moment from 'moment'
+import { useTheme } from 'next-themes'
+import { DateRange } from 'react-day-picker'
+import ReactJson from 'react-json-view'
+import { toast } from 'sonner'
+import { useQuery } from 'urql'
+
+import { DEFAULT_PAGE_SIZE } from '@/lib/constants'
+import { graphql } from '@/lib/gql/generates'
+import { EventKind, ListUserEventsQuery } from '@/lib/gql/generates/graphql'
+import { Member, useAllMembers } from '@/lib/hooks/use-all-members'
+import { QueryVariables } from '@/lib/tabby/gql'
+import { Button } from '@/components/ui/button'
+import { Card, CardContent } from '@/components/ui/card'
+import {
+ IconChevronLeft,
+ IconChevronRight,
+ IconFileSearch
+} from '@/components/ui/icons'
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectTrigger,
+ SelectValue
+} from '@/components/ui/select'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow
+} from '@/components/ui/table'
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger
+} from '@/components/ui/tooltip'
+import DateRangePicker from '@/components/date-range-picker'
+import LoadingWrapper from '@/components/loading-wrapper'
+
+const DEFAULT_DATE_RANGE = '-24h'
+const KEY_SELECT_ALL = 'all'
+
+export const listUserEvents = graphql(/* GraphQL */ `
+ query ListUserEvents(
+ $after: String
+ $before: String
+ $first: Int
+ $last: Int
+ $start: DateTimeUtc!
+ $end: DateTimeUtc!
+ $users: [ID!]
+ ) {
+ userEvents(
+ after: $after
+ before: $before
+ first: $first
+ last: $last
+ start: $start
+ end: $end
+ users: $users
+ ) {
+ edges {
+ node {
+ id
+ userId
+ createdAt
+ kind
+ payload
+ }
+ cursor
+ }
+ pageInfo {
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ endCursor
+ }
+ }
+ }
+`)
+
+export default function Activity() {
+ const defaultFromDate = moment().add(parseInt(DEFAULT_DATE_RANGE, 10), 'day')
+ const defaultToDate = moment()
+
+ const [members] = useAllMembers()
+ const [dateRange, setDateRange] = React.useState({
+ from: defaultFromDate.toDate(),
+ to: defaultToDate.toDate()
+ })
+ const [page, setPage] = React.useState(1)
+ const [userEvents, setUserEvents] =
+ React.useState()
+ const [selectedMember, setSelectedMember] = React.useState(KEY_SELECT_ALL)
+
+ const [queryVariables, setQueryVariables] = React.useState<
+ Omit, 'start' | 'end'>
+ >({
+ last: DEFAULT_PAGE_SIZE
+ })
+
+ const [{ data, error, fetching }] = useQuery({
+ query: listUserEvents,
+ variables: {
+ start: moment(dateRange.from!).utc().format(),
+ end: dateRange.to
+ ? moment(dateRange.to).utc().format()
+ : moment(dateRange.from!).utc().format(),
+ users: selectedMember === KEY_SELECT_ALL ? undefined : [selectedMember],
+ ...queryVariables
+ }
+ })
+
+ React.useEffect(() => {
+ if (data?.userEvents.edges.length) {
+ setUserEvents(data.userEvents)
+ }
+ }, [data])
+
+ React.useEffect(() => {
+ if (error?.message) {
+ toast.error(error.message)
+ }
+ }, [error])
+
+ const updateDateRange = (range: DateRange) => {
+ setDateRange(range)
+ setPage(1)
+ setQueryVariables({ last: DEFAULT_PAGE_SIZE })
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {(!data?.userEvents.edges ||
+ data?.userEvents.edges.length === 0) && (
+
+
+
+ No data available for the chosen dates
+
+
+ Please try a different date range
+
+
+ )}
+
+ {data?.userEvents.edges && data?.userEvents.edges.length > 0 && (
+ <>
+
+
+
+
+ Event
+ People
+ Time
+
+
+
+ {userEvents?.edges
+ .sort(
+ (a, b) =>
+ new Date(b.node.createdAt).getTime() -
+ new Date(a.node.createdAt).getTime()
+ )
+ .map(userEvent => (
+
+ ))}
+
+
+
+ >
+ )}
+
+
+ {(data?.userEvents.pageInfo?.hasNextPage ||
+ data?.userEvents.pageInfo?.hasPreviousPage) && (
+
+
+ {' '}
+ Page {page}
+
+
+
+
+
+
+ )}
+
+
+
+
+ )
+}
+
+function ActivityRow({
+ activity,
+ members
+}: {
+ activity: ListUserEventsQuery['userEvents']['edges'][0]['node']
+ members: Member[]
+}) {
+ const { theme } = useTheme()
+ // const [members] = useAllMembers()
+ const [isExpanded, setIsExpanded] = React.useState(false)
+
+ let payloadJson
+ try {
+ payloadJson = JSON.parse(activity.payload) as {
+ [key: string]: { language?: string }
+ }
+ } catch (error: any) {
+ if (error?.message) {
+ toast.error(error.message)
+ }
+ }
+
+ if (!payloadJson) return null
+
+ let tooltip = ''
+ switch (activity.kind) {
+ case EventKind.Completion: {
+ tooltip = 'Code completion supplied'
+ break
+ }
+
+ case EventKind.Dismiss: {
+ tooltip = 'Code completion viewed but not used'
+ break
+ }
+ case EventKind.Select: {
+ tooltip = 'Code completion accepted and inserted'
+ break
+ }
+ case EventKind.View: {
+ tooltip = 'Code completion shown in editor'
+ break
+ }
+ }
+ return (
+ <>
+ setIsExpanded(!isExpanded)}
+ >
+
+
+ {activity.kind}
+
+ {tooltip}
+
+
+
+
+ {members.find(user => user.id === activity.userId)?.email ||
+ activity.userId}
+
+
+ {moment(activity.createdAt).isBefore(moment().subtract(1, 'days'))
+ ? moment(activity.createdAt).format('YYYY-MM-DD HH:mm')
+ : moment(activity.createdAt).fromNow()}
+
+
+
+ {isExpanded && (
+
+
+
+
+
+ )}
+ >
+ )
+}
diff --git a/ee/tabby-ui/app/(dashboard)/activities/page.tsx b/ee/tabby-ui/app/(dashboard)/activities/page.tsx
new file mode 100644
index 000000000000..150f4fed124f
--- /dev/null
+++ b/ee/tabby-ui/app/(dashboard)/activities/page.tsx
@@ -0,0 +1,11 @@
+import { Metadata } from 'next'
+
+import Activity from './components/activity'
+
+export const metadata: Metadata = {
+ title: 'Activities'
+}
+
+export default function Page() {
+ return
+}
diff --git a/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx b/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx
index ecd158421dcb..7b3c5170aaef 100644
--- a/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx
+++ b/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx
@@ -68,6 +68,7 @@ export default function Sidebar({ children, className }: SidebarProps) {
Cluster
Jobs
Reports
+ Activities
({
- from: moment()
- .subtract(parseInt(DATE_OPTIONS.LAST14DAYS, 10), 'day')
- .toDate(),
+ from: moment().add(parseInt(DEFAULT_DATE_RANGE, 10), 'day').toDate(),
to: moment().toDate()
})
const [selectedMember, setSelectedMember] = useState(KEY_SELECT_ALL)
const [selectedLanguage, setSelectedLanguage] = useState([])
- const [showDateFilter, setShowDateFilter] = useState(false)
- const [selectDateFilter, setSelectDateFilter] = useState(
- DATE_OPTIONS.LAST14DAYS
- )
- const [showDateRangerPicker, setShowDateRangerPicker] = useState(false)
- const [calendarDateRange, setCalendarDateRange] = useState<
- DateRange | undefined
- >({
- from: moment()
- .subtract(parseInt(DATE_OPTIONS.LAST14DAYS, 10), 'day')
- .toDate(),
- to: moment().toDate()
- })
- const [showDateUntilNowPicker, setShowDateUntilNowPicker] = useState(false)
- const [dateUntilNow, setDateUntilNow] = useState(
- moment().toDate()
- )
// Query stats of selected date range
const [{ data: dailyStatsData, fetching: fetchingDailyState }] = useQuery({
@@ -236,58 +206,6 @@ export function Report() {
}))
}
- const onDateFilterChange = (value: DATE_OPTIONS) => {
- switch (value) {
- case DATE_OPTIONS.TODAY: {
- setDateRange({
- from: moment().startOf('day').toDate(),
- to: moment().toDate()
- })
- break
- }
- case DATE_OPTIONS.YESTERDAY: {
- setDateRange({
- from: moment().subtract(1, 'd').startOf('day').toDate(),
- to: moment().subtract(1, 'd').endOf('day').toDate()
- })
- break
- }
- default: {
- setDateRange({
- from: moment()
- .subtract(parseInt(value, 10), 'day')
- .startOf('day')
- .toDate(),
- to: moment().toDate()
- })
- }
- }
- setSelectDateFilter(value)
- }
-
- const onDateFilterOpenChange = (open: boolean) => {
- if (!open && !showDateRangerPicker && !showDateUntilNowPicker) {
- setShowDateFilter(false)
- }
- }
-
- const applyDateRange = () => {
- setShowDateFilter(false)
- setShowDateRangerPicker(false)
- setSelectDateFilter(DATE_OPTIONS.CUSTOM_RANGE)
- setDateRange(calendarDateRange!)
- }
-
- const applyDateUntilNow = () => {
- setShowDateFilter(false)
- setShowDateUntilNowPicker(false)
- setSelectDateFilter(DATE_OPTIONS.CUSTOM_DATE)
- setDateRange({
- from: moment(dateUntilNow).startOf('day').toDate(),
- to: moment().toDate()
- })
- }
-
return (
@@ -366,9 +284,7 @@ export function Report() {
)}
{selectedLanguage.length === 1 && (
- {toProgrammingLanguageDisplayName(
- selectedLanguage[0]
- )}
+ {getLanguageDisplayName(selectedLanguage[0])}
)}
{selectedLanguage.length > 1 && (
@@ -421,9 +337,7 @@ export function Report() {
>
-
- {toProgrammingLanguageDisplayName(value)}
-
+
{getLanguageDisplayName(value)}
)
})}
@@ -446,135 +360,17 @@ export function Report() {
-
-
-
-
-
- date > new Date()}
- />
-
-
-
-
-
-
-
-
-
-
- date > new Date()}
- />
-
-
-
-
-
-
-
-
+
diff --git a/ee/tabby-ui/app/(home)/components/stats.tsx b/ee/tabby-ui/app/(home)/components/stats.tsx
index b6a477394fec..cb34957cfbcf 100644
--- a/ee/tabby-ui/app/(home)/components/stats.tsx
+++ b/ee/tabby-ui/app/(home)/components/stats.tsx
@@ -26,13 +26,12 @@ import {
Language
} from '@/lib/gql/generates/graphql'
import { useMe } from '@/lib/hooks/use-me'
-import { toProgrammingLanguageDisplayName } from '@/lib/language-utils'
+import { getLanguageColor, getLanguageDisplayName } from '@/lib/language-utils'
import { queryDailyStats, queryDailyStatsInPastYear } from '@/lib/tabby/query'
import { Card, CardContent } from '@/components/ui/card'
import { Skeleton } from '@/components/ui/skeleton'
import LoadingWrapper from '@/components/loading-wrapper'
-import languageColors from '../language-colors.json'
import { CompletionCharts } from './completion-charts'
const DATE_RANGE = 6
@@ -50,13 +49,6 @@ type LanguageStats = Record<
}
>
-const getLanguageColorMap = (): Record => {
- return Object.entries(languageColors).reduce((acc, cur) => {
- const [lan, color] = cur
- return { ...acc, [lan.toLocaleLowerCase()]: color }
- }, {})
-}
-
function ActivityCalendar({
data
}: {
@@ -107,7 +99,7 @@ const LanguageLabel: React.FC<
textAnchor="start"
dominantBaseline="middle"
>
- {toProgrammingLanguageDisplayName(value as Language)}
+ {getLanguageDisplayName(value as Language)}
)
}
@@ -136,7 +128,7 @@ function LanguageTooltip({
{views}
- {toProgrammingLanguageDisplayName(name)}
+ {getLanguageDisplayName(name)}
@@ -152,7 +144,6 @@ export default function Stats() {
const searchParams = useSearchParams()
const sample = searchParams.get('sample') === 'true'
- const colorMap = getLanguageColorMap()
const startDate = moment()
.subtract(DATE_RANGE, 'day')
.startOf('day')
@@ -344,7 +335,7 @@ export default function Stats() {
}
/>
{languageData.map((entry, index) => {
- const lanColor = colorMap[entry.name.toLocaleLowerCase()]
+ const lanColor = getLanguageColor(entry.name)
const color = lanColor
? lanColor
: theme === 'dark'
diff --git a/ee/tabby-ui/components/date-range-picker.tsx b/ee/tabby-ui/components/date-range-picker.tsx
new file mode 100644
index 000000000000..458834a6a92f
--- /dev/null
+++ b/ee/tabby-ui/components/date-range-picker.tsx
@@ -0,0 +1,260 @@
+'use client'
+
+import React from 'react'
+import moment, { unitOfTime } from 'moment'
+import { DateRange } from 'react-day-picker'
+
+import { cn } from '@/lib/utils'
+import { Button } from '@/components/ui/button'
+import { Calendar } from '@/components/ui/calendar'
+import { Card, CardContent } from '@/components/ui/card'
+import { IconCheck } from '@/components/ui/icons'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue
+} from '@/components/ui/select'
+import { Separator } from '@/components/ui/separator'
+
+enum DATE_OPTIONS {
+ 'TODAY' = 'today',
+ 'YESTERDAY' = 'yesterday',
+ 'CUSTOM_DATE' = 'custom_date',
+ 'CUSTOM_RANGE' = 'custom_range'
+}
+
+const parseDateValue = (value: string) => {
+ return {
+ number: parseInt(value, 10) || -1,
+ unit: value[value.length - 1] || 'h'
+ }
+}
+
+export default function DateRangePicker({
+ options,
+ onSelect,
+ defaultValue,
+ hasToday,
+ hasYesterday
+}: {
+ options: { label: string; value: string }[]
+ onSelect?: (range: DateRange) => void
+ defaultValue?: string
+ hasToday?: boolean
+ hasYesterday?: boolean
+}) {
+ defaultValue = defaultValue || options[0].value
+ const defaultDate = parseDateValue(defaultValue)
+ const [dateRange, setDateRange] = React.useState({
+ from: moment()
+ .add(
+ defaultDate.number,
+ defaultDate.unit as unitOfTime.DurationConstructor
+ )
+ .toDate(),
+ to: moment().toDate()
+ })
+ const [showDateFilter, setShowDateFilter] = React.useState(false)
+ const [selectDateFilter, setSelectDateFilter] = React.useState(defaultValue)
+ const [showDateRangerPicker, setShowDateRangerPicker] = React.useState(false)
+ const [calendarDateRange, setCalendarDateRange] = React.useState<
+ DateRange | undefined
+ >({
+ from: moment()
+ .add(
+ defaultDate.number,
+ defaultDate.unit as unitOfTime.DurationConstructor
+ )
+ .toDate(),
+ to: moment().toDate()
+ })
+ const [showDateUntilNowPicker, setShowDateUntilNowPicker] =
+ React.useState(false)
+ const [dateUntilNow, setDateUntilNow] = React.useState(
+ moment().toDate()
+ )
+
+ const onDateFilterChange = (value: DATE_OPTIONS | string) => {
+ switch (value) {
+ case DATE_OPTIONS.TODAY: {
+ updateDateRange({
+ from: moment().startOf('day').toDate(),
+ to: moment().toDate()
+ })
+ break
+ }
+ case DATE_OPTIONS.YESTERDAY: {
+ updateDateRange({
+ from: moment().subtract(1, 'd').startOf('day').toDate(),
+ to: moment().subtract(1, 'd').endOf('day').toDate()
+ })
+ break
+ }
+ default: {
+ const { unit, number } = parseDateValue(value)
+ let from = moment().add(number, unit as unitOfTime.DurationConstructor)
+ if (!['h', 's', 'ms'].includes(unit)) from = from.startOf('day')
+ updateDateRange({
+ from: from.toDate(),
+ to: moment().toDate()
+ })
+ }
+ }
+ setSelectDateFilter(value)
+ }
+
+ const onDateFilterOpenChange = (open: boolean) => {
+ if (!open && !showDateRangerPicker && !showDateUntilNowPicker) {
+ setShowDateFilter(false)
+ }
+ }
+
+ const applyDateRange = () => {
+ setShowDateFilter(false)
+ setShowDateRangerPicker(false)
+ setSelectDateFilter(DATE_OPTIONS.CUSTOM_RANGE)
+ updateDateRange({
+ from: calendarDateRange?.from,
+ to: moment(calendarDateRange?.to).endOf('day').toDate()
+ })
+ }
+
+ const applyDateUntilNow = () => {
+ setShowDateFilter(false)
+ setShowDateUntilNowPicker(false)
+ setSelectDateFilter(DATE_OPTIONS.CUSTOM_DATE)
+ updateDateRange({
+ from: moment(dateUntilNow).startOf('day').toDate(),
+ to: moment().toDate()
+ })
+ }
+
+ const updateDateRange = (range: DateRange) => {
+ if (onSelect) onSelect(range)
+ setDateRange(range)
+ }
+
+ return (
+
+
+
+
+
+ date > new Date()}
+ />
+
+
+
+
+
+
+
+
+
+
+ date > new Date()}
+ />
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/ee/tabby-ui/components/ui/date-range-picker.tsx b/ee/tabby-ui/components/ui/date-range-picker.tsx
deleted file mode 100644
index a016bb802464..000000000000
--- a/ee/tabby-ui/components/ui/date-range-picker.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-'use client'
-
-import * as React from 'react'
-import { CalendarIcon } from '@radix-ui/react-icons'
-import { addDays, format } from 'date-fns'
-import moment from 'moment'
-import { DateRange } from 'react-day-picker'
-
-import { cn } from '@/lib/utils'
-import { Button } from '@/components/ui/button'
-import { Calendar } from '@/components/ui/calendar'
-import {
- Popover,
- PopoverContent,
- PopoverTrigger
-} from '@/components/ui/popover'
-
-export default function DatePickerWithRange({
- dateRange,
- className,
- buttonClassName,
- contentAlign,
- onOpenChange
-}: React.HTMLAttributes & {
- dateRange?: DateRange
- buttonClassName?: string
- contentAlign?: 'start' | 'end' | 'center'
- onOpenChange?: (isOpen: boolean, date: DateRange | undefined) => void
- onSelectDateRange?: (date: DateRange | undefined) => void
-}) {
- const [date, setDate] = React.useState({
- from: dateRange?.from || new Date(2022, 0, 20),
- to: dateRange?.to || addDays(new Date(2022, 0, 20), 20)
- })
-
- const toggleOpen = (isOpen: boolean) => {
- if (onOpenChange) onOpenChange(isOpen, date)
- }
-
- return (
-
-
-
-
-
-
- date > new Date()}
- />
-
-
-
- )
-}
diff --git a/ee/tabby-ui/app/(dashboard)/reports/use-all-members.tsx b/ee/tabby-ui/lib/hooks/use-all-members.tsx
similarity index 98%
rename from ee/tabby-ui/app/(dashboard)/reports/use-all-members.tsx
rename to ee/tabby-ui/lib/hooks/use-all-members.tsx
index b179ebe37797..6d6c33d2c4ef 100644
--- a/ee/tabby-ui/app/(dashboard)/reports/use-all-members.tsx
+++ b/ee/tabby-ui/lib/hooks/use-all-members.tsx
@@ -5,7 +5,7 @@ import { DEFAULT_PAGE_SIZE } from '@/lib/constants'
import { QueryVariables } from '@/lib/tabby/gql'
import { listUsers } from '@/lib/tabby/query'
-type Member = {
+export type Member = {
id: string
email: string
}
diff --git a/ee/tabby-ui/lib/language-utils/index.ts b/ee/tabby-ui/lib/language-utils/index.ts
index e16c135a47fd..37536cf0c60f 100644
--- a/ee/tabby-ui/lib/language-utils/index.ts
+++ b/ee/tabby-ui/lib/language-utils/index.ts
@@ -1,10 +1,18 @@
import path from 'path'
-import { has } from 'lodash-es'
+import { has, isNil } from 'lodash-es'
import { Language as ProgrammingLanguage } from '@/lib/gql/generates/graphql'
+import languageColors from './language-colors.json'
import languages from './languages'
+const languageColorMapping: Record = Object.entries(
+ languageColors
+).reduce((acc, cur) => {
+ const [lan, color] = cur
+ return { ...acc, [lan.toLocaleLowerCase()]: color }
+}, {})
+
// Fork from
// https://github.com/TomerAberbach/filename2prism/
export const filename2prism: (filename: string) => Array = filename => {
@@ -38,13 +46,20 @@ export const filename2prism: (filename: string) => Array = filename => {
.filter(Boolean)
}
-export const toProgrammingLanguageDisplayName = (
- lan: ProgrammingLanguage
+export const getLanguageDisplayName = (
+ lan?: string,
+ defaultLan?: string
): string => {
+ const returnDefault = () => (!isNil(defaultLan) ? defaultLan : 'Other')
+ if (!lan) return returnDefault()
+
+ const indexInSupportedLanguages = Object.values(ProgrammingLanguage)
+ .map(lan => lan.toLocaleLowerCase())
+ .indexOf(lan.toLocaleLowerCase())
+ if (indexInSupportedLanguages === -1) return returnDefault()
+
const displayName =
- Object.keys(ProgrammingLanguage)[
- Object.values(ProgrammingLanguage).indexOf(lan)
- ] || ''
+ Object.keys(ProgrammingLanguage)[indexInSupportedLanguages]
const mapping: Record = {
csharp: 'C#',
cpp: 'C++',
@@ -53,3 +68,7 @@ export const toProgrammingLanguageDisplayName = (
}
return mapping[displayName.toLocaleLowerCase()] || displayName
}
+
+export const getLanguageColor = (lan: string): string | undefined => {
+ return languageColorMapping[lan.toLowerCase()]
+}
diff --git a/ee/tabby-ui/app/(home)/language-colors.json b/ee/tabby-ui/lib/language-utils/language-colors.json
similarity index 100%
rename from ee/tabby-ui/app/(home)/language-colors.json
rename to ee/tabby-ui/lib/language-utils/language-colors.json
diff --git a/ee/tabby-ui/package.json b/ee/tabby-ui/package.json
index 7c9dae2e0c07..8a5532c7b398 100644
--- a/ee/tabby-ui/package.json
+++ b/ee/tabby-ui/package.json
@@ -80,6 +80,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-intersection-observer": "^9.4.4",
+ "react-json-view": "^1.21.3",
"react-markdown": "^8.0.7",
"react-nice-avatar": "^1.5.0",
"react-resizable-panels": "^1.0.7",
diff --git a/ee/tabby-ui/yarn.lock b/ee/tabby-ui/yarn.lock
index cca4c67d5df6..f2efe65156cf 100644
--- a/ee/tabby-ui/yarn.lock
+++ b/ee/tabby-ui/yarn.lock
@@ -545,7 +545,7 @@
dependencies:
regenerator-runtime "^0.14.0"
-"@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.3.1":
+"@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7":
version "7.23.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d"
integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==
@@ -559,7 +559,7 @@
dependencies:
regenerator-runtime "^0.14.0"
-"@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
+"@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.24.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
@@ -3320,6 +3320,11 @@ base-64@^0.1.0:
resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb"
integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
+base16@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
+ integrity sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==
+
base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
@@ -4607,12 +4612,19 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
+fbemitter@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
+ integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==
+ dependencies:
+ fbjs "^3.0.0"
+
fbjs-css-vars@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
-fbjs@^3.0.0:
+fbjs@^3.0.0, fbjs@^3.0.1:
version "3.0.5"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d"
integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==
@@ -4681,6 +4693,14 @@ flatted@^3.2.7:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
+flux@^4.0.1:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.4.tgz#9661182ea81d161ee1a6a6af10d20485ef2ac572"
+ integrity sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==
+ dependencies:
+ fbemitter "^3.0.0"
+ fbjs "^3.0.1"
+
focus-trap-react@^10.1.1:
version "10.2.2"
resolved "https://registry.yarnpkg.com/focus-trap-react/-/focus-trap-react-10.2.2.tgz#3b57cdee506e16c3cb75d2cb939b2d509b450489"
@@ -5780,6 +5800,16 @@ lodash.castarray@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115"
integrity sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==
+lodash.curry@^4.0.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
+ integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==
+
+lodash.flow@^3.3.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
+ integrity sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==
+
lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
@@ -7044,6 +7074,11 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
+pure-color@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
+ integrity sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==
+
pvtsutils@^1.3.2, pvtsutils@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.5.tgz#b8705b437b7b134cd7fd858f025a23456f1ce910"
@@ -7070,6 +7105,16 @@ react-activity-calendar@^2.2.8:
chroma-js "^2.4.2"
date-fns "^3.2.0"
+react-base16-styling@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
+ integrity sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==
+ dependencies:
+ base16 "^1.0.0"
+ lodash.curry "^4.0.1"
+ lodash.flow "^3.3.0"
+ pure-color "^1.2.0"
+
react-day-picker@^8.10.0:
version "8.10.0"
resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-8.10.0.tgz#729c5b9564967a924213978fb9c0751884a60595"
@@ -7103,6 +7148,21 @@ react-is@^18.0.0, react-is@^18.2.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+react-json-view@^1.21.3:
+ version "1.21.3"
+ resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475"
+ integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==
+ dependencies:
+ flux "^4.0.1"
+ react-base16-styling "^0.6.0"
+ react-lifecycles-compat "^3.0.4"
+ react-textarea-autosize "^8.3.2"
+
+react-lifecycles-compat@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+ integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
react-markdown@^8.0.7:
version "8.0.7"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.7.tgz#c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b"
@@ -7186,7 +7246,7 @@ react-syntax-highlighter@^15.5.0:
prismjs "^1.27.0"
refractor "^3.6.0"
-react-textarea-autosize@^8.4.1:
+react-textarea-autosize@^8.3.2, react-textarea-autosize@^8.4.1:
version "8.5.3"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz#d1e9fe760178413891484847d3378706052dd409"
integrity sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==