Enable rum for good

This commit is contained in:
Arthur Belleville 2025-07-17 09:26:08 +02:00
parent 9302a940a0
commit af75776dae
No known key found for this signature in database
4 changed files with 217 additions and 104 deletions

View file

@ -1,124 +1,49 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { LoginPage } from "@ui/pages/login";
import { SignUpPage } from "@ui/pages/signup";
import { BrowserRouter as Router, useRoutes } from "react-router-dom";
import { ThemeProvider } from "@ui/contexts/ThemeContext";
import { twMerge } from "tailwind-merge";
import { ResetPasswordPage } from "@ui/pages/reset-password";
import { LandingPage } from "@ui/pages/landing";
import { PublicRoute } from "@ui/components/PublicRoute";
import { TabloPage } from "@ui/pages/tablo";
import { SessionProvider } from "@ui/contexts/SessionContext";
import { OAuthSigninPage } from "@ui/pages/oauth-signin";
import { NotFoundPage } from "@ui/pages/NotFoundPage";
import { Layout } from "@ui/components/Layout";
import { DevisPage } from "@ui/pages/devis";
import { FacturesPage } from "@ui/pages/factures";
import { PlanningPage } from "@ui/pages/planning";
import { ChantiersPage } from "@ui/pages/chantiers";
import { ChatPage } from "@ui/pages/chat";
import { FeedbackPage } from "@ui/pages/feedback";
import { SupportPage } from "@ui/pages/support";
import { AllCommunityModule, ModuleRegistry } from "ag-grid-community";
import ChatProvider from "@ui/providers/ChatProvider";
import { UserStoreProvider } from "@ui/providers/UserStoreProvider";
import { ProtectedRoute } from "@ui/components/ProtectedRoute";
import { JoinPage } from "@ui/pages/join";
import { CreateEventModal } from "@ui/components/CreateEventModal";
import { isProd } from "@ui/utils/helpers";
import { useEffect } from "react";
import { datadogRum } from "@datadog/browser-rum";
import { initRum } from "@ui/lib/rum";
import { DatadogRumProvider } from "@ui/providers/DatadogRumProvider";
import { routes } from "@ui/lib/routes";
// Register all Community features
ModuleRegistry.registerModules([AllCommunityModule]);
export const App = () => {
useEffect(() => {
initRum();
datadogRum.startSessionReplayRecording();
}, [location]);
const AppRoutes = () => {
const element = useRoutes(routes);
return element;
};
export const App = () => {
return (
<ThemeProvider>
<SessionProvider>
<UserStoreProvider>
<Router>
<div
className={twMerge(
"min-h-screen",
!isProd ? "bg-orange-50" : "bg-white",
"dark:bg-gray-900"
)}
>
<Routes>
<Route path="/" element={<ProtectedRoute fallback="/login" />}>
<Route element={<Layout />}>
<Route index element={<TabloPage />} />
<Route path="tablo" element={<TabloPage />} />
<Route path="devis" element={<DevisPage />} />
<Route path="factures" element={<FacturesPage />} />
<Route path="planning" element={<PlanningPage />}>
<Route index />
<Route path=":tablo_id" />
<Route path="create" element={<CreateEventModal />} />
</Route>
<Route path="kanban" element={<NotFoundPage />}>
<Route index />
<Route path=":tablo_id" />
</Route>
<Route path="chantiers" element={<ChantiersPage />} />
<Route
path="chat"
element={
<ChatProvider>
<ChatPage />
</ChatProvider>
}
>
<Route index />
<Route path=":channelId" />
</Route>
<Route path="feedback" element={<FeedbackPage />} />
<Route path="support" element={<SupportPage />} />
</Route>
</Route>
<Route
element={
<ProtectedRoute
fallback="/login"
shouldRedirectToCurrentPage
/>
<DatadogRumProvider>
<div
className={twMerge(
"min-h-screen",
!isProd ? "bg-orange-50" : "bg-white",
"dark:bg-gray-900"
)}
>
<AppRoutes />
<style>
{`
@keyframes slide {
0% { transform: translateX(-100vw); }
100% { transform: translateX(100vw); }
}
>
<Route element={<Layout />}>
<Route path="join/:tablo_name" element={<JoinPage />} />
</Route>
</Route>
<Route path="login-with-oauth" element={<OAuthSigninPage />} />
<Route path="landing" element={<LandingPage />} />
<Route element={<PublicRoute />}>
<Route path="login" element={<LoginPage />} />
<Route path="signup" element={<SignUpPage />} />
<Route
path="reset-password"
element={<ResetPasswordPage />}
/>
</Route>
<Route path="*" element={<NotFoundPage />} />
</Routes>
<style>
{`
@keyframes slide {
0% { transform: translateX(-100vw); }
100% { transform: translateX(100vw); }
}
.animate-slide {
animation: slide 24s linear infinite;
}
`}
</style>
</div>
.animate-slide {
animation: slide 24s linear infinite;
}
`}
</style>
</div>
</DatadogRumProvider>
</Router>
</UserStoreProvider>
</SessionProvider>

139
ui/src/lib/routes.tsx Normal file
View file

@ -0,0 +1,139 @@
import { RouteObject } from "react-router-dom";
import { ProtectedRoute } from "@ui/components/ProtectedRoute";
import { Layout } from "@ui/components/Layout";
import { TabloPage } from "@ui/pages/tablo";
import { DevisPage } from "@ui/pages/devis";
import { FacturesPage } from "@ui/pages/factures";
import { PlanningPage } from "@ui/pages/planning";
import { NotFoundPage } from "@ui/pages/NotFoundPage";
import { JoinPage } from "@ui/pages/join";
import { OAuthSigninPage } from "@ui/pages/oauth-signin";
import { LandingPage } from "@ui/pages/landing";
import { LoginPage } from "@ui/pages/login";
import { SignUpPage } from "@ui/pages/signup";
import { ResetPasswordPage } from "@ui/pages/reset-password";
import { PublicRoute } from "@ui/components/PublicRoute";
import ChatProvider from "@ui/providers/ChatProvider";
import { CreateEventModal } from "@ui/components/CreateEventModal";
import { ChantiersPage } from "@ui/pages/chantiers";
import { ChatPage } from "@ui/pages/chat";
import { FeedbackPage } from "@ui/pages/feedback";
import { SupportPage } from "@ui/pages/support";
export const routes: RouteObject[] = [
// Protected routes
{
path: "/",
element: <ProtectedRoute fallback="/login" />,
children: [
{
path: "",
element: <Layout />,
children: [
{
index: true,
element: <TabloPage />,
},
{
path: "tablo",
element: <TabloPage />,
},
{
path: "devis",
element: <DevisPage />,
},
{
path: "factures",
element: <FacturesPage />,
},
{
path: "planning",
element: <PlanningPage />,
children: [
{ index: true },
{ path: ":tablo_id" },
{ path: "create", element: <CreateEventModal /> },
],
},
{
path: "kanban",
element: <NotFoundPage />,
children: [{ index: true }, { path: ":tablo_id" }],
},
{
path: "chantiers",
element: <ChantiersPage />,
},
{
path: "chat",
element: (
<ChatProvider>
<ChatPage />
</ChatProvider>
),
children: [{ index: true }, { path: ":channelId" }],
},
{
path: "feedback",
element: <FeedbackPage />,
},
{
path: "support",
element: <SupportPage />,
},
],
},
],
},
// Protected routes with redirect to current page
{
path: "/join/:tablo_name",
element: <ProtectedRoute fallback="/login" shouldRedirectToCurrentPage />,
children: [
{
path: "",
element: <Layout />,
children: [
{
index: true,
element: <JoinPage />,
},
],
},
],
},
// OAuth signin route
{
path: "/login-with-oauth",
element: <OAuthSigninPage />,
},
// Landing page
{
path: "/landing",
element: <LandingPage />,
},
// Public routes (authentication pages)
{
path: "/",
element: <PublicRoute />,
children: [
{
path: "login",
element: <LoginPage />,
},
{
path: "signup",
element: <SignUpPage />,
},
{
path: "reset-password",
element: <ResetPasswordPage />,
},
],
},
// Catch-all route for 404
{
path: "*",
element: <NotFoundPage />,
},
];

View file

@ -15,5 +15,7 @@ export const initRum = () => {
sessionReplaySampleRate: 80,
defaultPrivacyLevel: "mask-user-input",
plugins: [reactPlugin({ router: true })],
trackViewsManually: true,
startSessionReplayRecordingManually: false,
});
};

View file

@ -0,0 +1,47 @@
import { datadogRum } from "@datadog/browser-rum";
import { routes } from "@ui/lib/routes";
import { initRum } from "@ui/lib/rum";
import { useEffect } from "react";
import { matchRoutes, RouteMatch, useLocation } from "react-router-dom";
function computeViewName(routeMatches: RouteMatch[]) {
let viewName = "";
for (let index = 0; index < routeMatches.length; index++) {
const routeMatch = routeMatches[index];
const path = routeMatch.route.path;
// Skip pathless routes
if (!path) {
continue;
}
if (path.startsWith("/")) {
// Handle absolute child route paths
viewName = path;
} else {
// Handle route paths ending with "/"
viewName += viewName.endsWith("/") ? path : `/${path}`;
}
}
return viewName || "/";
}
export const DatadogRumProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const location = useLocation();
useEffect(() => {
initRum();
}, []);
useEffect(() => {
const routeMatches = matchRoutes(routes, location.pathname);
const viewName = routeMatches && computeViewName(routeMatches);
if (viewName) {
datadogRum.startView({ name: viewName });
}
}, [location.pathname]);
return <>{children}</>;
};