Skip to content

PMM-13700 created help center page #3901

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

Open
wants to merge 7 commits into
base: v3
Choose a base branch
from
Open
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
10 changes: 6 additions & 4 deletions ui/src/components/page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ export const Page: FC<PageProps> = ({ title, footer, children }) => {

return (
<Stack
sx={{
sx={(theme) => ({
[theme.breakpoints.up('lg')]: {
width: 1000,
},
width: {
sm: 1000,
xs: 'auto',
md: 'auto',
},
p: {
xs: 2,
},
mx: 'auto',
gap: 3,
mt: 1,
}}
})}
>
{!!title && <Typography variant="h2">{title}</Typography>}
{user?.isAuthorized ? (
Expand Down
1 change: 1 addition & 0 deletions ui/src/icons/pmm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './check';
export * from './dashboards';
export * from './node';
export * from './percona';
export * from './knowledgeBase';
17 changes: 17 additions & 0 deletions ui/src/icons/pmm/knowledgeBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { SvgIcon, SvgIconProps } from '@mui/material';

export const KnowledgeBaseIcon = (props: SvgIconProps) => (
<SvgIcon
width="28"
height="28"
viewBox="0 0 28 28"
fill="none"
xmlns="https://www.w3.org/2000/svg"
{...props}
>
<path
d="M16.3333 11.55V9.56663C16.975 9.2944 17.6315 9.09024 18.3027 8.95413C18.9731 8.81802 19.6778 8.74996 20.4167 8.74996C20.9222 8.74996 21.4181 8.78885 21.9042 8.86663C22.3903 8.9444 22.8667 9.04163 23.3333 9.15829V11.025C22.8667 10.85 22.3953 10.7189 21.9193 10.6318C21.4426 10.5439 20.9417 10.5 20.4167 10.5C19.6778 10.5 18.9681 10.5925 18.2875 10.7776C17.607 10.962 16.9556 11.2194 16.3333 11.55ZM16.3333 17.9666V15.9833C16.975 15.7111 17.6315 15.5069 18.3027 15.3708C18.9731 15.2347 19.6778 15.1666 20.4167 15.1666C20.9222 15.1666 21.4181 15.2055 21.9042 15.2833C22.3903 15.3611 22.8667 15.4583 23.3333 15.575V17.4416C22.8667 17.2666 22.3953 17.1356 21.9193 17.0485C21.4426 16.9606 20.9417 16.9166 20.4167 16.9166C19.6778 16.9166 18.9681 17.0041 18.2875 17.1791C17.607 17.3541 16.9556 17.6166 16.3333 17.9666ZM16.3333 14.7583V12.775C16.975 12.5027 17.6315 12.2986 18.3027 12.1625C18.9731 12.0263 19.6778 11.9583 20.4167 11.9583C20.9222 11.9583 21.4181 11.9972 21.9042 12.075C22.3903 12.1527 22.8667 12.25 23.3333 12.3666V14.2333C22.8667 14.0583 22.3953 13.9272 21.9193 13.8401C21.4426 13.7522 20.9417 13.7083 20.4167 13.7083C19.6778 13.7083 18.9681 13.8008 18.2875 13.986C17.607 14.1703 16.9556 14.4277 16.3333 14.7583ZM7.58334 18.6666C8.49723 18.6666 9.38701 18.7685 10.2527 18.9723C11.1176 19.1768 11.9778 19.4833 12.8333 19.8916V8.39996C12.0361 7.93329 11.1903 7.58329 10.2958 7.34996C9.40139 7.11663 8.49723 6.99996 7.58334 6.99996C6.88334 6.99996 6.18839 7.06802 5.49851 7.20413C4.80784 7.34024 4.14167 7.5444 3.50001 7.81663V19.3666C4.18056 19.1333 4.85645 18.9583 5.52767 18.8416C6.19812 18.725 6.88334 18.6666 7.58334 18.6666ZM15.1667 19.8916C16.0222 19.4833 16.8828 19.1768 17.7485 18.9723C18.6134 18.7685 19.5028 18.6666 20.4167 18.6666C21.1167 18.6666 21.8023 18.725 22.4735 18.8416C23.144 18.9583 23.8195 19.1333 24.5 19.3666V7.81663C23.8583 7.5444 23.1926 7.34024 22.5027 7.20413C21.812 7.06802 21.1167 6.99996 20.4167 6.99996C19.5028 6.99996 18.5986 7.11663 17.7042 7.34996C16.8097 7.58329 15.9639 7.93329 15.1667 8.39996V19.8916ZM14 23.3333C13.0667 22.5944 12.0556 22.0208 10.9667 21.6125C9.87778 21.2041 8.75001 21 7.58334 21C6.76667 21 5.96478 21.1069 5.17767 21.3208C4.38978 21.5347 3.63612 21.8361 2.91667 22.225C2.50834 22.4388 2.11478 22.4291 1.73601 22.1958C1.35645 21.9625 1.16667 21.6222 1.16667 21.175V7.11663C1.16667 6.90274 1.22034 6.69857 1.32767 6.50413C1.43423 6.30968 1.59445 6.16385 1.80834 6.06663C2.70278 5.59996 3.63612 5.24996 4.60834 5.01663C5.58056 4.78329 6.57223 4.66663 7.58334 4.66663C8.71112 4.66663 9.81478 4.81246 10.8943 5.10413C11.9731 5.39579 13.0083 5.83329 14 6.41663C14.9917 5.83329 16.0273 5.39579 17.1068 5.10413C18.1856 4.81246 19.2889 4.66663 20.4167 4.66663C21.4278 4.66663 22.4195 4.78329 23.3917 5.01663C24.3639 5.24996 25.2972 5.59996 26.1917 6.06663C26.4056 6.16385 26.5662 6.30968 26.6735 6.50413C26.7801 6.69857 26.8333 6.90274 26.8333 7.11663V21.175C26.8333 21.6222 26.644 21.9625 26.2652 22.1958C25.8856 22.4291 25.4917 22.4388 25.0833 22.225C24.3639 21.8361 23.6102 21.5347 22.8223 21.3208C22.0352 21.1069 21.2333 21 20.4167 21C19.25 21 18.1222 21.2041 17.0333 21.6125C15.9445 22.0208 14.9333 22.5944 14 23.3333Z"
fill="#2C323E"
/>
</SvgIcon>
);
109 changes: 109 additions & 0 deletions ui/src/pages/help-center/HelpCenter.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { HelpCardType } from './help-center-card/HelpCenterCard.types';

export const CARD_IDS = {
pmmDocs: 'pmm-docs',
support: 'support',
forum: 'forum',
pmmDump: 'pmm-dump',
pmmLogs: 'pmm-logs',
tips: 'tips',
};

export const START_ICON = {
download: 'download',
map: 'map',
};

export const CARDS_DATA: HelpCardType[] = [
{
id: CARD_IDS.pmmDocs,
title: 'PMM Documentation',
description:
'From setup to troubleshooting, you’ll find step-by-step instructions, tips, and best practices to get the most out of PMM.',
buttons: [
{
text: 'View docs',
target: '_blank',
url: 'https://per.co.na/pmm_documentation',
},
],
adminOnly: false,
borderColor: '#1486FF',
},
{
id: CARD_IDS.support,
title: 'Get Percona Support',
description:
'From 24/7 technical support to fully managed services, Percona’s trusted experts are ready to help you optimize, troubleshoot, and scale.',
buttons: [
{
text: 'Contact Support',
target: '_blank',
url: 'https://per.co.na/pmm_support',
},
],
adminOnly: false,
borderColor: '#F24500',
},
{
id: CARD_IDS.forum,
title: 'Percona Forum',
description:
'A friendly space to connect with other users, share insights, and get answers from the community and from the Percona experts.',
buttons: [
{
text: 'View forum',
target: '_blank',
url: 'https://per.co.na/PMM3_forum',
},
],
adminOnly: false,
borderColor: '#30D1B2',
},
{
id: CARD_IDS.pmmDump,
title: 'PMM Dump',
description:
'Generate datasets to securely share your data with Percona Support. This helps our experts quickly diagnose and replicate issues.',
buttons: [
{
text: 'Manage datasets',
url: '/graph/pmm-dump',
},
],
adminOnly: true,
borderColor: '#F0B336',
},
{
id: CARD_IDS.pmmLogs,
title: 'PMM Logs',
description:
'Download your PMM logs as a ZIP file for easy sharing and faster issue diagnosis.',
buttons: [
{
text: 'Export logs',
target: '_blank',
url: '/logs.zip',
startIconName: START_ICON.download,
},
],
adminOnly: true,
},
{
id: CARD_IDS.tips,
title: 'Useful Tips',
description:
'Need a refresher? Access the onboarding tour tips or the keyboard shortcuts.',
adminOnly: false,
buttons: [
{
text: 'Start PMM tour',
startIconName: START_ICON.map,
},
{
text: 'Shortcuts',
url: 'https://per.co.na/pmm_documentation',
},
],
},
];
3 changes: 3 additions & 0 deletions ui/src/pages/help-center/HelpCenter.messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Messages = {
pageTitle: 'Help Center',
};
95 changes: 95 additions & 0 deletions ui/src/pages/help-center/HelpCenter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { render, screen } from '@testing-library/react';
import { HelpCenter } from './HelpCenter';
import { CARD_IDS } from './HelpCenter.constants';
import * as useUserModule from 'contexts/user';
import { OrgRole } from 'types/user.types';

describe('HelpCenter', () => {
it('should show pmm dump and pmm logs if user is admin', () => {
vi.spyOn(useUserModule, 'useUser').mockReturnValue({
isLoading: false,
user: {
id: 1,
isPMMAdmin: true,
orgRole: OrgRole.Admin,
isAuthorized: true,
},
});

render(<HelpCenter />);

expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmDump}`)
).toBeInTheDocument();
expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmLogs}`)
).toBeInTheDocument();
expect(screen.queryAllByTestId(/^help-card-/).length).toEqual(6);
});

it('should not show pmm dump and pmm logs if user has no org role', () => {
vi.spyOn(useUserModule, 'useUser').mockReturnValue({
isLoading: false,
user: {
id: 1,
isPMMAdmin: false,
orgRole: OrgRole.None,
isAuthorized: true,
},
});

render(<HelpCenter />);

expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmDump}`)
).not.toBeInTheDocument();
expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmLogs}`)
).not.toBeInTheDocument();
expect(screen.queryAllByTestId(/^help-card-/).length).toEqual(4);
});

