0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(console): remove AppInsights

This commit is contained in:
Gao Sun 2024-04-17 21:38:30 +08:00
parent a2bbc250ca
commit 8a54136b3a
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
40 changed files with 65 additions and 175 deletions

View file

@ -23,7 +23,6 @@ const config: Config.InitialOptions = {
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^@logto/app-insights/(.*)$': '<rootDir>/../app-insights/lib/$1',
'^@logto/shared/(.*)$': '<rootDir>/../shared/lib/$1',
'\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
},

View file

@ -27,7 +27,6 @@
"devDependencies": {
"@fontsource/roboto-mono": "^5.0.0",
"@jest/types": "^29.5.0",
"@logto/app-insights": "workspace:^1.4.0",
"@logto/cloud": "0.2.5-821690c",
"@logto/connector-kit": "workspace:^3.0.0",
"@logto/core-kit": "workspace:^2.4.0",

View file

@ -1,4 +1,3 @@
import { AppInsightsBoundary } from '@logto/app-insights/react';
import { UserScope } from '@logto/core-kit';
import { LogtoProvider, Prompt, useLogto } from '@logto/react';
import {
@ -23,7 +22,6 @@ import AppLoading from '@/components/AppLoading';
import { isCloud } from '@/consts/env';
import { cloudApi, getManagementApi, meApi } from '@/consts/resources';
import { ConsoleRoutes } from '@/containers/ConsoleRoutes';
import useTrackUserId from '@/hooks/use-track-user-id';
import { OnboardingRoutes } from '@/onboarding';
import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data';
@ -114,26 +112,24 @@ function Providers() {
}}
>
<AppThemeProvider>
<AppInsightsBoundary cloudRole="console">
<Helmet titleTemplate={`%s - ${mainTitle}`} defaultTitle={mainTitle} />
<ErrorBoundary>
<LogtoErrorBoundary>
{/**
* If it's not Cloud (OSS), render the tenant app container directly since only default tenant is available;
* if it's Cloud, render the tenant app container only when a tenant ID is available (in a tenant context).
*/}
{!isCloud || currentTenantId ? (
<AppDataProvider>
<AppConfirmModalProvider>
<AppRoutes />
</AppConfirmModalProvider>
</AppDataProvider>
) : (
<CloudAppRoutes />
)}
</LogtoErrorBoundary>
</ErrorBoundary>
</AppInsightsBoundary>
<Helmet titleTemplate={`%s - ${mainTitle}`} defaultTitle={mainTitle} />
<ErrorBoundary>
<LogtoErrorBoundary>
{/**
* If it's not Cloud (OSS), render the tenant app container directly since only default tenant is available;
* if it's Cloud, render the tenant app container only when a tenant ID is available (in a tenant context).
*/}
{!isCloud || currentTenantId ? (
<AppDataProvider>
<AppConfirmModalProvider>
<AppRoutes />
</AppConfirmModalProvider>
</AppDataProvider>
) : (
<CloudAppRoutes />
)}
</LogtoErrorBoundary>
</ErrorBoundary>
</AppThemeProvider>
</LogtoProvider>
);
@ -146,8 +142,6 @@ function AppRoutes() {
const { isOnboarding } = useUserOnboardingData();
const { isAuthenticated } = useLogto();
useTrackUserId();
// Authenticated user should load onboarding data before rendering the app.
// This looks weird and it will be refactored soon by merging the onboarding
// routes with the console routes.

View file

@ -1,31 +1,16 @@
import { AppInsightsContext } from '@logto/app-insights/react';
import type { AdminConsoleKey } from '@logto/phrases';
import { useContext, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
export type Props = {
titleKey: AdminConsoleKey | AdminConsoleKey[];
// eslint-disable-next-line react/boolean-prop-naming
trackPageView?: boolean;
};
function PageMeta({ titleKey, trackPageView = true }: Props) {
function PageMeta({ titleKey }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { isSetupFinished, appInsights } = useContext(AppInsightsContext);
const [pageViewTracked, setPageViewTracked] = useState(false);
const keys = typeof titleKey === 'string' ? [titleKey] : titleKey;
const rawTitle = keys.map((key) => t(key, { lng: 'en' })).join(' - ');
const title = keys.map((key) => t(key)).join(' - ');
useEffect(() => {
// Only track once for the same page
if (isSetupFinished && trackPageView && !pageViewTracked) {
appInsights.trackPageView?.({ name: `Console: ${rawTitle}` });
setPageViewTracked(true);
}
}, [appInsights, isSetupFinished, pageViewTracked, rawTitle, trackPageView]);
return <Helmet title={title} />;
}

View file

@ -1,5 +1,3 @@
import { Component, GeneralEvent } from '@logto/app-insights/custom-event';
import { TrackOnce } from '@logto/app-insights/react';
import { ossConsolePath } from '@logto/schemas';
import { Navigate, Outlet, Route, Routes } from 'react-router-dom';
import { SWRConfig } from 'swr';
@ -25,7 +23,6 @@ function Layout() {
return (
<SWRConfig value={swrOptions}>
<AppBoundary>
<TrackOnce component={Component.Console} event={GeneralEvent.Visit} />
<Toast />
<Outlet />
</AppBoundary>

View file

@ -1,42 +0,0 @@
import { AppInsightsContext } from '@logto/app-insights/react';
import { useLogto } from '@logto/react';
import { trySafe } from '@silverhand/essentials';
import { useContext, useEffect } from 'react';
class NoIdTokenClaimsError extends Error {
name = 'NoIdTokenClaimsError';
message = 'Cloud not fetch ID Token claims where user is authenticated.';
}
const useTrackUserId = () => {
const { isAuthenticated, getIdTokenClaims } = useLogto();
const { isSetupFinished, appInsights } = useContext(AppInsightsContext);
useEffect(() => {
const setUserId = async () => {
if (!appInsights.instance) {
return;
}
if (!isAuthenticated) {
appInsights.instance.clearAuthenticatedUserContext();
return;
}
const claims = await trySafe(getIdTokenClaims());
if (claims) {
appInsights.instance.setAuthenticatedUserContext(claims.sub, claims.sub, true);
} else {
appInsights.instance.trackException({ exception: new NoIdTokenClaimsError() });
}
};
if (isSetupFinished) {
void setUserId();
}
}, [getIdTokenClaims, isSetupFinished, isAuthenticated, appInsights.instance]);
};
export default useTrackUserId;

View file

@ -1,5 +1,3 @@
import { Component, ConsoleEvent } from '@logto/app-insights/custom-event';
import { TrackOnce } from '@logto/app-insights/react';
import { Theme } from '@logto/schemas';
import { useContext, useEffect } from 'react';
import { Route, Navigate, Outlet, Routes } from 'react-router-dom';
@ -64,17 +62,14 @@ function Layout() {
}
return (
<>
<TrackOnce component={Component.Console} event={ConsoleEvent.Onboard} />
<div className={styles.app}>
<SWRConfig value={swrOptions}>
<AppBoundary>
<Toast />
<Outlet />
</AppBoundary>
</SWRConfig>
</div>
</>
<div className={styles.app}>
<SWRConfig value={swrOptions}>
<AppBoundary>
<Toast />
<Outlet />
</AppBoundary>
</SWRConfig>
</div>
);
}

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { ConnectorType, ServiceConnector } from '@logto/connector-kit';
import { SignInIdentifier } from '@logto/schemas';
import type { SignInExperience as SignInExperienceType, ConnectorResponse } from '@logto/schemas';
@ -250,4 +249,4 @@ function SignInExperience() {
);
}
export default withAppInsights(SignInExperience);
export default SignInExperience;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type Questionnaire, Project } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useEffect } from 'react';
@ -130,4 +129,4 @@ function Welcome() {
);
}
export default withAppInsights(Welcome);
export default Welcome;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { Resource } from '@logto/schemas';
import { isManagementApi, Theme } from '@logto/schemas';
import { conditionalArray } from '@silverhand/essentials';
@ -193,4 +192,4 @@ function ApiResourceDetails() {
);
}
export default withAppInsights(ApiResourceDetails);
export default ApiResourceDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { Resource } from '@logto/schemas';
import { Theme, isManagementApi } from '@logto/schemas';
import { useTranslation } from 'react-i18next';
@ -146,4 +145,4 @@ function ApiResources() {
);
}
export default withAppInsights(ApiResources);
export default ApiResources;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type ApplicationResponse, type SnakeCaseOidcConfig } from '@logto/schemas';
import { useParams } from 'react-router-dom';
import useSWR from 'swr';
@ -65,4 +64,4 @@ function ApplicationDetails() {
);
}
export default withAppInsights(ApplicationDetails);
export default ApplicationDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { joinPath } from '@silverhand/essentials';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
@ -185,4 +184,4 @@ function Applications({ tab }: Props) {
);
}
export default withAppInsights(Applications);
export default Applications;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { Application, User, Log, Hook } from '@logto/schemas';
import { demoAppApplicationId } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
@ -161,4 +160,4 @@ function AuditLogDetails() {
);
}
export default withAppInsights(AuditLogDetails);
export default AuditLogDetails;

