Show potential errors alongside buttons

Summary:
Instead of replacing the buttons, this shows an error next to
them and gives the opportunity to retry.

Reviewed By: jknoxville

Differential Revision: D17907389

fbshipit-source-id: 15b27802671b39c53b32d01f1d2bcf8c67fd2647
This commit is contained in:
Pascal Hartig
2019-10-14 10:07:06 -07:00
committed by Facebook Github Bot
parent 4bdccb22fa
commit b10a67d443

View File

@@ -178,21 +178,23 @@ function InstallButton(props: {
installed: boolean; installed: boolean;
}) { }) {
type InstallAction = type InstallAction =
| {kind: 'Install'} | {kind: 'Install'; error?: string}
| {kind: 'Waiting'} | {kind: 'Waiting'}
| {kind: 'Remove'} | {kind: 'Remove'; error?: string};
| {kind: 'Error'; error: string};
const catchError = (fn: () => Promise<void>) => async () => { const catchError = (
actionKind: 'Install' | 'Remove',
fn: () => Promise<void>,
) => async () => {
try { try {
await fn(); await fn();
} catch (err) { } catch (err) {
setAction({kind: 'Error', error: err.toString()}); setAction({kind: actionKind, error: err.toString()});
} }
}; };
const onInstall = useCallback( const performInstall = useCallback(
catchError(async () => { catchError('Install', async () => {
reportUsage(`${TAG}:install`, undefined, props.name); reportUsage(`${TAG}:install`, undefined, props.name);
setAction({kind: 'Waiting'}); setAction({kind: 'Waiting'});
await fs.ensureDir(PLUGIN_DIR); await fs.ensureDir(PLUGIN_DIR);
@@ -227,8 +229,8 @@ function InstallButton(props: {
[props.name, props.version], [props.name, props.version],
); );
const onRemove = useCallback( const performRemove = useCallback(
catchError(async () => { catchError('Remove', async () => {
reportUsage(`${TAG}:remove`, undefined, props.name); reportUsage(`${TAG}:remove`, undefined, props.name);
setAction({kind: 'Waiting'}); setAction({kind: 'Waiting'});
await fs.remove(path.join(PLUGIN_DIR, props.name)); await fs.remove(path.join(PLUGIN_DIR, props.name));
@@ -245,30 +247,38 @@ function InstallButton(props: {
if (action.kind === 'Waiting') { if (action.kind === 'Waiting') {
return <Spinner size={16} />; return <Spinner size={16} />;
} }
if (action.kind === 'Error') { if ((action.kind === 'Install' || action.kind === 'Remove') && action.error) {
const glyph = (
<AlignedGlyph color={colors.orange} size={16} name="caution-triangle" />
);
return (
<Tooltip
options={{position: 'toRight'}}
title={`Something went wrong: ${action.error}`}
children={glyph}
/>
);
} }
return ( const button = (
<TableButton <TableButton
compact compact
type={action.kind === 'Install' ? 'primary' : undefined} type={action.kind === 'Install' ? 'primary' : undefined}
onClick={ onClick={
action.kind === 'Install' action.kind === 'Install'
? () => reportPlatformFailures(onInstall(), `${TAG}:install`) ? () => reportPlatformFailures(performInstall(), `${TAG}:install`)
: () => reportPlatformFailures(onRemove(), `${TAG}:remove`) : () => reportPlatformFailures(performRemove(), `${TAG}:remove`)
}> }>
{action.kind} {action.kind}
</TableButton> </TableButton>
); );
if (action.error) {
const glyph = (
<AlignedGlyph color={colors.orange} size={16} name="caution-triangle" />
);
return (
<FlexRow>
<Tooltip
options={{position: 'toLeft'}}
title={`Something went wrong: ${action.error}`}
children={glyph}
/>
{button}
</FlexRow>
);
} else {
return button;
}
} }
function useNPMSearch( function useNPMSearch(