diff --git a/ui/package.json b/ui/package.json index 29e4248d44..fa5581d694 100644 --- a/ui/package.json +++ b/ui/package.json @@ -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", @@ -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", @@ -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" -} +} \ No newline at end of file diff --git a/ui/pmm-dev.conf b/ui/pmm-dev.conf index 47a5af63dc..5e5f8b6b7d 100644 --- a/ui/pmm-dev.conf +++ b/ui/pmm-dev.conf @@ -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/; } } diff --git a/ui/src/App.tsx b/ui/src/App.tsx index bd4f98d963..ac7b3a7cef 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -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: { @@ -39,7 +40,9 @@ const App = () => ( - + + + diff --git a/ui/src/api/__mocks__/agents.ts b/ui/src/api/__mocks__/agents.ts new file mode 100644 index 0000000000..ec3d950fef --- /dev/null +++ b/ui/src/api/__mocks__/agents.ts @@ -0,0 +1,10 @@ +import { AgentUpdateSeverity, GetAgentVersionItem } from 'types/agent.types'; + +export const getAgentVersions = async (): Promise => [ + { + agentId: 'pmm-server', + version: '3.0.0', + nodeName: 'pmm-server', + severity: AgentUpdateSeverity.UP_TO_DATE, + }, +]; diff --git a/ui/src/api/agents.ts b/ui/src/api/agents.ts new file mode 100644 index 0000000000..74b7ebcfff --- /dev/null +++ b/ui/src/api/agents.ts @@ -0,0 +1,9 @@ +import { GetAgentVersionsResponse } from 'types/agent.types'; +import { api } from './api'; + +export const getAgentVersions = async () => { + const res = await api.get( + '/management/agents/versions' + ); + return res.data.agentVersions; +}; diff --git a/ui/src/api/ready.ts b/ui/src/api/ready.ts new file mode 100644 index 0000000000..7d40dfa3ce --- /dev/null +++ b/ui/src/api/ready.ts @@ -0,0 +1,6 @@ +import { api } from './api'; + +export const getReadiness = async () => { + const res = await api.get>('/server/readyz'); + return res.data; +}; diff --git a/ui/src/api/updates.ts b/ui/src/api/updates.ts index 14ab16216d..db6c3d05d9 100644 --- a/ui/src/api/updates.ts +++ b/ui/src/api/updates.ts @@ -4,6 +4,7 @@ import { GetUpdateStatusResponse, GetUpdatesParams, GetUpdatesResponse, + StartUpdateBody, StartUpdateResponse, } from 'types/updates.types'; import { api } from './api'; @@ -17,11 +18,11 @@ export const checkForUpdates = async ( return res.data; }; -export const startUpdate = async () => { - const res = await api.post>( - '/server/updates:start', - {} - ); +export const startUpdate = async (body: StartUpdateBody) => { + const res = await api.post< + StartUpdateBody, + AxiosResponse + >('/server/updates:start', body); return res.data; }; diff --git a/ui/src/components/app-bar/AppBar.tsx b/ui/src/components/app-bar/AppBar.tsx index 333329fc25..29717712da 100644 --- a/ui/src/components/app-bar/AppBar.tsx +++ b/ui/src/components/app-bar/AppBar.tsx @@ -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 = () => ( - + - ({ - marginRight: theme.spacing(2), - })} + sx={{ + mr: 2, + }} data-testid="appbar-pmm-link" > {Messages.title} - + { const theme = useTheme(); @@ -19,9 +19,9 @@ export const Breadcrumbs: FC = () => { color="text" separator={} > - + {Messages.home} - + `PMM ${version}`, + inProgress: 'Update in progress...', + checkedOn: (date: string) => `Checked on: ${date}`, +}; diff --git a/ui/src/components/footer/Footer.test.tsx b/ui/src/components/footer/Footer.test.tsx new file mode 100644 index 0000000000..a9073e66cf --- /dev/null +++ b/ui/src/components/footer/Footer.test.tsx @@ -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(