Skip to content

Commit

Permalink
PMM-12930 Update status, log & clients (#3039)
Browse files Browse the repository at this point in the history
* PMM-11231 Setup PMM UI

* PMM-11231 Update working directory for node setup

* PMM-11231 Adjust setup node step

* PMM-11231 Add build & cleanup makefile

* PMM-11231 Use correct UI directory

* PMM-11231 Adjust pmm-ui build directory

* PMM-11231 Add install commands

* PMM-11231 Add pmm ui directory to files section

* PMM-11231 Copy correct build files

* PMM-11231 Handle token rotation

* PMM-11231 Simplify spec file

* PMM-11231 Update dependencies

* PMM-11231 Allow use of eslints non flat config

* PMM-11231 Align version fetch logic with previous

* PMM-11231 Refactor fetching icon

* PMM-11231 Update compose file

* PMM-11231 Use /pmm-ui as path

* PMM-11231 Allow specifying pmm server image through env variable

* PMM-12930 Show update status

* PMM-11231 Switch to tanstack query

* PMM-12930 Fix lint

* PMM-11231 Update dev configuration

* PMM-11231 Use correct naming & switch to hooks

* PMM-11231 Use different name for update image

* PMM-12930 Improve update process

* PMM-11231 Disable auth_request for pmm-ui

* PMM-11231 Rework redirect to login

* PMM-11231 Update api response

* PMM-11231 Add link to support

* PMM-11231 Fix support url redirect

* PMM-11231 Fix lint

* PMM-11231 Fix typings

* PMM-12930 Fix version typings

* PMM-11231 Add admin & auth check

* PMM-12930 Make page component responsive

* PMM-12930 Add Page unit tests

* PMM-12930 Make page component responsive

* PMM-12930 Add Page unit tests

* PMM-11231 Update api endpoints

* PMM-12930 Add upgrade docs link

* PMM-12930 Update types & readyz url

* PMM-12930 Remove temporary error handling

* PMM-12930 Add footer

* PMM-12930 Refactor footer

* PMM-12930 Refactor user context imports

* PMM-12930 Add doc comnent

* PMM-12930 Update progress bar color

* PMM-12930 Update progress bar

* PMM-12930 Bump packages

* PMM-12930 Fix updates check

* PMM-12934 Add page for client updates

* PMM-12934 Extend page & remove mocks

* PMM-12934 Update table loading

* PMM-12934 Use custom filter component

* PMM-12933 Add update log modal

* PMM-12934 Add next button

* PMM-12930 Add unit tests

* PMM-12930 Downgrade eslint version

* PMM-12934 Add check for pending client update

* PMM-12934 Adjust styling

* PMM-12930 Fix before CR

* PMM-12930 Remove empty file

* PMM-12930 Simplify initial auth check

* PMM-12930 Make appbar sticky

* PMM-12930 Fix font loading

* PMM-12930 Adjust section spacing

* PMM-12930 Bump axios version

* PMM-7 fix proto validation error

* PMM-12930 Use table from ui-lib

* PMM-12930 Update dev nginx file

* PMM-12930 Use shortened links

* PMM-12930 Add pmm home button, rework dialog & add test

* PMM-12930 Improve clients update check

* PMM-12930 Highligh only Release Notes
  • Loading branch information
matejkubinec authored Oct 21, 2024
1 parent 6a67936 commit 8fe0d76
Show file tree
Hide file tree
Showing 88 changed files with 2,534 additions and 966 deletions.
25 changes: 16 additions & 9 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"format": "prettier . --write",
"preview": "vite preview",
"test": "vitest run",
Expand All @@ -15,13 +15,16 @@
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/poppins": "^5.0.15",
"@fontsource/roboto": "^5.0.14",
"@fontsource/roboto-mono": "^5.0.18",
"@mui/icons-material": "^5.15.18",
"@mui/material": "^5.15.18",
"@mui/x-date-pickers": "^7.5.0",
"@percona/design": "^1.0.0",
"@percona/ui-lib": "^1.0.0",
"@tanstack/react-query": "^5.45.1",
"axios": "^1.7.0",
"axios": "^1.7.4",
"axios-case-converter": "^1.1.1",
"date-fns": "^2.30.0",
"react": "^18.3.1",
Expand All @@ -32,23 +35,27 @@
"@percona/eslint-config-react": "^1.0.0",
"@percona/prettier-config": "^1.0.0",
"@percona/tsconfig": "^1.0.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^15.0.7",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"@vitejs/plugin-react-swc": "^3.6.0",
"eslint": "^9.3.0",
"@vitejs/plugin-react-swc": "^3.7.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"jsdom": "^24.0.0",
"jsdom": "^24.1.1",
"prettier": "^3.2.5",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite": "^5.3.5",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0"
"vitest": "^2.0.5"
},
"resolutions": {
"braces": "^3.0.3",
"vite": "^5.3.5"
},
"prettier": "@percona/prettier-config"
}
}
3 changes: 3 additions & 0 deletions ui/pmm-dev.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# duplicate so http_host is correctly set
rewrite ^/$ $scheme://$http_host/graph/;
}
}
7 changes: 5 additions & 2 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { NotistackMuiSnackbar } from '@percona/ui-lib';
import { SnackbarProvider } from 'notistack';
import pmmThemeOptions from 'themes/PmmTheme';
import { AuthProvider } from 'contexts/auth';
import { UserProvider } from 'contexts/user/user.provider';
import { UserProvider } from 'contexts/user';
import { UpdatesProvider } from 'contexts/updates';

