function InstallButton()

in desktop/flipper-ui-core/src/chrome/plugin-manager/PluginInstaller.tsx [126:239]


function InstallButton(props: {
  name: string;
  version: string;
  onInstall: () => void;
  updateStatus: UpdateResult;
}) {
  type InstallAction =
    | {kind: 'Install'; error?: string}
    | {kind: 'Waiting'}
    | {kind: 'Remove'; error?: string}
    | {kind: 'Update'; error?: string};

  const catchError =
    (actionKind: 'Install' | 'Remove' | 'Update', fn: () => Promise<void>) =>
    async () => {
      try {
        await fn();
      } catch (err) {
        console.error(
          `Installation process of kind ${actionKind} failed with:`,
          err,
        );
        setAction({kind: actionKind, error: err.toString()});
      }
    };

  const mkInstallCallback = (action: 'Install' | 'Update') =>
    catchError(action, async () => {
      reportUsage(
        action === 'Install' ? `${TAG}:install` : `${TAG}:update`,
        undefined,
        props.name,
      );
      setAction({kind: 'Waiting'});

      await installPluginFromNpm(props.name);

      props.onInstall();
      setAction({kind: 'Remove'});
    });

  const performInstall = useCallback(mkInstallCallback('Install'), [
    props.name,
    props.version,
  ]);

  const performUpdate = useCallback(mkInstallCallback('Update'), [
    props.name,
    props.version,
  ]);

  const performRemove = useCallback(
    catchError('Remove', async () => {
      reportUsage(`${TAG}:remove`, undefined, props.name);
      setAction({kind: 'Waiting'});
      await removePlugin(props.name);
      props.onInstall();
      setAction({kind: 'Install'});
    }),
    [props.name],
  );

  const [action, setAction] = useState<InstallAction>(
    props.updateStatus.kind === 'update-available'
      ? {kind: 'Update'}
      : props.updateStatus.kind === 'not-installed'
      ? {kind: 'Install'}
      : {kind: 'Remove'},
  );

  if (action.kind === 'Waiting') {
    return <LoadingIndicator size={16} />;
  }
  if ((action.kind === 'Install' || action.kind === 'Remove') && action.error) {
  }
  const button = (
    <Button
      size="small"
      type={action.kind !== 'Remove' ? 'primary' : undefined}
      onClick={() => {
        switch (action.kind) {
          case 'Install':
            reportPlatformFailures(performInstall(), `${TAG}:install`);
            break;
          case 'Remove':
            reportPlatformFailures(performRemove(), `${TAG}:remove`);
            break;
          case 'Update':
            reportPlatformFailures(performUpdate(), `${TAG}:update`);
            break;
        }
      }}>
      {action.kind}
    </Button>
  );

  if (action.error) {
    const glyph = (
      <Glyph color={theme.warningColor} size={16} name="caution-triangle" />
    );
    return (
      <Layout.Horizontal gap>
        <Tooltip
          placement="leftBottom"
          title={`Something went wrong: ${action.error}`}
          children={glyph}
        />
        {button}
      </Layout.Horizontal>
    );
  } else {
    return button;
  }
}