import CloseIcon from 'mdi-react/CloseIcon';
import * as React from 'react';
import { Link } from 'react-router-dom';
import { fromEvent, Subscription } from 'rxjs';
import { catchError, filter, map } from 'rxjs/operators';
import { Key } from 'ts-key-enum';
import { Form } from '../../components/Form';
import { configurationCascade, parseJSON } from '../../settings/configuration';
import { eventLogger } from '../../tracking/eventLogger';
export class SavedQueryForm extends React.Component {
    constructor(props) {
        super(props);
        this.handleDescriptionChange = this.createInputChangeHandler('description');
        this.handleSubjectChange = this.createInputChangeHandler('subject');
        this.handleShowOnHomeChange = this.createInputChangeHandler('showOnHomepage');
        this.handleNotifyChange = this.createInputChangeHandler('notify');
        this.handleNotifySlackChange = this.createInputChangeHandler('notifySlack');
        this.subscriptions = new Subscription();
        this.isSubjectMissingSlackWebhook = () => {
            const chosen = this.state.subjectOptions.find(subjectOption => subjectOption.id === this.state.values.subject);
            if (!chosen) {
                return false;
            }
            return !this.state.slackWebhooks.get(chosen.id);
        };
        this.getConfigureSlackURL = () => {
            const chosen = this.state.subjectOptions.find(subjectOption => subjectOption.id === this.state.values.subject);
            if (!chosen) {
                return '';
            }
            if (chosen.__typename === 'Org') {
                return `/organizations/${chosen.name}/settings`;
            }
            if (chosen.__typename === 'User') {
                return `/settings`;
            }
            return ''; // unexpected
        };
        this.saveTargetName = () => {
            const chosen = this.state.subjectOptions
                .filter((subjectOption) => subjectOption.__typename === 'Org' || subjectOption.__typename === 'User')
                .find(subjectOption => subjectOption.id === this.state.values.subject);
            return chosen && configurationSubjectLabel(chosen, true);
        };
        this.handleSubmit = (event) => {
            event.preventDefault();
            this.setState({ isSubmitting: true });
            this.subscriptions.add(this.props
                .onSubmit(this.state.values)
                .pipe(catchError(error => {
                console.error(error);
                this.setState({ error });
                return [];
            }))
                .subscribe(this.props.onDidCommit));
        };
        this.handleInputFocus = (event) => {
            this.setState(() => ({ isFocused: true }));
        };
        this.handleInputBlur = (event) => {
            this.setState(() => ({ isFocused: false }));
        };
        this.handleQueryChange = (event) => {
            const newValues = Object.assign({}, this.state.values, { query: event.currentTarget.value });
            if (!this.state.sawUnsupportedNotifyQueryWarning && this.isUnsupportedNotifyQuery(newValues)) {
                this.setState({ sawUnsupportedNotifyQueryWarning: true });
                eventLogger.log('SavedSearchUnsupportedNotifyQueryWarning');
            }
            const newQuery = event.currentTarget.value;
            this.setState(prevState => ({
                values: Object.assign({}, prevState.values, { query: newQuery }),
            }));
        };
        const { defaultValues } = props;
        this.state = {
            values: {
                query: (defaultValues && defaultValues.query) || '',
                description: (defaultValues && defaultValues.description) || '',
                subject: (defaultValues && defaultValues.subject) || '',
                showOnHomepage: !!(defaultValues && defaultValues.showOnHomepage),
                notify: !!(defaultValues && defaultValues.notify),
                notifySlack: !!(defaultValues && defaultValues.notifySlack),
            },
            subjectOptions: [],
            isSubmitting: false,
            isFocused: false,
            sawUnsupportedNotifyQueryWarning: false,
            slackWebhooks: new Map(),
        };
    }
    componentDidMount() {
        this.subscriptions.add(configurationCascade.pipe(map(({ subjects }) => subjects)).subscribe(subjects => {
            const subject = subjects.find(s => !!s.id);
            this.setState(state => ({
                subjectOptions: subjects,
                values: Object.assign({}, state.values, { subject: state.values.subject || (subject && subject.id) || '' }),
            }));
            subjects.map(subject => {
                if (subject.latestSettings) {
                    let slackWebhookURL;
                    try {
                        const settings = parseJSON(subject.latestSettings.configuration.contents);
                        if (settings && settings['notifications.slack']) {
                            slackWebhookURL = settings['notifications.slack'].webhookURL;
                        }
                    }
                    catch (_a) {
                        slackWebhookURL = null;
                    }
                    this.setState(state => ({
                        slackWebhooks: state.slackWebhooks.set(subject.id, slackWebhookURL),
                    }));
                }
            });
        }));
        this.subscriptions.add(fromEvent(window, 'keydown')
            .pipe(filter(event => !this.state.isFocused && event.key === Key.Escape && !this.state.isSubmitting))
            .subscribe(() => this.props.onDidCancel()));
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        const { onDidCancel, title, submitLabel } = this.props;
        const { values: { query, description, subject, showOnHomepage, notify, notifySlack }, subjectOptions, isSubmitting, error, } = this.state;
        return (React.createElement(Form, { className: "saved-query-form", onSubmit: this.handleSubmit },
            React.createElement("button", { type: "reset", className: "btn btn-icon saved-query-form__close", onClick: onDidCancel },
                React.createElement(CloseIcon, { className: "icon-inline" })),
            React.createElement("h2", { className: "saved-query-form__title" }, title),
            React.createElement("div", { className: "form-group" },
                React.createElement("label", null, "Search query"),
                React.createElement("input", { type: "text", name: "query", className: "form-control", placeholder: "Query", onChange: this.handleQueryChange, value: query, required: true, autoCorrect: "off", spellCheck: false, autoCapitalize: "off", autoFocus: !query, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur })),
            React.createElement("div", { className: "form-group" },
                React.createElement("label", null, "Description of this search"),
                React.createElement("input", { type: "text", name: "description", className: "form-control", placeholder: "Description", onChange: this.handleDescriptionChange, value: description, required: true, autoFocus: !!query && !description, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur })),
            React.createElement("div", { className: "form-group" },
                React.createElement("label", null, "Save location"),
                React.createElement("div", { className: "saved-query-form__save-location" }, subjectOptions
                    .filter((subjectOption) => subjectOption.__typename === 'Org' || subjectOption.__typename === 'User')
                    .map((subjectOption, i) => (React.createElement("label", { className: "saved-query-form__save-location-options", key: i },
                    React.createElement("input", { className: "saved-query-form__save-location-input", onChange: this.handleSubjectChange, type: "radio", value: subjectOption.id, checked: subject === subjectOption.id }),
                    ' ',
                    configurationSubjectLabel(subjectOption))))),
                React.createElement("div", { className: "saved-query-form__save-location" },
                    React.createElement("span", { className: "saved-query-form__save-location-options" },
                        React.createElement("label", null,
                            React.createElement("input", { className: "saved-query-form__save-location-input", type: "checkbox", defaultChecked: showOnHomepage, onChange: this.handleShowOnHomeChange }),
                            ' ',
                            "Show on homepage")),
                    React.createElement("span", { className: "saved-query-form__save-location-options" },
                        React.createElement("label", { "data-tooltip": `Send email notifications to config owner (${this.saveTargetName()})` },
                            React.createElement("input", { className: "saved-query-form__save-location-input", type: "checkbox", defaultChecked: notify, onChange: this.handleNotifyChange }),
                            ' ',
                            "Email notifications")),
                    React.createElement("span", { className: "saved-query-form__save-location-options" },
                        React.createElement("label", { "data-tooltip": `Send Slack notifications to webhook defined in configuration for ${this.saveTargetName()}` },
                            React.createElement("input", { className: "saved-query-form__save-location-input", type: "checkbox", defaultChecked: notifySlack, onChange: this.handleNotifySlackChange }),
                            ' ',
                            "Slack notifications")))),
            this.isUnsupportedNotifyQuery(this.state.values) && (React.createElement("div", { className: "alert alert-warning mb-2" },
                React.createElement("strong", null, "Warning:"),
                " non-commit searches do not currently support notifications. Consider adding ",
                React.createElement("code", null, "type:diff"),
                " or ",
                React.createElement("code", null, "type:commit"),
                " to your query.")),
            notify &&
                !window.context.emailEnabled &&
                !this.isUnsupportedNotifyQuery(this.state.values) && (React.createElement("div", { className: "alert alert-warning mb-2" },
                React.createElement("strong", null, "Warning:"),
                " Sending emails is not currently configured on this Sourcegraph server.",
                ' ',
                this.props.user && this.props.user.siteAdmin
                    ? 'Use the email.smtp site configuration setting to enable sending emails.'
                    : 'Contact your server admin for more information.')),
            notifySlack &&
                this.isSubjectMissingSlackWebhook() && (React.createElement("div", { className: "alert alert-warning mb-2" },
                React.createElement("strong", null, "Required:"),
                ' ',
                React.createElement(Link, { target: "_blank", to: this.getConfigureSlackURL() }, "Configure a Slack webhook URL"),
                ' ',
                "to receive Slack notifications.")),
            error &&
                !isSubmitting && (React.createElement("div", { className: "alert alert-danger mb-2" },
                React.createElement("strong", null, "Error:"),
                " ",
                error.message)),
            React.createElement("div", null,
                React.createElement("button", { type: "submit", className: "btn btn-primary", disabled: !subject || isSubmitting }, submitLabel),
                ' ',
                React.createElement("button", { type: "reset", className: "btn btn-secondary", disabled: isSubmitting, onClick: onDidCancel }, "Cancel"))));
    }
    /**
     * Tells if the query is unsupported for sending notifications.
     */
    isUnsupportedNotifyQuery(v) {
        const notifying = v.notify || v.notifySlack;
        return notifying && !v.query.includes('type:diff') && !v.query.includes('type:commit');
    }
    /**
     * Returns an input change handler that updates the SavedQueryFields in the component's state
     *
     * @param key The key of saved query fields that a change of this input should update
     */
    createInputChangeHandler(key) {
        return event => {
            const { value, checked, type } = event.currentTarget;
            this.setState(state => ({
                values: Object.assign({}, state.values, { [key]: type === 'checkbox' ? checked : value }),
            }));
        };
    }
}
function configurationSubjectLabel(s, short) {
    switch (s.__typename) {
        case 'User':
            return short ? s.username : `${s.username} (user settings)`;
        case 'Org':
            return short ? s.name : `${s.name} (org settings)`;
    }
}
//# sourceMappingURL=SavedQueryForm.js.map