const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -39,7 +40,9 @@ const App = () => (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<UserProvider>
<RouterProvider router={router} />
<UpdatesProvider>
<RouterProvider router={router} />
</UpdatesProvider>
</UserProvider>
</AuthProvider>
</QueryClientProvider>
Expand Down
10 changes: 10 additions & 0 deletions ui/src/api/__mocks__/agents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { AgentUpdateSeverity, GetAgentVersionItem } from 'types/agent.types';

export const getAgentVersions = async (): Promise<GetAgentVersionItem[]> => [
{
agentId: 'pmm-server',
version: '3.0.0',
nodeName: 'pmm-server',
severity: AgentUpdateSeverity.UP_TO_DATE,
},
];
9 changes: 9 additions & 0 deletions ui/src/api/agents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { GetAgentVersionsResponse } from 'types/agent.types';
import { api } from './api';

export const getAgentVersions = async () => {
const res = await api.get<GetAgentVersionsResponse>(
'/management/agents/versions'
);
return res.data.agentVersions;
};
6 changes: 6 additions & 0 deletions ui/src/api/ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { api } from './api';

export const getReadiness = async () => {
const res = await api.get<Record<string, never>>('/server/readyz');
return res.data;
};
11 changes: 6 additions & 5 deletions ui/src/api/updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
GetUpdateStatusResponse,
GetUpdatesParams,
GetUpdatesResponse,
StartUpdateBody,
StartUpdateResponse,
} from 'types/updates.types';
import { api } from './api';
Expand All @@ -17,11 +18,11 @@ export const checkForUpdates = async (
return res.data;
};

