insomnia/packages/insomnia-app/app/ui/components/sync-pull-button.tsx
2022-02-25 13:21:35 +00:00

101 lines
2.5 KiB
TypeScript

import { autoBindMethodsForReact } from 'class-autobind-decorator';
import React, { PureComponent, ReactNode } from 'react';
import { connect } from 'react-redux';
import { AUTOBIND_CFG } from '../../common/constants';
import { VCS } from '../../sync/vcs/vcs';
import { RootState } from '../redux/modules';
import { selectActiveProject } from '../redux/selectors';
import { showError } from './modals';
type ReduxProps = ReturnType<typeof mapStateToProps>;
interface Props extends ReduxProps {
vcs: VCS;
branch: string;
onPull: (...args: any[]) => any;
disabled?: boolean;
className?: string;
children?: ReactNode;
}
interface State {
loading: boolean;
}
@autoBindMethodsForReact(AUTOBIND_CFG)
export class UnconnectedSyncPullButton extends PureComponent<Props, State> {
_timeout: NodeJS.Timeout | null = null;
state: State = {
loading: false,
};
async _handleClick() {
const { vcs, onPull, branch, project } = this.props;
this.setState({
loading: true,
});
const newVCS = vcs.newInstance();
const oldBranch = await newVCS.getBranch();
let failed = false;
try {
// Clone old VCS so we don't mess anything up while working on other projects
await newVCS.checkout([], branch);
await newVCS.pull([], project.remoteId);
} catch (err) {
showError({
title: 'Pull Error',
message: 'Failed to pull ' + branch,
error: err,
});
failed = true;
} finally {
// We actually need to checkout the old branch again because the VCS
// stores it on the filesystem. We should probably have a way to not
// have to do this hack
await newVCS.checkout([], oldBranch);
}
// Do this a bit later so the loading doesn't seem to stop too early
this._timeout = setTimeout(() => {
this.setState({
loading: false,
});
}, 400);
if (!failed) {
onPull?.();
}
}
componentWillUnmount() {
if (this._timeout !== null) {
clearTimeout(this._timeout);
}
}
render() {
const { className, children, disabled } = this.props;
const { loading } = this.state;
return (
<button className={className} onClick={this._handleClick} disabled={disabled}>
{loading && <i className="fa fa-spin fa-refresh space-right" />}
{children || 'Pull'}
</button>
);
}
}
const mapStateToProps = (state: RootState) => ({
project: selectActiveProject(state),
});
export const SyncPullButton = connect(
mapStateToProps,
null,
null,
{ forwardRef: true },
)(UnconnectedSyncPullButton);