diff --git a/src/@types/parseable/api/about.ts b/src/@types/parseable/api/about.ts new file mode 100644 index 00000000..c83321a7 --- /dev/null +++ b/src/@types/parseable/api/about.ts @@ -0,0 +1,11 @@ +export type AboutData ={ + commit : string; + deploymentId : string; + latestVersion : string; + license : string; + mode : string; + staging : string; + store : string; + updateAvailable : boolean; + version : string; +} \ No newline at end of file diff --git a/src/api/about.ts b/src/api/about.ts new file mode 100644 index 00000000..8fcb1258 --- /dev/null +++ b/src/api/about.ts @@ -0,0 +1,8 @@ + +import { AboutData } from "@/@types/parseable/api/about"; +import { Axios } from "./axios"; +import { ABOUT_URL } from "./constants"; + +export const getCurrentAbout = () => { + return Axios().get(ABOUT_URL); +} \ No newline at end of file diff --git a/src/api/auth.ts b/src/api/auth.ts index fd980bde..5ea63030 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -1,10 +1,10 @@ import { Axios } from './axios'; -import { HEALTH_LIVENESS_URL } from './constants'; +import { LOG_STREAM_LIST_URL } from './constants'; export const loginIn = (username: string, password: string) => { const credentials = btoa(`${username}:${password}`); - return Axios().get(HEALTH_LIVENESS_URL, { + return Axios().get(LOG_STREAM_LIST_URL, { headers: { Authorization: `Basic ${credentials}`, }, diff --git a/src/api/constants.ts b/src/api/constants.ts index 3e244fae..e1b33403 100644 --- a/src/api/constants.ts +++ b/src/api/constants.ts @@ -8,4 +8,4 @@ export const LOG_STREAMS_ALERTS_URL = (streamName: string) => `${LOG_STREAM_LIST export const LOG_STREAMS_RETRNTION_URL = (streamName: string) => `${LOG_STREAM_LIST_URL}/${streamName}/retention`; export const LOG_STREAMS_STATS_URL = (streamName: string) => `${LOG_STREAM_LIST_URL}/${streamName}/stats`; export const DELETE_STREAMS_URL = (streamName: string) => `${LOG_STREAM_LIST_URL}/${streamName}`; - +export const ABOUT_URL = `${API_V1}/about`; diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 24008153..bbe1f343 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -3,12 +3,9 @@ import { Navbar as MantineNavbar, NavLink, Select, - Anchor, - Card, Box, Modal, Text, - Image, Button, TextInput, } from '@mantine/core'; @@ -17,18 +14,15 @@ import { IconReportAnalytics, IconFileAlert, IconReload, - IconHelpCircle, IconLogout, IconUser, IconBinaryTree2, IconTableShortcut, IconSettings, IconTrash, + IconInfoCircle, } from '@tabler/icons-react'; import { FC, useEffect } from 'react'; -import docImage from '@/assets/images/doc.webp'; -import githubLogo from '@/assets/images/github-logo.webp'; -import slackLogo from '@/assets/images/slack-logo.webp'; import { useNavbarStyles } from './styles'; import { useParams } from 'react-router-dom'; import { useGetLogStreamList } from '@/hooks/useGetLogStreamList'; @@ -40,6 +34,7 @@ import dayjs from 'dayjs'; import { useDisclosure, useLocalStorage } from '@mantine/hooks'; import { LOGIN_ROUTE } from '@/constants/routes'; import { useDeleteLogStream } from '@/hooks/useDeleteLogStream'; +import InfoModal from './infoModal'; const links = [ { icon: IconZoomCode, label: 'Query', pathname: '/query' }, @@ -70,7 +65,7 @@ const Navbar: FC = (props) => { const [disableLink, setDisableLink] = useMountedState(false); const [isSubNavbarOpen, setIsSubNavbarOpen] = useMountedState(false); - const [opened, { open, close }] = useDisclosure(false); + const [opened, { open, close }] = useDisclosure(true); const [openedDelete, { close: closeDelete, open: openDelete }] = useDisclosure(); const { data: streams, error, getData, resetData: resetStreamArray } = useGetLogStreamList(); @@ -177,8 +172,6 @@ const Navbar: FC = (props) => { streamsBtn, lowerContainer, actionBtn, - helpTitle, - helpDescription, userBtn, } = classes; return ( @@ -237,8 +230,8 @@ const Navbar: FC = (props) => { } className={userBtn} component="a" /> } + label="About" + icon={} className={actionBtn} component="a" onClick={open} @@ -275,61 +268,11 @@ const Navbar: FC = (props) => { - - Need any help? - Here you can find useful resources and information. - - {helpResources.map((data) => ( - - ))} - - + ); }; -const helpResources = [ - { - image: slackLogo, - title: 'Slack', - description: 'Connect with us', - href: 'https://launchpass.com/parseable', - }, - { - image: githubLogo, - title: 'GitHub', - description: 'Find resources', - href: 'https://github.com/parseablehq/parseable', - }, - { - image: docImage, - title: 'Documentation', - description: 'Learn more', - href: 'https://www.parseable.io/docs/introduction', - }, -]; - -type HelpCardProps = { - data: (typeof helpResources)[number]; -}; - -const HelpCard: FC = (props) => { - const { data } = props; - const { classes } = useNavbarStyles(); - const { helpCard, helpCardTitle, helpCardDescription } = classes; - - return ( - - - - {data.title} - {data.description} - - {data.title} - - - ); -}; export default Navbar; diff --git a/src/components/Navbar/infoModal.tsx b/src/components/Navbar/infoModal.tsx new file mode 100644 index 00000000..e5cfe3f9 --- /dev/null +++ b/src/components/Navbar/infoModal.tsx @@ -0,0 +1,159 @@ +import { Anchor, Box, Image, Modal, Table, Text, Tooltip } from '@mantine/core'; +import { FC, useEffect } from 'react'; +import { useInfoModalStyles } from './styles'; +import docImage from '@/assets/images/doc.webp'; +import githubLogo from '@/assets/images/github-logo.webp'; +import slackLogo from '@/assets/images/slack-logo.webp'; +import { useGetAbout } from '@/hooks/useGetAbout'; + +const helpResources = [ + { + image: slackLogo, + title: 'Slack', + description: 'Connect with us', + href: 'https://launchpass.com/parseable', + }, + { + image: githubLogo, + title: 'GitHub', + description: 'Find resources', + href: 'https://github.com/parseablehq/parseable', + }, + { + image: docImage, + title: 'Documentation', + description: 'Learn more', + href: 'https://www.parseable.io/docs/introduction', + }, +]; + +type HelpCardProps = { + data: (typeof helpResources)[number]; +}; + +const HelpCard: FC = (props) => { + const { data } = props; + + const { classes } = useInfoModalStyles(); + const { HelpIconBox, helpToolip } = classes; + + return ( + + + + {data.title} + + + + ); +}; + +type InfoModalProps = { + opened: boolean; + close(): void; +}; + +const InfoModal: FC = (props) => { + const { opened, close } = props; + + const { data, loading, error, getAbout, resetData } = useGetAbout(); + useEffect(() => { + if (data) { + resetData(); + } + getAbout(); + return () => { + resetData(); + }; + }, []); + + const { classes } = useInfoModalStyles(); + const { + container, + innerContainer, + infoModal, + helpTitle, + helpDescription, + aboutText, + aboutTitle, + aboutDescription, + helpIconContainer, + } = classes; + + return ( + + + + About + {error ? ( + Error... + ) : loading ? ( + Loading... + ) : data ? ( + <> + + Here you can find useful information about your Parseable instance. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Commit{data.commit}
Deployment Id{data.deploymentId}
Latest Version{data.latestVersion}
License{data.license}
Mode{data.mode}
Staging{data.staging}
Store{data.store}
Version{data.version}
+ + ) : null} +
+ + Need any help? + Here you can find useful resources and information. + + + {helpResources.map((data) => ( + + ))} + + +
+
+ ); +}; + +export default InfoModal; diff --git a/src/components/Navbar/styles.tsx b/src/components/Navbar/styles.tsx index e1ec5295..8ec68ca5 100644 --- a/src/components/Navbar/styles.tsx +++ b/src/components/Navbar/styles.tsx @@ -1,8 +1,8 @@ import { createStyles } from '@mantine/core'; -import { heights, widths } from '../Mantine/sizing'; +import { heights, sizing, widths } from '../Mantine/sizing'; export const useNavbarStyles = createStyles((theme) => { - const { colors, radius, fontSizes, shadows, spacing } = theme; + const { colors, radius, fontSizes } = theme; const { fontWeights, sizing } = theme.other; const white = colors.white[0]; const sColor = colors.brandSecondary[0]; @@ -81,15 +81,56 @@ export const useNavbarStyles = createStyles((theme) => { background: white, }, }, + userContainer: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + userText: { + fontSize: fontSizes.sm, + }, + }; +}); - helpTitle: { +//infoModal, infoModalTitle, infoModalDescription +export const useInfoModalStyles = createStyles((theme) => { + const { colors, radius, fontSizes, shadows, spacing } = theme; + const { fontWeights } = theme.other; + const white = colors.white[0]; + const sColor = colors.brandSecondary[0]; + const defaultRadius = radius[theme.defaultRadius as string]; + + return { + container: { + height: '100%', + width: '100%', + + }, + innerContainer: { + padding: spacing.md, + }, + infoModal: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + background: white, + color: theme.colors.gray[7], + fontFamily: theme.fontFamily, + fontSize: fontSizes.md, + fontWeight: fontWeights.normal, + lineHeight: 'normal', + padding: '24px', + borderRadius: defaultRadius, + boxShadow: shadows.sm, + }, + aboutTitle: { fontSize: fontSizes.md, textAlign: 'center', - color: white, + color: colors.gray[7], fontWeight: fontWeights.bold, }, - - helpDescription: { + aboutDescription: { fontSize: fontSizes.sm, textAlign: 'center', color: colors.dimmed[0], @@ -105,48 +146,79 @@ export const useNavbarStyles = createStyles((theme) => { marginTop: theme.spacing.sm, marginLeft: 'auto', marginRight: 'auto', + marginBottom: spacing.sm, }, }, + aboutText: { + '& tr': { + transition: 'transform .2s ease-in-out', + '&: hover': { + transform: 'scale(1.05)', + " & td " : { + border: `${sizing.px} solid ${colors.gray[2]}`, + } - helpCard: { - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - boxShadow: shadows.sm, - marginTop: spacing.sm, - transition: 'transform .2s ease-in-out', + }, + }, + - '&:hover': { - transform: 'scale(1.05)', + '& tr>td:last-of-type': { + fontSize: fontSizes.sm, + color: colors.dimmed[0], + lineHeight: 'normal', + '&: hover': { + color: sColor, + } }, }, + helpTitle: { + fontSize: fontSizes.md, + textAlign: 'center', + color: colors.gray[7], + fontWeight: fontWeights.bold, + }, - helpCardTitle: { - fontWeight: fontWeights.semibold, + helpDescription: { + fontSize: fontSizes.sm, + textAlign: 'center', + color: colors.dimmed[0], + marginTop: spacing.xs, '&::after': { content: '""', + borderRadius: defaultRadius, display: 'block', - backgroundColor: white, + backgroundColor: sColor, width: widths[14], height: heights['0.5'], - marginTop: spacing.xs, - marginBottom: spacing.xs, + marginTop: theme.spacing.sm, + marginLeft: 'auto', + marginRight: 'auto', + marginBottom: '31px', }, }, - helpCardDescription: { - color: colors.dimmed[0], - fontSize: fontSizes.sm, + HelpIconBox: { + marginLeft: spacing.md, + transition: 'transform .2s ease-in-out', + '&:hover': { + transform: 'scale(1.05)', + }, }, - userContainer: { + helpToolip: { + "& .mantine-Tooltip-tooltip": { + fontWeight: fontWeights.semibold, + fontSize: fontSizes.sm, + color: colors.gray[7], + backgroundColor: colors.black[0], + } + }, + helpIconContainer: { display: 'flex', alignItems: 'center', + width: '100%', justifyContent: 'center', }, - userText: { - fontSize: fontSizes.sm, - }, }; }); diff --git a/src/hooks/useGetAbout.ts b/src/hooks/useGetAbout.ts new file mode 100644 index 00000000..1ec78fb3 --- /dev/null +++ b/src/hooks/useGetAbout.ts @@ -0,0 +1,41 @@ +import { StatusCodes } from 'http-status-codes'; +import useMountedState from './useMountedState'; +import { getCurrentAbout } from '@/api/about'; +import { AboutData } from '@/@types/parseable/api/about'; + +export const useGetAbout = () => { + const [data, setData] = useMountedState(null); + const [error, setError] = useMountedState(null); + const [loading, setLoading] = useMountedState(false); + + const getAbout = async () => { + try { + setLoading(true); + setError(null); + const res = await getCurrentAbout(); + + switch (res.status) { + case StatusCodes.OK: { + + setData(res.data); + break; + } + default: { + setError('Failed to get ALert'); + console.error(res); + } + } + } catch(error) { + setError('Failed to get ALert'); + console.error(error); + } finally { + setLoading(false); + } + }; + + const resetData = () => { + setData(null); + }; + + return { data, error, loading, getAbout, resetData }; +};