export const startUpdate = async () => {
const res = await api.post<object, AxiosResponse<StartUpdateResponse>>(
'/server/updates:start',
{}
);
export const startUpdate = async (body: StartUpdateBody) => {
const res = await api.post<
StartUpdateBody,
AxiosResponse<StartUpdateResponse>
>('/server/updates:start', body);
return res.data;
};

Expand Down
16 changes: 8 additions & 8 deletions ui/src/components/app-bar/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ import {
} from '@mui/material';
import { HelpFilledIcon, PmmRoundedIcon } from 'icons';
import { Breadcrumbs } from 'components/breadcrumbs';
import { PMM_HOME_URL, PMM_SUPPORT_URL } from 'constants';
import { PMM_SUPPORT_URL } from 'constants';
import { Messages } from './AppBar.messages';
import { HomeLink } from 'components/home-link';

export const AppBar = () => (
<MuiAppBar position="static" color="primary">
<MuiAppBar position="sticky" color="primary">
<Toolbar>
<Link
href={PMM_HOME_URL}
<HomeLink
color="inherit"
underline="hover"
sx={(theme) => ({
marginRight: theme.spacing(2),
})}
sx={{
mr: 2,
}}
data-testid="appbar-pmm-link"
>
<Stack gap={1} direction="row" alignItems="center">
<PmmRoundedIcon sx={{ height: '40px', width: 'auto' }} />
<Typography>{Messages.title}</Typography>
</Stack>
</Link>
</HomeLink>
<Breadcrumbs />
<Box sx={{ ml: 'auto' }}>
<Link
Expand Down
6 changes: 3 additions & 3 deletions ui/src/components/breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
} from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import { KeyboardArrowRight } from '@mui/icons-material';
import { PMM_HOME_URL } from 'constants';
import { Messages } from './Breadcrumbs.messages';
import { HomeLink } from 'components/home-link';

export const Breadcrumbs: FC = () => {
const theme = useTheme();
Expand All @@ -19,9 +19,9 @@ export const Breadcrumbs: FC = () => {
color="text"
separator={<KeyboardArrowRight fontSize="small" />}
>
<Link underline="hover" color="inherit" href={PMM_HOME_URL}>
<HomeLink underline="hover" color="inherit">
{Messages.home}
</Link>
</HomeLink>
<Link
underline="hover"
component={RouterLink}
Expand Down
5 changes: 5 additions & 0 deletions ui/src/components/footer/Footer.messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Messages = {
version: (version: string) => `PMM ${version}`,
inProgress: 'Update in progress...',
checkedOn: (date: string) => `Checked on: ${date}`,
};
32 changes: 32 additions & 0 deletions ui/src/components/footer/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { screen, render } from '@testing-library/react';
import { Footer } from './Footer';
import { Messages } from './Footer.messages';
import { wrapWithUpdatesProvider } from 'utils/testUtils';

describe('Footer', () => {
it("doesnt't show when version info is not available", () => {
render(
wrapWithUpdatesProvider(<Footer />, {
versionInfo: undefined,
})
);

expect(screen.queryByTestId('pmm-footer')).toBeNull();
});

it('shows correct checked date', () => {
render(wrapWithUpdatesProvider(<Footer />));

expect('Checked on: 2024/07/30');
});

it('shows in progress message', () => {
render(
wrapWithUpdatesProvider(<Footer />, {
inProgress: true,
})
);

expect(screen.getByText(Messages.inProgress));
});
});
24 changes: 24 additions & 0 deletions ui/src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Stack, Typography } from '@mui/material';
import { useUpdates } from 'contexts/updates';
import { FC } from 'react';
import { formatCheckDate } from './Footer.utils';
import { Messages } from './Footer.messages';

export const Footer: FC = () => {
const { inProgress, versionInfo } = useUpdates();

if (!versionInfo) return null;

return (
<Stack direction="row" gap={2} data-testid="pmm-footer">
<Typography variant="body2">
{Messages.version(versionInfo.installed.version)}
</Typography>
<Typography variant="body2" color="text.disabled">
{inProgress
? Messages.inProgress
: Messages.checkedOn(formatCheckDate(versionInfo.lastCheck))}
</Typography>
</Stack>
);
};
7 changes: 7 additions & 0 deletions ui/src/components/footer/Footer.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Formats date to YYYY/MM/DD
* @param date
* @returns formatted date
*/
export const formatCheckDate = (date: string) =>
new Date(date).toISOString().slice(0, 10).replace(/-/g, '/');
1 change: 1 addition & 0 deletions ui/src/components/footer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Footer';
66 changes: 66 additions & 0 deletions ui/src/components/home-link/HomeLink.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { wrapWithUpdatesProvider } from 'utils/testUtils';
import { HomeLink } from './HomeLink';
import { fireEvent, render, screen } from '@testing-library/react';
import { UpdateStatus } from 'types/updates.types';
import { PMM_HOME_URL } from 'constants';
import { MemoryRouter } from 'react-router-dom';

describe('HomeLink', () => {
it('navigates to PMM Home if client update is not pending', () => {
render(
wrapWithUpdatesProvider(
<MemoryRouter initialEntries={[{ pathname: '/updates/clients' }]}>
<HomeLink data-testid="home-link" />
</MemoryRouter>,
{
status: UpdateStatus.UpToDate,
}
)
);

expect(screen.getByTestId('home-link')).toHaveAttribute(
'href',
PMM_HOME_URL
);
});

it('shows modal if client update is pending', () => {
render(
wrapWithUpdatesProvider(
<MemoryRouter initialEntries={[{ pathname: '/updates/clients' }]}>
<HomeLink data-testid="home-link" />
</MemoryRouter>,
{
status: UpdateStatus.UpdateClients,
areClientsUpToDate: false,
}
)
);
const homeLink = screen.getByTestId('home-link');

expect(homeLink).not.toHaveAttribute('href', PMM_HOME_URL);

fireEvent.click(homeLink);

expect(screen.getByTestId('modal-clients-update-pending')).toBeDefined();
});

it("doesn't propmt on pages other than client updates", () => {
render(
wrapWithUpdatesProvider(
<MemoryRouter initialEntries={[{ pathname: '/updates' }]}>
<HomeLink data-testid="home-link" />
</MemoryRouter>,
{
status: UpdateStatus.UpdateClients,
areClientsUpToDate: false,
}
)
);

expect(screen.getByTestId('home-link')).toHaveAttribute(
'href',
PMM_HOME_URL
);
});
});
39 changes: 39 additions & 0 deletions ui/src/components/home-link/HomeLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Link, LinkProps } from '@mui/material';
import { PMM_HOME_URL } from 'constants';
import { useUpdates } from 'contexts/updates';
import { FC, useMemo, useState } from 'react';
import { UpdateStatus } from 'types/updates.types';
import { ClientsModal } from './clients-modal';
import { useLocation } from 'react-router-dom';

export const HomeLink: FC<LinkProps> = ({ children, sx, ...props }) => {
const { status, areClientsUpToDate } = useUpdates();
const [modalOpen, setModalOpen] = useState(false);
const location = useLocation();
const isOnClientsPage = useMemo(
() => location.pathname.startsWith('/updates/clients'),
[location]
);
const homeLinkProps =
(status === UpdateStatus.UpdateClients || !areClientsUpToDate) &&
isOnClientsPage
? {
onClick: () => setModalOpen(true),
}
: {
href: PMM_HOME_URL,
};

return (
<>
<ClientsModal isOpen={modalOpen} onClose={() => setModalOpen(false)} />
<Link
{...props}
sx={[{ cursor: 'pointer ' }, ...(Array.isArray(sx) ? sx : [sx])]}
{...homeLinkProps}
>
{children}
</Link>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const Messages = {
title: 'PMM has not finished updating',
description1:
'One or more PMM Client instances are not updated yet and will remain in an outdated version.',
description2:
'If you exit now you will not take advatages of the newest fixes, improvements and features.',
close: 'Close window',
home: 'Go to PMM Home',
};
Loading

0 comments on commit 8fe0d76

Please sign in to comment.