import { LoadingSpinner } from '@sourcegraph/react-loading-spinner';
import { upperFirst } from 'lodash';
import AddIcon from 'mdi-react/AddIcon';
import CheckCircleIcon from 'mdi-react/CheckCircleIcon';
import DoNotDisturbIcon from 'mdi-react/DoNotDisturbIcon';
import MapSearchIcon from 'mdi-react/MapSearchIcon';
import * as React from 'react';
import { merge, of, Subject, Subscription } from 'rxjs';
import { catchError, delay, distinctUntilChanged, map, switchMap, withLatestFrom } from 'rxjs/operators';
import { HeroPage } from '../components/HeroPage';
import { addRepository, checkMirrorRepositoryConnection, setRepositoryEnabled } from '../site-admin/backend';
import { eventLogger } from '../tracking/eventLogger';
import { asError, isErrorLike } from '../util/errors';
/**
 * A page informing the user that an error occurred while trying to display the repository. It
 * attempts to present the user with actions to solve the problem.
 */
export class RepositoryErrorPage extends React.PureComponent {
    constructor() {
        super(...arguments);
        this.state = {
            showAdd: false,
            showEnable: false,
        };
        this.componentUpdates = new Subject();
        this.addClicks = new Subject();
        this.enableClicks = new Subject();
        this.subscriptions = new Subscription();
        this.addRepository = () => this.addClicks.next();
        this.enableRepository = () => this.enableClicks.next();
    }
    componentDidMount() {
        eventLogger.logViewEvent('RepositoryError');
        // Show/hide add.
        this.subscriptions.add(this.componentUpdates
            .pipe(distinctUntilChanged((a, b) => a.repo === b.repo && a.error === b.error && a.viewerCanAdminister === b.viewerCanAdminister), switchMap(({ repo, error, viewerCanAdminister }) => {
            if (error === 'disabled' || !viewerCanAdminister) {
                return of({ showAdd: false, canAddOrError: undefined });
            }
            return merge(of({ showAdd: true, canAddOrError: undefined }), checkMirrorRepositoryConnection({ name: repo }).pipe(map(c => c.error === null), catchError(error => [asError(error)]), map(c => ({ canAddOrError: c }))));
        }))
            .subscribe(stateUpdate => this.setState(stateUpdate), error => console.error(error)));
        // Handle add.
        this.subscriptions.add(this.addClicks
            .pipe(withLatestFrom(this.componentUpdates), switchMap(([, { repo }]) => merge(of({ addedOrError: 'loading' }), addRepository(repo).pipe(switchMap(({ id }) => setRepositoryEnabled(id, true)), map(c => true), 
        // HACK: Delay for gitserver to report the repository as cloning (after
        // the call to setRepositoryEnabled above, which will trigger a clone).
        // Without this, there is a race condition where immediately after
        // clicking this enable button, gitserver reports revision-not-found and
        // not cloning-in-progress. We need it to report cloning-in-progress so
        // that the browser polls for the clone to be complete.
        //
        // See https://github.com/sourcegraph/sourcegraph/pull/9304.
        delay(1500), catchError(error => [asError(error)]), map(c => ({ addedOrError: c }))))))
            .subscribe(stateUpdate => {
            this.setState(stateUpdate);
            if (this.props.onDidAddRepository && stateUpdate.addedOrError === true) {
                this.props.onDidAddRepository();
            }
        }, error => console.error(error)));
        // Show/hide enable.
        this.subscriptions.add(this.componentUpdates
            .pipe(distinctUntilChanged((a, b) => a.repo === b.repo && a.error === b.error && a.viewerCanAdminister === b.viewerCanAdminister), map(({ error, viewerCanAdminister }) => ({
            showEnable: error === 'disabled' && viewerCanAdminister,
        })))
            .subscribe(stateUpdate => this.setState(stateUpdate), error => console.error(error)));
        // Handle enable.
        this.subscriptions.add(this.enableClicks
            .pipe(withLatestFrom(this.componentUpdates), switchMap(([, { repoID }]) => merge(of({ enabledOrError: 'loading' }), setRepositoryEnabled(repoID, true).pipe(map(c => true), 
        // HACK: Delay for gitserver to report the repository as cloning (after
        // the call to setRepositoryEnabled above, which will trigger a clone).
        // Without this, there is a race condition where immediately after
        // clicking this enable button, gitserver reports revision-not-found and
        // not cloning-in-progress. We need it to report cloning-in-progress so
        // that the browser polls for the clone to be complete.
        //
        // See https://github.com/sourcegraph/sourcegraph/pull/9304.
        delay(1500), catchError(error => [asError(error)]), map(c => ({ enabledOrError: c }))))))
            .subscribe(stateUpdate => {
            this.setState(stateUpdate);
            if (this.props.onDidUpdateRepository && stateUpdate.enabledOrError === true) {
                this.props.onDidUpdateRepository({ enabled: true });
            }
        }, error => console.error(error)));
        this.componentUpdates.next(this.props);
    }
    componentWillReceiveProps(props) {
        this.componentUpdates.next(props);
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        let title;
        let Icon;
        if (this.props.error === 'disabled') {
            title = 'Repository disabled';
            Icon = DoNotDisturbIcon;
        }
        else {
            title = 'Repository not found';
            Icon = MapSearchIcon;
        }
        return (React.createElement(HeroPage, { icon: Icon, title: title, subtitle: React.createElement("div", { className: "repository-error-page" },
                this.state.showAdd && (React.createElement("div", { className: "repository-error-page__section mt-3" },
                    React.createElement("div", { className: "repository-error-page__section-inner" },
                        React.createElement("div", { className: "repository-error-page__section-description" },
                            this.state.canAddOrError === undefined && (React.createElement(React.Fragment, null, "Checking whether this repository can be added...")),
                            (this.state.canAddOrError === false ||
                                isErrorLike(this.state.canAddOrError)) && (React.createElement(React.Fragment, null,
                                React.createElement("p", null, "The repository can't be added because it is not accessible from any code hosts configured on this site."),
                                React.createElement("p", null, "Check that this site is configured with a token that has access to this repository."))),
                            this.state.canAddOrError === true && (React.createElement(React.Fragment, null, "As a site admin, you can add this repository to Sourcegraph to allow users to search and view it."))),
                        React.createElement("div", { className: "repository-error-page__section-action" },
                            React.createElement("button", { className: "btn btn-primary repository-error-page__btn", onClick: this.addRepository, disabled: this.state.canAddOrError !== true ||
                                    this.state.addedOrError === 'loading' },
                                this.state.canAddOrError === undefined ||
                                    this.state.addedOrError === 'loading' ? (React.createElement(LoadingSpinner, { className: "icon-inline" })) : (React.createElement(AddIcon, { className: "icon-inline" })),
                                ' ',
                                "Add repository"))),
                    isErrorLike(this.state.addedOrError) && (React.createElement("div", { className: "alert alert-danger repository-error-page__alert mt-2" },
                        "Error adding repository: ",
                        upperFirst(this.state.addedOrError.message))))),
                this.state.showEnable && (React.createElement("div", { className: "repository-error-page__section mt-3" },
                    React.createElement("div", { className: "repository-error-page__section-inner" },
                        React.createElement("div", { className: "repository-error-page__section-description" }, "As a site admin, you can enable this repository to allow users to search and view it."),
                        React.createElement("div", { className: "repository-error-page__section-action" },
                            React.createElement("button", { className: "btn btn-primary repository-error-page__btn", onClick: this.enableRepository, disabled: this.state.enabledOrError === 'loading' },
                                this.state.enabledOrError !== 'loading' ? (React.createElement(LoadingSpinner, { className: "icon-inline" })) : (React.createElement(CheckCircleIcon, { className: "icon-inline" })),
                                ' ',
                                "Enable repository"))),
                    isErrorLike(this.state.enabledOrError) && (React.createElement("div", { className: "alert alert-danger repository-error-page__alert mt-2" },
                        "Error enabling repository: ",
                        upperFirst(this.state.enabledOrError.message))))),
                !this.state.showAdd &&
                    !this.state.showEnable && React.createElement("p", null, "To access this repository, contact the Sourcegraph admin.")) }));
    }
}
//# sourceMappingURL=RepositoryErrorPage.js.map