View file

@ -1,5 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import AuditLogTable from '@/components/AuditLogTable';
import PageMeta from '@/components/PageMeta';
import CardTitle from '@/ds-components/CardTitle';
@ -17,4 +15,4 @@ function AuditLogs() {
);
}
export default withAppInsights(AuditLogs);
export default AuditLogs;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { ServiceConnector } from '@logto/connector-kit';
import { ConnectorType } from '@logto/schemas';
import type { ConnectorFactoryResponse, ConnectorResponse } from '@logto/schemas';
@ -232,4 +231,4 @@ function ConnectorDetails() {
);
}
export default withAppInsights(ConnectorDetails);
export default ConnectorDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { ServiceConnector } from '@logto/connector-kit';
import { ConnectorType } from '@logto/schemas';
import type { ConnectorFactoryResponse } from '@logto/schemas';
@ -243,4 +242,4 @@ function Connectors() {
);
}
export default withAppInsights(Connectors);
export default Connectors;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { LogtoJwtTokenKeyType } from '@logto/schemas';
import { useTranslation } from 'react-i18next';
@ -64,4 +63,4 @@ function CustomizeJwt() {
);
}
export default withAppInsights(CustomizeJwt);
export default CustomizeJwt;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { type LogtoJwtTokenKeyType } from '@logto/schemas';
import { useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
@ -18,7 +17,7 @@ type Props = {
action: Action;
};
function CustomizeJwtDetails({ tokenType, action }: Props) {
function Content({ tokenType, action }: Props) {
const { isLoading, error, ...rest } = useDataFetch(tokenType, action);
const [isMonacoLoaded, setIsMonacoLoaded] = useState(false);
@ -51,7 +50,7 @@ function CustomizeJwtDetails({ tokenType, action }: Props) {
}
// Guard the parameters to ensure they are valid
function CustomizeJwtDetailsWrapper() {
function CustomizeJwtDetails() {
const { tokenType, action } = useParams();
const params = pageParamsGuard.safeParse({ tokenType, action });
@ -60,7 +59,7 @@ function CustomizeJwtDetailsWrapper() {
return <EmptyDataPlaceholder />;
}
return <CustomizeJwtDetails tokenType={params.data.tokenType} action={params.data.action} />;
return <Content tokenType={params.data.tokenType} action={params.data.action} />;
}
export default withAppInsights(CustomizeJwtDetailsWrapper);
export default CustomizeJwtDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { format } from 'date-fns';
import type { ChangeEventHandler } from 'react';
import { useState } from 'react';
@ -153,4 +152,4 @@ function Dashboard() {
);
}
export default withAppInsights(Dashboard);
export default Dashboard;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type SsoConnectorWithProviderConfig, ReservedPlanId } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useContext } from 'react';
@ -32,7 +31,7 @@ const enterpriseSsoPathname = '/enterprise-sso';
const createEnterpriseSsoPathname = `${enterpriseSsoPathname}/create`;
const buildDetailsPathname = (id: string) => `${enterpriseSsoPathname}/${id}`;
function EnterpriseSsoConnectors() {
function EnterpriseSso() {
const { pathname } = useLocation();
const { navigate } = useTenantPathname();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
@ -176,4 +175,4 @@ function EnterpriseSsoConnectors() {
);
}
export default withAppInsights(EnterpriseSsoConnectors);
export default EnterpriseSso;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type SignInExperience, type SsoConnectorWithProviderConfig } from '@logto/schemas';
import { pick } from '@silverhand/essentials';
import { useEffect, useState } from 'react';
@ -31,7 +30,7 @@ import useDeleteConnector from './use-delete-connector';
const getSsoConnectorDetailsPathname = (ssoConnectorId: string, tab: EnterpriseSsoDetailsTabs) =>
`${enterpriseSsoPathname}/${ssoConnectorId}/${tab}`;
function EnterpriseSsoConnectorDetails() {
function EnterpriseSsoDetails() {
const { pathname } = useLocation();
const { ssoConnectorId, tab } = useParams();
@ -175,4 +174,4 @@ function EnterpriseSsoConnectorDetails() {
);
}
export default withAppInsights(EnterpriseSsoConnectorDetails);
export default EnterpriseSsoDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { Theme, type Application, type Resource } from '@logto/schemas';
import classNames from 'classnames';
import { useCallback, useContext, useMemo, useRef, useState } from 'react';
@ -208,4 +207,4 @@ function GetStarted() {
);
}
export default withAppInsights(GetStarted);
export default GetStarted;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { type SignInExperience } from '@logto/schemas';
import useSWR from 'swr';
@ -44,4 +43,4 @@ function Mfa() {
);
}
export default withAppInsights(Mfa);
export default Mfa;

