Skip to content

Commit

Permalink
Add global error handling page and imrpove SFDC classic styling
Browse files Browse the repository at this point in the history
  • Loading branch information
paustint committed Aug 6, 2024
1 parent dfbb2cc commit ca149f1
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 137 deletions.
12 changes: 7 additions & 5 deletions apps/jetstream-web-extension/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-restricted-globals */
import { css } from '@emotion/react';
import { logger } from '@jetstream/shared/client-logger';
import { isValidSalesforceRecordId, useInterval } from '@jetstream/shared/ui-utils';
import { Maybe } from '@jetstream/types';
import { Grid, GridCol, OutsideClickHandler } from '@jetstream/ui';
Expand Down Expand Up @@ -158,8 +159,7 @@ export function Button() {
}
}
} catch (ex) {
console.error(ex);
// FIXME: we need to tell the user there was a problem - most likely they are not logged in
logger.error('Error initializing org', ex);
}
})();
})
Expand Down Expand Up @@ -294,14 +294,16 @@ export function Button() {
<hr
className="slds-m-vertical_medium"
css={css`
margin-top: var(--lwc-spacingMedium, 1rem);
margin-bottom: var(--lwc-spacingMedium, 1rem);
margin-top: 0.5rem;
margin-bottom: 1rem;
display: block;
border-top: 1px solid var(--slds-g-color-border-base-1, var(--lwc-colorBorder, rgb(229, 229, 229)));
border: 0;
border-top: 1px solid rgb(229, 229, 229);
height: 1px;
clear: both;
padding: 0;
box-sizing: content-box;
width: 100%;
`}
/>
<GridCol
Expand Down
94 changes: 13 additions & 81 deletions apps/jetstream-web-extension/src/core/AppInitializer.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
/* eslint-disable no-restricted-globals */
import { HTTP } from '@jetstream/shared/constants';
import { registerMiddleware } from '@jetstream/shared/data';
import { SalesforceOrgUi, UserProfileUi } from '@jetstream/types';
import { AppLoading, fromAppState, selectSkipFrontdoorAuth } from '@jetstream/ui-core';
import { logger } from '@jetstream/shared/client-logger';
import { getErrorMessage } from '@jetstream/shared/utils';
import { UserProfileUi } from '@jetstream/types';
import { AppLoading, fromAppState } from '@jetstream/ui-core';
import { sendMessage } from '@jetstream/web-extension-utils';
import { AxiosResponse } from 'axios';
import localforage from 'localforage';
import React, { FunctionComponent, useEffect } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { Subject } from 'rxjs';
import { GlobalExtensionError } from './GlobalExtensionError';

const args = new URLSearchParams(location.search.slice(1));
const salesforceHost = args.get('host');

const orgConnectionError = new Subject<{ uniqueId: string; connectionError: string }>();
const orgConnectionError$ = orgConnectionError.asObservable();

registerMiddleware('Error', (response: AxiosResponse, org?: SalesforceOrgUi) => {
const connectionError =
response?.headers?.[HTTP.HEADERS.X_SFDC_ORG_CONNECTION_ERROR.toLowerCase()] ||
response?.headers?.[HTTP.HEADERS.X_SFDC_ORG_CONNECTION_ERROR];
if (org && connectionError) {
orgConnectionError.next({ uniqueId: org.uniqueId, connectionError });
}
});

// Configure IndexedDB database
localforage.config({
name: 'jetstream-web-extension',
Expand All @@ -37,17 +24,13 @@ export interface AppInitializerProps {

export const AppInitializer: FunctionComponent<AppInitializerProps> = ({ onUserProfile, children }) => {
const userProfile = useRecoilValue<UserProfileUi>(fromAppState.userProfileState);
const skipFrontDoorAuth = useRecoilValue(selectSkipFrontdoorAuth);

// const { version } = useRecoilValue(fromAppState.appVersionState);
// const appCookie = useRecoilValue<ApplicationCookie>(fromAppState.applicationCookieState);
// const [orgs, setOrgs] = useRecoilState(fromAppState.salesforceOrgsState);
// const invalidOrg = useObservable(orgConnectionError$);

const setSelectedOrgId = useSetRecoilState(fromAppState.selectedOrgIdState);
const setSalesforceOrgs = useSetRecoilState(fromAppState.salesforceOrgsState);
const selectedOrg = useRecoilValue(fromAppState.selectedOrgState);

const [fatalError, setFatalError] = useState<string>();

useEffect(() => {
(async () => {
try {
Expand All @@ -67,72 +50,21 @@ export const AppInitializer: FunctionComponent<AppInitializerProps> = ({ onUserP
}
}
} catch (ex) {
console.error(ex);
// FIXME: we need to tell the user there was a problem - most likely they are not logged in
logger.error('Error initializing org', ex);
setFatalError(getErrorMessage(ex));
}
})();
}, [setSalesforceOrgs, setSelectedOrgId]);

// useEffect(() => {
// console.log('APP VERSION', version);
// }, [version]);

// useRollbar({
// accessToken: environment.rollbarClientAccessToken,
// environment: appCookie.environment,
// userProfile: userProfile,
// version,
// });
// useAmplitude();
// usePageViews();

// useEffect(() => {
// if (invalidOrg) {
// const { uniqueId, connectionError } = invalidOrg;
// const clonedOrgs = orgs.map((org) => {
// if (org.uniqueId === uniqueId) {
// return { ...org, connectionError };
// } else {
// return org;
// }
// });
// logger.log('[invalidOrg]', invalidOrg, { orgs: clonedOrgs });
// setOrgs(clonedOrgs);
// }
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [invalidOrg]);

useEffect(() => {
if (userProfile) {
onUserProfile(userProfile);
}
}, [onUserProfile, userProfile]);

/**
* TODO:
* When a tab/browser window becomes visible check with the server
* 1. ensure user is still authenticated
* 2. make sure the app version has not changed, if it has then refresh the page
*/
// const handleWindowFocus = useCallback(async (event: FocusEvent) => {
// try {
// if (document.visibilityState === 'visible') {
// const { version: serverVersion } = await checkHeartbeat();
// // TODO: inform user that there is a new version and that they should refresh their browser.
// // We could force refresh, but don't want to get into some weird infinite refresh state
// if (version !== serverVersion) {
// console.log('VERSION MISMATCH', { serverVersion, version });
// }
// }
// } catch (ex) {
// // ignore error, but user should have been logged out if this failed
// }
// }, []);

// useEffect(() => {
// document.addEventListener('visibilitychange', handleWindowFocus);
// return () => document.removeEventListener('visibilitychange', handleWindowFocus);
// }, [handleWindowFocus]);
if (fatalError) {
return <GlobalExtensionError message={fatalError} />;
}

if (!salesforceHost || !selectedOrg?.uniqueId) {
return <AppLoading />;
Expand Down
2 changes: 0 additions & 2 deletions apps/jetstream-web-extension/src/core/AppWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import AppInitializer from './AppInitializer';

enableLogger(true);

const featureFlags = new Set<string>();

export function AppWrapper({ children }: { children: ReactNode }) {
return (
<ConfirmationServiceProvider>
Expand Down
29 changes: 29 additions & 0 deletions apps/jetstream-web-extension/src/core/GlobalExtensionError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { FeedbackLink, Grid } from '@jetstream/ui';

export const GlobalExtensionError = ({ message }: { message: string }) => {
return (
<div className="slds-card slds-box">
<p>There was a problem connecting with Salesforce. Make sure you are logged in to Salesforce and try again.</p>
{message && <p className="slds-m-top_small slds-text-color_error">{message}</p>}
<hr className="slds-m-vertical_medium" />
<Grid vertical>
<div>
<ol className="slds-list_ordered">
<li>
Bug reports and feature requests - <FeedbackLink type="GH_ISSUE" />
</li>
<li className="slds-m-top_x-small">
<FeedbackLink type="GH_DISCUSSION" />
</li>
<li className="slds-m-top_x-small">
Ask a question in the <strong>#vendors-jetstream</strong> Discord channel <FeedbackLink type="DISCORD" />
</li>
<li className="slds-m-top_x-small">
You can always email us at <FeedbackLink type="EMAIL" />
</li>
</ol>
</div>
</Grid>
</div>
);
};
8 changes: 7 additions & 1 deletion apps/jetstream-web-extension/src/serviceWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,13 @@ const handleResponse = (data: Message['response'], sendResponse: (response: Mess

const handleError = (sendResponse: (response: MessageResponse) => void) => (err: unknown) => {
console.log('ERROR', err);
sendResponse({ data: null });
sendResponse({
data: null,
error: {
error: true,
message: err instanceof Error ? err.message : 'An unknown error occurred',
},
});
};

/**
Expand Down
7 changes: 7 additions & 0 deletions libs/web-extension-utils/src/lib/extension.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ import { Maybe, SalesforceOrgUi } from '@jetstream/types';

export type Message = ToggleExtension | GetSfHost | GetSession | GetPageUrl | InitOrg;
export type MessageRequest = Message['request'];

export interface ResponseError {
error: true;
message: string;
}

export interface MessageResponse<T extends Message['response'] = Message['response']> {
data: T;
error?: ResponseError;
}

export interface SessionInfo {
Expand Down
52 changes: 4 additions & 48 deletions libs/web-extension-utils/src/lib/web-extension-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type ResponseForRequest<R> = R extends { message: infer M }

function handleResponse<T>(response: MessageResponse<ResponseForRequest<T>>) {
console.log('RESPONSE', response);
if (response.error) {
throw new Error(response.error.message);
}
return response.data;
}

Expand Down Expand Up @@ -43,54 +46,7 @@ export async function sendMessage<T extends MessageRequest>(message: T): Promise
try {
return await chrome.runtime.sendMessage<T, MessageResponse<ResponseForRequest<T>>>(message).then(handleResponse);
} catch (error) {
console.error('Error getting salesforce host', error);
console.error('Error sending message', error);
throw error;
}
}

// export async function getHost(url: string) {
// try {
// return await chrome.runtime
// .sendMessage<GetSfHost['request'], MessageResponse<GetSfHost['response']>>({
// message: 'GET_SF_HOST',
// url,
// })
// .then(handleResponse);
// } catch (error) {
// console.error('Error getting salesforce host', error);
// throw error;
// }
// }

// export async function getSession(salesforceHost: string) {
// try {
// return await chrome.runtime
// .sendMessage<GetSession['request'], MessageResponse<GetSession['response']>>({ message: 'GET_SESSION', salesforceHost })
// .then(handleResponse);
// } catch (error) {
// console.error('Error getting session', error);
// throw error;
// }
// }

// export async function getPageUrl(page: string) {
// try {
// return await chrome.runtime
// .sendMessage<GetPageUrl['request'], MessageResponse<GetPageUrl['response']>>({ message: 'GET_PAGE_URL', page })
// .then(handleResponse);
// } catch (error) {
// console.error('Error getting session', error);
// throw error;
// }
// }

// export async function initOrg(sessionInfo: SessionInfo) {
// try {
// return await chrome.runtime
// .sendMessage<InitOrg['request'], MessageResponse<InitOrg['response']>>({ message: 'INIT_ORG', sessionInfo })
// .then(handleResponse);
// } catch (error) {
// console.error('Error getting session', error);
// throw error;
// }
// }

0 comments on commit ca149f1

Please sign in to comment.