From 2e99452645c1538c277428e56c345a0e8e16d53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Mon, 4 Nov 2024 14:20:26 +0000 Subject: [PATCH] chore: add Unleash AI to New in Unleash (#8642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://linear.app/unleash/issue/2-2910/add-unleash-ai-to-new-in-unleash Adds a new "Unleash AI" item to the "New in Unleash" section. We don’t have documentation to link to yet, as this is still an experimental feature. However, I’m considering adding a “Check it out” button that highlights the button, which I can introduce in a separate PR. ![image](https://github.com/user-attachments/assets/520362b2-627c-415e-b0bb-296825d5d8ee) --- frontend/src/assets/img/aiPreview.svg | 24 +++++++ frontend/src/component/ai/AIChat.tsx | 30 ++++---- .../NewInUnleash/NewInUnleash.tsx | 57 +++++++++++---- .../NewInUnleash/NewInUnleashItem.tsx | 23 +++--- .../NewInUnleash/NewInUnleashTooltip.tsx | 71 +++++++++++-------- 5 files changed, 140 insertions(+), 65 deletions(-) create mode 100644 frontend/src/assets/img/aiPreview.svg diff --git a/frontend/src/assets/img/aiPreview.svg b/frontend/src/assets/img/aiPreview.svg new file mode 100644 index 000000000000..5700cb8a788f --- /dev/null +++ b/frontend/src/assets/img/aiPreview.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/component/ai/AIChat.tsx b/frontend/src/component/ai/AIChat.tsx index 92b404291920..77656797ff80 100644 --- a/frontend/src/component/ai/AIChat.tsx +++ b/frontend/src/component/ai/AIChat.tsx @@ -1,6 +1,6 @@ import { mutate } from 'swr'; import { ReactComponent as AIIcon } from 'assets/icons/AI.svg'; -import { IconButton, styled, useMediaQuery } from '@mui/material'; +import { IconButton, styled, Tooltip, useMediaQuery } from '@mui/material'; import { useEffect, useRef, useState } from 'react'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; @@ -198,19 +198,21 @@ export const AIChat = () => { if (!open) { return ( - { - trackEvent('unleash-ai-chat', { - props: { - eventType: 'open', - }, - }); - setOpen(true); - }} - > - - + + { + trackEvent('unleash-ai-chat', { + props: { + eventType: 'open', + }, + }); + setOpen(true); + }} + > + + + ); } diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx index bfdb849f4cf4..a4341f495591 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx @@ -1,4 +1,3 @@ -import type { ReactNode } from 'react'; import { useUiFlag } from 'hooks/useUiFlag'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { useLocalStorageState } from 'hooks/useLocalStorageState'; @@ -13,13 +12,18 @@ import { } from '@mui/material'; import Signals from '@mui/icons-material/Sensors'; import type { NavigationMode } from 'component/layout/MainLayout/NavigationSidebar/NavigationMode'; -import { NewInUnleashItem } from './NewInUnleashItem'; +import { + NewInUnleashItem, + type NewInUnleashItemDetails, +} from './NewInUnleashItem'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { ReactComponent as SignalsPreview } from 'assets/img/signals.svg'; import LinearScaleIcon from '@mui/icons-material/LinearScale'; import { useNavigate } from 'react-router-dom'; import { useEventTimelineContext } from 'component/events/EventTimeline/EventTimelineContext'; import { ReactComponent as EventTimelinePreview } from 'assets/img/eventTimeline.svg'; +import { ReactComponent as AIIcon } from 'assets/icons/AI.svg'; +import { ReactComponent as AIPreview } from 'assets/img/aiPreview.svg'; const StyledNewInUnleash = styled('div')(({ theme }) => ({ margin: theme.spacing(2, 0, 1, 0), @@ -75,17 +79,11 @@ const StyledLinearScaleIcon = styled(LinearScaleIcon)(({ theme }) => ({ color: theme.palette.primary.main, })); -type NewItem = { - label: string; - summary: string; - icon: ReactNode; - onCheckItOut: () => void; - docsLink: string; - show: boolean; - longDescription: ReactNode; - preview?: ReactNode; - beta?: boolean; -}; +const StyledAIIcon = styled(AIIcon)(({ theme }) => ({ + '& > path': { + fill: theme.palette.primary.main, + }, +})); interface INewInUnleashProps { mode?: NavigationMode; @@ -102,12 +100,17 @@ export const NewInUnleash = ({ 'new-in-unleash-seen:v1', new Set(), ); - const { isOss, isEnterprise } = useUiConfig(); + const { + isOss, + isEnterprise, + uiConfig: { unleashAIAvailable }, + } = useUiConfig(); const signalsEnabled = useUiFlag('signals'); + const unleashAIEnabled = useUiFlag('unleashAI'); const { setHighlighted } = useEventTimelineContext(); - const items: NewItem[] = [ + const items: NewInUnleashItemDetails[] = [ { label: 'Signals & Actions', summary: 'Listen to signals via Webhooks', @@ -174,6 +177,30 @@ export const NewInUnleash = ({ ), }, + { + label: 'Unleash AI', + summary: + 'Enhance your Unleash experience with the help of the Unleash AI assistant', + icon: , + preview: , + show: Boolean(unleashAIAvailable) && unleashAIEnabled, + beta: true, + longDescription: ( + <> +

+ Meet the Unleash AI assistant, designed to make your + experience with Unleash easier and more intuitive, + whether you're handling tasks or looking for guidance. +

+ +

+ Start chatting by using the button in the bottom right + corner of the page, and discover all the ways the + Unleash AI assistant can help you. +

+ + ), + }, ]; const visibleItems = items.filter( diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx index 743e0c3a0582..7de61ab86a16 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx @@ -13,6 +13,18 @@ import { NewInUnleashTooltip } from './NewInUnleashTooltip'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { Badge } from 'component/common/Badge/Badge'; +export type NewInUnleashItemDetails = { + label: string; + summary: string; + icon: ReactNode; + onCheckItOut?: () => void; + docsLink?: string; + show: boolean; + longDescription: ReactNode; + preview?: ReactNode; + beta?: boolean; +}; + const StyledItemButton = styled(ListItemButton)(({ theme }) => ({ outline: `1px solid ${theme.palette.divider}`, borderRadius: theme.shape.borderRadiusMedium, @@ -32,22 +44,17 @@ const StyledItemTitle = styled('div')(({ theme }) => ({ display: 'flex', gap: theme.spacing(1), alignItems: 'center', + height: theme.spacing(3), })); const StyledItemButtonClose = styled(IconButton)(({ theme }) => ({ padding: theme.spacing(0.25), })); -interface INewInUnleashItemProps { - icon: ReactNode; +interface INewInUnleashItemProps + extends Omit { onClick: () => void; onDismiss: () => void; - label: string; - longDescription: ReactNode; - onCheckItOut: () => void; - docsLink: string; - preview?: ReactNode; - summary: string; beta: boolean; } diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx index c2491ab9e3b1..9233ece2ce53 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx @@ -78,15 +78,20 @@ const StyledTitle = styled('div')(({ theme }) => ({ })); const ReadMore = styled(Box)(({ theme }) => ({ - padding: theme.spacing(3, 0), + paddingTop: theme.spacing(3), + paddingBottom: theme.spacing(1), +})); + +const StyledCheckItOutButton = styled(Button)(({ theme }) => ({ + marginTop: theme.spacing(2), })); export const NewInUnleashTooltip: FC<{ children: React.ReactElement; title: string; longDescription: ReactNode; - docsLink: string; - onCheckItOut: () => void; + docsLink?: string; + onCheckItOut?: () => void; open: boolean; preview?: ReactNode; onClose: () => void; @@ -134,31 +139,41 @@ export const NewInUnleashTooltip: FC<{ /> {longDescription} - - - Read more in our - documentation - - - + + + Read more in our + documentation + + + } + /> + { + event.stopPropagation(); + onClose(); + onCheckItOut!(); + }} + > + Check it out + + } + />