diff --git a/apps/dashboard/components/AgentDeployTab.tsx b/apps/dashboard/components/AgentDeployTab.tsx index 457ed9c2b..0f9e59680 100644 --- a/apps/dashboard/components/AgentDeployTab.tsx +++ b/apps/dashboard/components/AgentDeployTab.tsx @@ -123,8 +123,7 @@ function AgentDeployTab(props: Props) { disableSubmitButton cardProps={{ sx: { - maxWidth: 'md', - mx: 'auto', + maxWidth: '100%', }, }} > diff --git a/apps/dashboard/components/ChatSection.tsx b/apps/dashboard/components/ChatSection.tsx index a26b9f11d..2f39f063a 100644 --- a/apps/dashboard/components/ChatSection.tsx +++ b/apps/dashboard/components/ChatSection.tsx @@ -32,6 +32,7 @@ function ChatSection({ rootSx={{ pt: 1, height: '100%', + minHeight: '100%', width: '200px', }} currentConversationId={currentConversationId} diff --git a/apps/dashboard/components/ConversationExport.tsx b/apps/dashboard/components/ConversationExport.tsx index ea6215fe1..7332ad2c8 100644 --- a/apps/dashboard/components/ConversationExport.tsx +++ b/apps/dashboard/components/ConversationExport.tsx @@ -1,22 +1,62 @@ import DownloadForOfflineRoundedIcon from '@mui/icons-material/DownloadForOfflineRounded'; -import InfoRoundedIcon from '@mui/icons-material/InfoRounded'; -import { Alert, Button, Card, Stack } from '@mui/joy'; +import { Button } from '@mui/joy'; import axios from 'axios'; import { saveAs } from 'file-saver'; import { useState } from 'react'; import { toast } from 'react-hot-toast'; +import { z } from 'zod'; -interface Props {} +import { + ConversationChannel, + ConversationPriority, + MessageEval, +} from '@chaindesk/prisma'; -export function ConversationExport({}: Props) { +interface Props { + channel?: ConversationChannel; + priority?: ConversationPriority; + agentId?: string; + assigneeId?: string; + messageEval?: MessageEval; +} + +export function ConversationExport({ + channel, + priority, + messageEval, + agentId, + assigneeId, +}: Props) { const [isLoading, setIsLoading] = useState(false); const exportConversations = async () => { try { + const { success: validChannel } = z + .nativeEnum(ConversationChannel) + .safeParse(channel); + const { success: validEval } = z + .nativeEnum(MessageEval) + .safeParse(messageEval); + const { success: validPriority } = z + .nativeEnum(MessageEval) + .safeParse(priority); + + const { success: validAgentId } = z.string().min(3).safeParse(agentId); + const { success: validAssigneeId } = z + .string() + .min(3) + .safeParse(assigneeId); + setIsLoading(true); const { data } = await toast.promise( axios.post( '/api/conversations/export', - {}, + { + ...(validChannel ? { channel } : {}), + ...(validPriority ? { priority } : {}), + ...(validAgentId ? { agentId } : {}), + ...(validAssigneeId ? { assigneeId } : {}), + ...(validEval ? { messageEval } : {}), + }, { responseType: 'blob', } diff --git a/apps/dashboard/components/ConversationList.tsx b/apps/dashboard/components/ConversationList.tsx index 861bae279..9cd98b807 100644 --- a/apps/dashboard/components/ConversationList.tsx +++ b/apps/dashboard/components/ConversationList.tsx @@ -1,8 +1,5 @@ -import AddCircleOutlineRoundedIcon from '@mui/icons-material/AddCircleOutlineRounded'; import AddRoundedIcon from '@mui/icons-material/AddRounded'; import Button from '@mui/joy/Button'; -import Chip from '@mui/joy/Chip'; -import Divider from '@mui/joy/Divider'; import List from '@mui/joy/List'; import ListDivider from '@mui/joy/ListDivider'; import ListItem from '@mui/joy/ListItem'; @@ -13,7 +10,7 @@ import Stack from '@mui/joy/Stack'; import { SxProps } from '@mui/joy/styles/types'; import Typography from '@mui/joy/Typography'; import { useRouter } from 'next/router'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import InfiniteScroll from 'react-infinite-scroller'; import useSWR, { useSWRConfig } from 'swr'; import useSWRInfinite from 'swr/infinite'; @@ -65,8 +62,6 @@ const Item = (props: { - - {/* */} ); }; @@ -80,6 +75,7 @@ function ConversationList({ }: Props) { const scrollParentRef = useRef(null); const router = useRouter(); + const [state, setState] = useStateReducer({ hasMore: true, hasLoadedOnce: false, @@ -106,7 +102,7 @@ function ConversationList({ }, fetcher, { - refreshInterval: 5000, + refreshInterval: router?.query?.conversationId ? 5000 : 500, onSuccess: (data) => { const id = data?.[0]?.[0]?.id; @@ -117,19 +113,25 @@ function ConversationList({ } ); - const conversations = getConversationsQuery?.data?.flat?.() || []; + const conversations = useMemo( + () => getConversationsQuery?.data?.flat?.() || [], + [getConversationsQuery?.data] + ); + + const conversationsLength = useMemo( + () => conversations.length, + [conversations] + ); useEffect(() => { + const conversationId = (router.query.conversationId || + conversations[0]?.id) as string; if (router.query?.conversationId) { - handleSelectConversation?.(router.query.conversationId as string); + handleSelectConversation?.(conversationId); } else { - handleSelectConversation?.(conversations[0]?.id); + handleSelectConversation?.(conversationId); } - }, [getConversationsQuery?.data]); - - if (!getConversationsQuery.isLoading && conversations.length === 0) { - return null; - } + }, [conversationsLength]); return ( - {/* */} + - - {/* */} )) as any } > + {!router.query.conversationId && ( + + )} + {conversations?.map((each) => ( - Advanced Settings - - - - - + {!props.hideText && defaultValues?.datastoreId && defaultValues?.id && (
diff --git a/apps/dashboard/components/DatastoreSettings.tsx b/apps/dashboard/components/DatastoreSettings.tsx index 4c306d89a..f074d967c 100644 --- a/apps/dashboard/components/DatastoreSettings.tsx +++ b/apps/dashboard/components/DatastoreSettings.tsx @@ -371,7 +371,8 @@ function DatastoreSettings() { ({ maxWidth: '100%', - width: theme.breakpoints.values.md, + width: '100%', + px: 4, mx: 'auto', })} > diff --git a/apps/dashboard/components/FormInstallTab.tsx b/apps/dashboard/components/FormInstallTab.tsx index 02d05196d..fa8a79a2a 100644 --- a/apps/dashboard/components/FormInstallTab.tsx +++ b/apps/dashboard/components/FormInstallTab.tsx @@ -32,7 +32,7 @@ function FormInstallTab({ formId }: Props) { `; return ( - + Web Component diff --git a/apps/dashboard/components/FormSettingsTab.tsx b/apps/dashboard/components/FormSettingsTab.tsx index fddfad37a..1d87822c1 100644 --- a/apps/dashboard/components/FormSettingsTab.tsx +++ b/apps/dashboard/components/FormSettingsTab.tsx @@ -28,16 +28,13 @@ function FormSettingsTab({ formId }: Props) { } return ( - + diff --git a/apps/dashboard/components/Layout/ExpandedNavigation.tsx b/apps/dashboard/components/Layout/ExpandedNavigation.tsx new file mode 100644 index 000000000..dfcf56365 --- /dev/null +++ b/apps/dashboard/components/Layout/ExpandedNavigation.tsx @@ -0,0 +1,433 @@ +import ArrowForwardRoundedIcon from '@mui/icons-material/ArrowForwardRounded'; +import ChatRoundedIcon from '@mui/icons-material/ChatRounded'; +import LinkedInIcon from '@mui/icons-material/LinkedIn'; +import TwitterIcon from '@mui/icons-material/Twitter'; +import { + Box, + Button, + Chip, + ColorPaletteProp, + Divider, + IconButton, + List, + ListItem, + ListItemButton, + ListItemContent, + ListItemDecorator, + Stack, + SvgIcon, + Typography, +} from '@mui/joy'; +import Head from 'next/head'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useSession } from 'next-auth/react'; + +import { ProductType } from '@app/hooks/useProduct'; + +import { appUrl } from '@chaindesk/lib/config'; +import { AppStatus, RouteNames } from '@chaindesk/lib/types'; +import DarkModeToggle from '@chaindesk/ui/DarkModeToggle'; + +import AccountCard from '../AccountCard'; +import UserMenu from '../UserMenu'; + +export type AppLink = + | { + label: string; + route: RouteNames; + icon: JSX.Element; + active: boolean; + isNew: boolean; + isExperimental?: undefined; + } + | { + label: string; + route: RouteNames; + icon: JSX.Element; + active: boolean; + isExperimental: boolean; + isNew: boolean; + }; + +function NavigationLink(props: { + href: string; + target?: string; + active?: boolean; + icon?: React.ReactNode; + label?: string | React.ReactElement; + isExperimental?: boolean; + isNew?: boolean; +}) { + return ( + + + + + {props.icon} + + {props.label} + + + {props.isNew && ( + + new + + )} + + {props.isExperimental && ( + + beta + + )} + + + + + ); +} + +export default function ExpandedNavigation({ + product, + appLinks, + settingLinks, + docLinks, + publicRuntimeConfig, + status, +}: { + product: ProductType; + appLinks: AppLink[]; + settingLinks: AppLink[]; + docLinks: AppLink[]; + status: AppStatus | undefined; + publicRuntimeConfig: Record & { version?: string }; +}) { + const { data: session } = useSession({ + required: true, + }); + return ( + <> + + + + +
+ Chaindesk +
+ Chaindesk +
+ +
+ + + + + {!!session?.user?.id && ( + +