From f1fff4ca0c5dca2316c64d480f6bd4a92efac900 Mon Sep 17 00:00:00 2001 From: Mustajab Ikram Date: Wed, 2 Aug 2023 15:14:15 +0530 Subject: [PATCH] feat: show page name in document title using React Helmet (#3229) * feat: show page name in document title using React Helmet * fix: add translation support for page titles * feat: title is updated --------- Co-authored-by: Palash Gupta --- frontend/package.json | 2 ++ frontend/public/locales/en-GB/titles.json | 36 ++++++++++++++++++++++ frontend/public/locales/en/titles.json | 36 ++++++++++++++++++++++ frontend/src/container/AppLayout/index.tsx | 13 ++++++-- frontend/src/container/AppLayout/utils.ts | 9 ++++++ frontend/src/index.tsx | 23 ++++++++------ frontend/yarn.lock | 32 ++++++++++++++++++- 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 frontend/public/locales/en-GB/titles.json create mode 100644 frontend/public/locales/en/titles.json create mode 100644 frontend/src/container/AppLayout/utils.ts diff --git a/frontend/package.json b/frontend/package.json index daad1b8269..174fab4073 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -76,6 +76,7 @@ "react-drag-listview": "2.0.0", "react-force-graph": "^1.41.0", "react-grid-layout": "^1.3.4", + "react-helmet-async": "1.3.0", "react-i18next": "^11.16.1", "react-intersection-observer": "9.4.1", "react-query": "^3.34.19", @@ -140,6 +141,7 @@ "@types/react-addons-update": "0.14.21", "@types/react-dom": "18.0.10", "@types/react-grid-layout": "^1.1.2", + "@types/react-helmet-async": "1.0.3", "@types/react-redux": "^7.1.11", "@types/react-resizable": "3.0.3", "@types/react-router-dom": "^5.1.6", diff --git a/frontend/public/locales/en-GB/titles.json b/frontend/public/locales/en-GB/titles.json new file mode 100644 index 0000000000..53ac325f11 --- /dev/null +++ b/frontend/public/locales/en-GB/titles.json @@ -0,0 +1,36 @@ +{ + "SIGN_UP": "SigNoz | Sign Up", + "LOGIN": "SigNoz | Login", + "SERVICE_METRICS": "SigNoz | Service Metrics", + "SERVICE_MAP": "SigNoz | Service Map", + "TRACE": "SigNoz | Trace", + "TRACE_DETAIL": "SigNoz | Trace Detail", + "TRACES_EXPLORER": "SigNoz | Traces Explorer", + "SETTINGS": "SigNoz | Settings", + "INSTRUMENTATION": "SigNoz | Get Started", + "USAGE_EXPLORER": "SigNoz | Usage Explorer", + "APPLICATION": "SigNoz | Home", + "ALL_DASHBOARD": "SigNoz | All Dashboards", + "DASHBOARD": "SigNoz | Dashboard", + "DASHBOARD_WIDGET": "SigNoz | Dashboard Widget", + "EDIT_ALERTS": "SigNoz | Edit Alerts", + "LIST_ALL_ALERT": "SigNoz | All Alerts", + "ALERTS_NEW": "SigNoz | New Alert", + "ALL_CHANNELS": "SigNoz | All Channels", + "CHANNELS_NEW": "SigNoz | New Channel", + "CHANNELS_EDIT": "SigNoz | Edit Channel", + "ALL_ERROR": "SigNoz | All Errors", + "ERROR_DETAIL": "SigNoz | Error Detail", + "VERSION": "SigNoz | Version", + "MY_SETTINGS": "SigNoz | My Settings", + "ORG_SETTINGS": "SigNoz | Organization Settings", + "SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong", + "UN_AUTHORIZED": "SigNoz | Unauthorized", + "NOT_FOUND": "SigNoz | Page Not Found", + "LOGS": "SigNoz | Logs", + "LOGS_EXPLORER": "SigNoz | Logs Explorer", + "HOME_PAGE": "Open source Observability Platform | SigNoz", + "PASSWORD_RESET": "SigNoz | Password Reset", + "LIST_LICENSES": "SigNoz | List of Licenses", + "DEFAULT": "Open source Observability Platform | SigNoz" +} diff --git a/frontend/public/locales/en/titles.json b/frontend/public/locales/en/titles.json new file mode 100644 index 0000000000..53ac325f11 --- /dev/null +++ b/frontend/public/locales/en/titles.json @@ -0,0 +1,36 @@ +{ + "SIGN_UP": "SigNoz | Sign Up", + "LOGIN": "SigNoz | Login", + "SERVICE_METRICS": "SigNoz | Service Metrics", + "SERVICE_MAP": "SigNoz | Service Map", + "TRACE": "SigNoz | Trace", + "TRACE_DETAIL": "SigNoz | Trace Detail", + "TRACES_EXPLORER": "SigNoz | Traces Explorer", + "SETTINGS": "SigNoz | Settings", + "INSTRUMENTATION": "SigNoz | Get Started", + "USAGE_EXPLORER": "SigNoz | Usage Explorer", + "APPLICATION": "SigNoz | Home", + "ALL_DASHBOARD": "SigNoz | All Dashboards", + "DASHBOARD": "SigNoz | Dashboard", + "DASHBOARD_WIDGET": "SigNoz | Dashboard Widget", + "EDIT_ALERTS": "SigNoz | Edit Alerts", + "LIST_ALL_ALERT": "SigNoz | All Alerts", + "ALERTS_NEW": "SigNoz | New Alert", + "ALL_CHANNELS": "SigNoz | All Channels", + "CHANNELS_NEW": "SigNoz | New Channel", + "CHANNELS_EDIT": "SigNoz | Edit Channel", + "ALL_ERROR": "SigNoz | All Errors", + "ERROR_DETAIL": "SigNoz | Error Detail", + "VERSION": "SigNoz | Version", + "MY_SETTINGS": "SigNoz | My Settings", + "ORG_SETTINGS": "SigNoz | Organization Settings", + "SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong", + "UN_AUTHORIZED": "SigNoz | Unauthorized", + "NOT_FOUND": "SigNoz | Page Not Found", + "LOGS": "SigNoz | Logs", + "LOGS_EXPLORER": "SigNoz | Logs Explorer", + "HOME_PAGE": "Open source Observability Platform | SigNoz", + "PASSWORD_RESET": "SigNoz | Password Reset", + "LIST_LICENSES": "SigNoz | List of Licenses", + "DEFAULT": "Open source Observability Platform | SigNoz" +} diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index b127d6c429..7574e59143 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -6,7 +6,8 @@ import Header from 'container/Header'; import SideNav from 'container/SideNav'; import TopNav from 'container/TopNav'; import { useNotifications } from 'hooks/useNotifications'; -import { ReactNode, useEffect, useRef } from 'react'; +import { ReactNode, useEffect, useMemo, useRef } from 'react'; +import { Helmet } from 'react-helmet-async'; import { useTranslation } from 'react-i18next'; import { useQueries } from 'react-query'; import { useDispatch, useSelector } from 'react-redux'; @@ -25,13 +26,14 @@ import { import AppReducer from 'types/reducer/app'; import { ChildrenContainer, Layout } from './styles'; +import { getRouteKey } from './utils'; function AppLayout(props: AppLayoutProps): JSX.Element { const { isLoggedIn, user } = useSelector( (state) => state.app, ); const { pathname } = useLocation(); - const { t } = useTranslation(); + const { t } = useTranslation(['titles']); const [ getUserVersionResponse, @@ -226,8 +228,15 @@ function AppLayout(props: AppLayoutProps): JSX.Element { const isToDisplayLayout = isLoggedIn; + const routeKey = useMemo(() => getRouteKey(pathname), [pathname]); + const pageTitle = t(routeKey); + return ( + + {pageTitle} + + {isToDisplayLayout &&
} {isToDisplayLayout && } diff --git a/frontend/src/container/AppLayout/utils.ts b/frontend/src/container/AppLayout/utils.ts new file mode 100644 index 0000000000..649dcc46fc --- /dev/null +++ b/frontend/src/container/AppLayout/utils.ts @@ -0,0 +1,9 @@ +import ROUTES from 'constants/routes'; + +export function getRouteKey(pathname: string): string { + const [routeKey] = Object.entries(ROUTES).find( + ([, value]) => value === pathname, + ) || ['DEFAULT']; + + return routeKey; +} diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index d7985e8dc6..049c0a4c0e 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -4,6 +4,7 @@ import './ReactI18'; import AppRoutes from 'AppRoutes'; import { ThemeProvider } from 'hooks/useDarkMode'; import { createRoot } from 'react-dom/client'; +import { HelmetProvider } from 'react-helmet-async'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; import { Provider } from 'react-redux'; @@ -28,15 +29,17 @@ if (container) { const root = createRoot(container); root.render( - - - - - - {process.env.NODE_ENV === 'development' && ( - - )} - - , + + + + + + + {process.env.NODE_ENV === 'development' && ( + + )} + + + , ); } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 769b65d920..a0cf548284 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2350,6 +2350,13 @@ dependencies: "@types/react" "*" +"@types/react-helmet-async@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/react-helmet-async/-/react-helmet-async-1.0.3.tgz#89d581d6cb129e5357d39d7d1b41313b20523989" + integrity sha512-DqbSuZPSHiH1l3XI/y8LbhrAGNh+Bpc9QY4MsYRM1yD4+qhax8bN4DInUMpv/tNyIdjsa+1V8XXmbRx8W5dB0w== + dependencies: + react-helmet-async "*" + "@types/react-redux@^7.1.11", "@types/react-redux@^7.1.20": version "7.1.25" resolved "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz" @@ -7038,6 +7045,13 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" @@ -8528,7 +8542,7 @@ loglevelnext@^3.0.1: resolved "https://registry.npmjs.org/loglevelnext/-/loglevelnext-3.0.1.tgz" integrity sha512-JpjaJhIN1reaSb26SIxDGtE0uc67gPl19OMVHrr+Ggt6b/Vy60jmCtKgQBrygAH0bhRA2nkxgDvM+8QvR8r0YA== -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -10612,6 +10626,11 @@ react-draggable@^4.0.0, react-draggable@^4.0.3: clsx "^1.1.1" prop-types "^15.8.1" +react-fast-compare@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== + react-force-graph@^1.41.0: version "1.42.2" resolved "https://registry.npmjs.org/react-force-graph/-/react-force-graph-1.42.2.tgz" @@ -10635,6 +10654,17 @@ react-grid-layout@^1.3.4: react-draggable "^4.0.0" react-resizable "^3.0.4" +react-helmet-async@*, react-helmet-async@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.3.0.tgz#7bd5bf8c5c69ea9f02f6083f14ce33ef545c222e" + integrity sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg== + dependencies: + "@babel/runtime" "^7.12.5" + invariant "^2.2.4" + prop-types "^15.7.2" + react-fast-compare "^3.2.0" + shallowequal "^1.1.0" + react-hooks-testing-library@0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/react-hooks-testing-library/-/react-hooks-testing-library-0.6.0.tgz"