View file

@ -1,7 +1,6 @@
import { Theme } from '@logto/schemas';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import NotFoundDarkImage from '@/assets/images/not-found-dark.svg';
import NotFoundImage from '@/assets/images/not-found.svg';
@ -18,12 +17,11 @@ type Props = {
function NotFound({ className }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const theme = useTheme();
const location = useLocation();
return (
<div className={classNames(styles.container, className)}>
{/* Don't track "not found" for the root path as it will be redirected. */}
<PageMeta titleKey="errors.page_not_found" trackPageView={location.pathname !== '/'} />
<PageMeta titleKey="errors.page_not_found" />
<Card className={styles.content}>
{theme === Theme.Light ? <NotFoundImage /> : <NotFoundDarkImage />}
<div className={styles.message}>{t('errors.page_not_found')}</div>

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { type OrganizationRole } from '@logto/schemas';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
@ -133,4 +132,4 @@ function OrganizationRoleDetails() {
);
}
export default withAppInsights(OrganizationRoleDetails);
export default OrganizationRoleDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { ReservedPlanId } from '@logto/schemas';
import { cond } from '@silverhand/essentials';
import classNames from 'classnames';
@ -111,4 +110,4 @@ function OrganizationTemplate() {
);
}
export default withAppInsights(OrganizationTemplate);
export default OrganizationTemplate;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { ConnectorResponse } from '@logto/schemas';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -99,4 +98,4 @@ function Profile() {
);
}
export default withAppInsights(Profile);
export default Profile;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { Role } from '@logto/schemas';
import { Theme, RoleType } from '@logto/schemas';
import classNames from 'classnames';
@ -151,4 +150,4 @@ function RoleDetails() {
);
}
export default withAppInsights(RoleDetails);
export default RoleDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { RoleType, type RoleResponse } from '@logto/schemas';
import { Theme } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
@ -211,4 +210,4 @@ function Roles() {
);
}
export default withAppInsights(Roles);
export default Roles;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { SignInExperience as SignInExperienceType } from '@logto/schemas';
import type { ReactNode } from 'react';
import useSWR from 'swr';
@ -101,4 +100,4 @@ function SignInExperience() {
);
}
export default withAppInsights(SignInExperience);
export default SignInExperience;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact';
import { LogtoOidcConfigKeyType } from '@logto/schemas';
import PageMeta from '@/components/PageMeta';
@ -27,4 +26,4 @@ function SigningKeys() {
);
}
export default withAppInsights(SigningKeys);
export default SigningKeys;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { conditional } from '@silverhand/essentials';
import dayjs from 'dayjs';
import { useCallback, useContext, useMemo } from 'react';
@ -92,4 +91,4 @@ function BillingHistory() {
);
}
export default withAppInsights(BillingHistory);
export default BillingHistory;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { useContext } from 'react';
import PageMeta from '@/components/PageMeta';
@ -61,4 +60,4 @@ function Subscription() {
);
}
export default withAppInsights(Subscription);
export default Subscription;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type Domain, DomainStatus } from '@logto/schemas';
import { Trans, useTranslation } from 'react-i18next';
@ -92,4 +91,4 @@ function TenantDomainSettings() {
);
}
export default withAppInsights(TenantDomainSettings);
export default TenantDomainSettings;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { UserProfileResponse, User } from '@logto/schemas';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
@ -235,4 +234,4 @@ function UserDetails() {
);
}
export default withAppInsights(UserDetails);
export default UserDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import type { User } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useTranslation } from 'react-i18next';
@ -177,4 +176,4 @@ function Users() {
);
}
export default withAppInsights(Users);
export default Users;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type HookResponse, type Hook } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import classNames from 'classnames';
@ -176,4 +175,4 @@ function WebhookDetails() {
);
}
export default withAppInsights(WebhookDetails);
export default WebhookDetails;

View file

@ -1,4 +1,3 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type HookEvent, type Hook, Theme, type HookResponse } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { toast } from 'react-hot-toast';
@ -181,4 +180,4 @@ function Webhooks() {
);
}
export default withAppInsights(Webhooks);
export default Webhooks;

View file

@ -2711,9 +2711,6 @@ importers:
'@jest/types':
specifier: ^29.5.0
version: 29.5.0
'@logto/app-insights':
specifier: workspace:^1.4.0
version: link:../app-insights
'@logto/cloud':
specifier: 0.2.5-821690c
version: 0.2.5-821690c(zod@3.22.4)
@ -10589,7 +10586,7 @@ packages:
strip-literal: 2.0.0
test-exclude: 6.0.0
v8-to-istanbul: 9.2.0
vitest: 1.4.0(@types/node@20.11.20)
vitest: 1.4.0(@types/node@20.10.4)
transitivePeerDependencies:
- supports-color
dev: true