it('should not show pmm dump and pmm logs if user is viewer', () => {
vi.spyOn(useUserModule, 'useUser').mockReturnValue({
isLoading: false,
user: {
id: 1,
isPMMAdmin: false,
orgRole: OrgRole.Viewer,
isAuthorized: true,
},
});

render(<HelpCenter />);

expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmDump}`)
).not.toBeInTheDocument();
expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmLogs}`)
).not.toBeInTheDocument();
expect(screen.queryAllByTestId(/^help-card-/).length).toEqual(4);
});

it('should not show pmm dump and pmm logs if user is editor', () => {
vi.spyOn(useUserModule, 'useUser').mockReturnValue({
isLoading: false,
user: {
id: 1,
isPMMAdmin: false,
orgRole: OrgRole.Editor,
isAuthorized: true,
},
});

render(<HelpCenter />);

expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmDump}`)
).not.toBeInTheDocument();
expect(
screen.queryByTestId(`help-card-${CARD_IDS.pmmLogs}`)
).not.toBeInTheDocument();
expect(screen.queryAllByTestId(/^help-card-/).length).toEqual(4);
});
});
35 changes: 35 additions & 0 deletions ui/src/pages/help-center/HelpCenter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Box } from '@mui/material';
import { Page } from 'components/page';
import { FC } from 'react';
import { Messages } from './HelpCenter.messages';
import { CARDS_DATA } from './HelpCenter.constants';
import { useUser } from 'contexts/user';
import { HelpCenterCard } from './help-center-card/HelpCenterCard';

export const HelpCenter: FC = () => {
const { user } = useUser();

const cards = CARDS_DATA.filter(
(card) => user?.isPMMAdmin || !card.adminOnly
);

return (
<Page title={Messages.pageTitle}>
<Box
sx={{
display: 'grid',
gridTemplateColumns: {
xs: '1fr',
sm: '1fr',
md: 'repeat(2, 1fr)',
},
gap: 4,
}}
>
{cards.map((item) => (
<HelpCenterCard card={item} />
))}
</Box>
</Page>
);
};
94 changes: 94 additions & 0 deletions ui/src/pages/help-center/help-center-card/HelpCenterCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Button, CardContent, Typography, Card, Stack } from '@mui/material';
import {
Support,
ForumOutlined,
DatasetOutlined,
NorthEast,
SaveAlt,
MapOutlined,
} from '@mui/icons-material';
import { KnowledgeBaseIcon } from 'icons';
import { FC, ReactNode, useCallback } from 'react';
import { CARD_IDS, START_ICON } from '../HelpCenter.constants';
import { HelpCenterCardProps, HelpCardButton } from './HelpCenterCard.types';

export const HelpCenterCard: FC<HelpCenterCardProps> = ({ card }) => {
const { id, title, borderColor, description, buttons } = card;

const getIcon = useCallback((cardId: string): ReactNode => {
switch (cardId) {
case CARD_IDS.pmmDocs:
return <KnowledgeBaseIcon />;
case CARD_IDS.support:
return <Support />;
case CARD_IDS.forum:
return <ForumOutlined />;
case CARD_IDS.pmmDump:
return <DatasetOutlined />;
default:
return null;
}
}, []);

const getButtonStartIcon = useCallback((iconName?: string): ReactNode => {
switch (iconName) {
case START_ICON.download:
return <SaveAlt />;
case START_ICON.map:
return <MapOutlined />;
default:
return null;
}
}, []);

const onButtonClick = useCallback((button: HelpCardButton) => {
if (button.target) {
window.open(button.url, button.target, 'noopener,noreferrer');
} else {
//TO DO: use react router once the grafana iframe is in place
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please write todo comments as // TODO: ... to keep consistency.

button.url && window.location.assign(button.url);
}
}, []);

return (
<Card
sx={{
borderTop: borderColor ? `solid 12px ${borderColor}` : 'none',
}}
key={id}
data-testid={`help-card-${id}`}
>
<CardContent sx={{ px: 2 }}>
<Stack
flexDirection="row"
justifyContent="flex-start"
alignItems="center"
marginBottom={1}
>
{getIcon(id)}
<Typography variant="h6" sx={{ ml: getIcon(id) ? 1 : 0 }}>
{title}
</Typography>
</Stack>

<Typography>{description}</Typography>
<Stack paddingTop={2} flexDirection="row">
{buttons.map((button) => (
<Button
key={button.url}
variant="outlined"
component="a"
size="small"
sx={{ mr: 1 }}
startIcon={getButtonStartIcon(button.startIconName)}
endIcon={button.target && <NorthEast />}
onClick={() => onButtonClick(button)}
>
{button.text}
</Button>
))}
</Stack>
</CardContent>
</Card>
);
};
Loading
Loading