var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class LauncherControl {
    make(options) {
        this.uiOptions = options;
        this.formControl = new LabeledFormControl(options, this.label());
        this.controlId = this.formControl.controlId;
        let col = document.createElement('div');
        col.className = "col-sm-6";
        let group = document.createElement('div');
        group.className = "input-group";
        col.appendChild(group);
        this.formControl.addControl(col);
        this.create(col, group);
        return this.formControl.host;
    }
}
class ImageControl extends LauncherControl {
    constructor(images, defaultImage, allowUnknown, lastUsedImage) {
        super();
        this.images = images;
        this.defaultImage = defaultImage;
        this.allowUnknown = allowUnknown;
        this.lastUsedImage = lastUsedImage;
    }
    create(column, group) {
        this.group = group;
        if (this.images && this.images.length > 0) {
            this.buildSelect();
        }
        else if (this.allowUnknown) {
            this.buildInput();
        }
        else if (this.defaultImage) {
            this.buildFixed();
        }
    }
    buildSelect() {
        var _a, _b;
        this.clear();
        this.select = document.createElement('select');
        this.select.className = this.uiOptions.select_class;
        this.select.id = this.controlId;
        this.select.addEventListener("change", () => {
            var _a;
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.select.value);
        });
        if (!this.defaultImage) {
            const def = document.createElement('option');
            def.value = "";
            def.text = "Default";
            this.select.add(def);
        }
        const lastUsedInImages = !!this.images.find(i => i.image === this.lastUsedImage);
        if (this.lastUsedImage !== undefined && this.allowUnknown && !lastUsedInImages) {
            const image = { image: this.lastUsedImage, workbenches: new Map() };
            this.images.push(image);
        }
        const imageGroups = {};
        const addImageToGroup = (prefix, image) => {
            if (imageGroups[prefix] !== undefined) {
                imageGroups[prefix].push(image);
                return;
            }
            imageGroups[prefix] = [image];
        };
        for (const val of this.images) {
            const lastSlash = val.image.lastIndexOf("/");
            if (lastSlash === -1) {
                addImageToGroup("", val.image);
                continue;
            }
            const prefix = val.image.slice(0, lastSlash);
            addImageToGroup(prefix, val.image);
        }
        const groups = Object.keys(imageGroups).sort((a, b) => {
            return a === "" ? 1 : a.localeCompare(b);
        });
        const emptyGroupTitle = groups.length === 1 ? "Available images" : "Other";
        for (const group of groups) {
            const optgroup = document.createElement('optgroup');
            optgroup.label = group === "" ? emptyGroupTitle : group;
            imageGroups[group].sort((a, b) => a.localeCompare(b));
            for (const image of imageGroups[group]) {
                const option = document.createElement('option');
                option.value = image;
                option.text = group === "" ? image : image.replace(group + "/", "");
                if (image === this.lastUsedImage) {
                    option.selected = true;
                }
                if (image === this.defaultImage) {
                    option.selected = option.selected || !lastUsedInImages;
                    option.text += " (default)";
                    optgroup.insertBefore(option, optgroup.firstElementChild);
                }
                else {
                    optgroup.appendChild(option);
                }
            }
            this.select.appendChild(optgroup);
        }
        if (this.allowUnknown) {
            const optgroup = document.createElement('optgroup');
            optgroup.label = "Custom image";
            const other = document.createElement('option');
            other.value = "other";
            other.text = "Enter custom image";
            optgroup.appendChild(other);
            this.select.appendChild(optgroup);
            this.select.addEventListener('change', () => {
                var _a;
                if (this.select.selectedIndex === this.select.options.length - 1) {
                    this.buildInput();
                    (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.input.value);
                }
            });
        }
        this.group.appendChild(this.select);
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, ((_b = this.select.firstChild) === null || _b === void 0 ? void 0 : _b.textContent) || '');
    }
    showImageList() {
        var _a;
        this.buildSelect();
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.select.value);
    }
    buildInput() {
        this.clear();
        this.input = document.createElement('input');
        this.input.type = "text";
        this.input.className = this.uiOptions.textbox_class;
        this.input.id = this.controlId;
        this.input.addEventListener('change', () => {
            var _a;
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.input.value);
        });
        this.group.appendChild(this.input);
        if (this.images && this.images.length > 0) {
            const more = document.createElement('a');
            more.className = this.uiOptions.link_label_class;
            more.tabIndex = 0;
            more.textContent = "Show list";
            more.addEventListener('click', this.showImageList.bind(this));
            more.addEventListener('keydown', (ev) => {
                if (ev.key === "Enter") {
                    this.showImageList();
                }
            });
            this.group.appendChild(more);
        }
        else {
            if (this.defaultImage) {
                this.input.placeholder = this.defaultImage;
            }
            else {
                this.input.placeholder = "Default";
            }
        }
    }
    buildFixed() {
        const fixed = document.createElement('p');
        fixed.id = this.controlId;
        if (this.defaultImage) {
            this.fixed = this.defaultImage;
            fixed.textContent = this.defaultImage;
        }
        else {
            this.fixed = "";
            fixed.textContent = "Default";
        }
        this.group.appendChild(fixed);
    }
    value() {
        if (this.select)
            return this.select.options[this.select.selectedIndex].value;
        else if (this.input) {
            if (this.input.value.length == 0 &&
                this.input.placeholder.length != 0) {
                return this.input.placeholder;
            }
            return this.input.value.trim();
        }
        else if (this.fixed)
            return this.fixed;
        return "";
    }
    set(value, add) {
        var _a;
        if (this.select) {
            let found = false;
            for (let i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    this.select.options[i].text += " (current)";
                    found = true;
                    break;
                }
            }
            if (!found && add) {
                const option = document.createElement('option');
                option.value = value;
                option.text = value + " (current)";
                this.select.prepend(option);
                this.select.selectedIndex = 0;
            }
        }
        else if (this.input && add) {
            this.input.value = value;
        }
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, value);
    }
    label() {
        return "Image";
    }
    clear() {
        this.group.innerHTML = "";
        this.select = null;
        this.input = null;
    }
}
var ShowClusterType;
(function (ShowClusterType) {
    ShowClusterType["All"] = "all";
    ShowClusterType["Interactive"] = "interactive";
    ShowClusterType["NonInteractive"] = "non-interactive";
})(ShowClusterType || (ShowClusterType = {}));
class LimitInput {
    constructor(input, hint, uiOptions, limit, units) {
        this.input = input;
        this.hint = hint;
        this.uiOptions = uiOptions;
        this.limit = limit;
        this.units = units;
        if (typeof this.limit.defaultValue === "string") {
            this.input.value = this.formatNumber(this.limit.defaultValue);
            this.input.placeholder = this.formatNumber(this.limit.defaultValue) + " " + units;
        }
        else {
            this.input.placeholder = "Default";
        }
        this.input.addEventListener("blur", () => {
            this.validateInput();
        });
        this.clearHint();
    }
    formatNumber(num) {
        let parsed = parseFloat(num);
        if (isNaN(parsed)) {
            return num;
        }
        if (this.units === "GB") {
            parsed = parsed / 1024.0;
        }
        return Number(parsed.toFixed(2)).toString();
    }
    clearHint() {
        this.input.className = this.uiOptions.textbox_class;
        this.hint.className = this.uiOptions.input_hint_class;
        if (typeof this.limit.maxValue === "string") {
            this.hint.innerText = "Maximum " + this.formatNumber(this.limit.maxValue) + " " + this.units;
        }
        else {
            this.hint.style.display = "none";
        }
    }
    showError(error) {
        this.input.className = this.uiOptions.textbox_error_class;
        this.hint.className = this.uiOptions.input_hint_error_class;
        this.hint.style.display = "";
        this.hint.innerText = error;
    }
    validateInput() {
        let value = this.value();
        if (value === "") {
            this.clearHint();
            return true;
        }
        let num = parseFloat(value);
        if (isNaN(num)) {
            this.showError("Enter a number.");
            return false;
        }
        let allowZero = false;
        switch (this.limit.type) {
            case "cpuCount":
            case "cpuTime":
            case "memory":
            case "memorySwap":
                allowZero = false;
                break;
            default:
                allowZero = true;
                break;
        }
        if (num < 0) {
            this.showError("Enter a positive number.");
            return false;
        }
        if (!allowZero && num == 0) {
            this.showError("Enter a number greater than 0.");
            return false;
        }
        if (typeof this.limit.maxValue === "string") {
            let max = parseFloat(this.limit.maxValue);
            if (!isNaN(max) && num > max) {
                this.showError("Enter a maximum of " +
                    this.formatNumber(this.limit.maxValue) + " " +
                    this.units + ".");
                return false;
            }
        }
        this.clearHint();
        return true;
    }
    resourceLimit() {
        return this.limit;
    }
    value() {
        let value = this.input.value.trim();
        if (this.units !== "GB") {
            return value;
        }
        const parsed = parseFloat(value);
        if (isNaN(parsed)) {
            return value;
        }
        return (parsed * 1024.0).toString();
    }
    set(value) {
        this.input.value = this.formatNumber(value);
    }
}
class QueueControl extends LauncherControl {
    constructor(queues, defaultQueue = '') {
        super();
        this.queues = queues;
        this.defaultQueue = defaultQueue;
    }
    create(column, group) {
        this.select = document.createElement('select');
        this.select.className = this.uiOptions.select_class;
        this.select.id = this.controlId;
        for (let val of this.queues) {
            let option = document.createElement('option');
            option.value = val;
            option.text = val;
            if (val === this.defaultQueue) {
                option.selected = true;
                option.text += " (default)";
                this.select.prepend(option);
            }
            else {
                this.select.appendChild(option);
            }
        }
        group.appendChild(this.select);
    }
    value() {
        return this.select.options[this.select.selectedIndex].value;
    }
    set(value) {
        for (let i = 0; i < this.select.options.length; i++) {
            if (this.select.options[i].value === value) {
                this.select.selectedIndex = i;
                break;
            }
        }
    }
    label() {
        return "Queue";
    }
}
class PlacementControl extends LauncherControl {
    constructor(name, values) {
        super();
        this.name = name;
        this.values = values;
        this.select = null;
        this.input = null;
    }
    label() {
        return this.name.slice(0, 1).toUpperCase() + this.name.slice(1);
    }
    create(column, group) {
        if (this.values.length > 0) {
            let select = document.createElement('select');
            select.className = this.uiOptions.select_class;
            select.id = this.controlId;
            let defaultVal = document.createElement('option');
            defaultVal.value = "";
            defaultVal.text = "Default";
            select.add(defaultVal);
            for (let val of this.values) {
                let option = document.createElement('option');
                option.value = val;
                option.text = val;
                select.add(option);
            }
            select.addEventListener('change', () => {
                var _a;
                (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, select.value);
            });
            this.select = select;
            group.appendChild(select);
        }
        else {
            this.input = document.createElement('input');
            this.input.type = "text";
            this.input.className = this.uiOptions.textbox_class;
            this.input.id = this.controlId;
            this.input.addEventListener('change', () => {
                var _a;
                (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.input.value);
            });
            group.appendChild(this.input);
        }
    }
    constraint() {
        let val = "";
        if (this.input !== null)
            val = this.input.value.trim();
        else if (this.select !== null)
            val = this.select.options[this.select.selectedIndex].value;
        if (val === "")
            return null;
        return {
            name: this.name,
            value: val
        };
    }
    set(value) {
        if (this.input !== null) {
            this.input.value = value;
        }
        else if (this.select !== null) {
            for (let i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    break;
                }
            }
        }
    }
    enable() {
        if (this.input !== null) {
            this.input.disabled = false;
            return;
        }
        this.select.disabled = false;
    }
    disable() {
        if (this.input !== null) {
            this.input.disabled = true;
            return;
        }
        this.select.disabled = true;
    }
}
class ResourceControl extends LauncherControl {
    constructor(limit) {
        super();
        this.limit = limit;
    }
    resourceUnits(limitType) {
        let units = "";
        switch (limitType) {
            case "cpuCount":
                units = "CPUs";
                break;
            case "memory":
            case "memorySwap":
                units = "GB";
                break;
        }
        return units;
    }
    label() {
        let description = "";
        switch (this.limit.type) {
            case "cpuCount":
                description = "CPUs";
                break;
            case "cpuTime":
                description = "CPU Time";
                break;
            case "memory":
                description = "Memory";
                break;
            case "memorySwap":
                description = "Swap";
                break;
            default:
                description = this.limit.type;
                break;
        }
        return description;
    }
    create(column, group) {
        let units = this.resourceUnits(this.limit.type);
        let controlParent = group;
        let groupTable;
        let groupTableRow;
        if (this.uiOptions.table_layout) {
            groupTable = document.createElement('table');
            groupTable.setAttribute("role", "presentation");
            groupTable.style.setProperty("cellspacing", "0");
            groupTable.style.setProperty("cellpadding", "0");
            groupTable.createTFoot();
            groupTableRow = groupTable.createTBody().insertRow();
            controlParent = groupTableRow.insertCell();
        }
        let input = document.createElement('input');
        input.type = "text";
        input.className = this.uiOptions.textbox_class;
        input.id = this.controlId;
        controlParent.appendChild(input);
        if (units !== "") {
            if (this.uiOptions.table_layout) {
                controlParent = groupTableRow.insertCell();
            }
            let unitLabel = document.createElement('div');
            unitLabel.innerText = units;
            unitLabel.className = this.uiOptions.input_addon_class;
            controlParent.appendChild(unitLabel);
        }
        if (this.uiOptions.table_layout) {
            group.appendChild(groupTable);
        }
        let hint = document.createElement('small');
        column.appendChild(hint);
        this.input = new LimitInput(input, hint, this.uiOptions, this.limit, units);
        input.addEventListener('blur', () => {
            var _a;
            if (!this.input.validateInput()) {
                return;
            }
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.input.value());
        });
    }
    value() {
        if (this.input.value() === "") {
            return null;
        }
        return {
            type: this.limit.type,
            value: this.input.value()
        };
    }
    set(value) {
        this.input.set(value);
    }
}
class LabeledFormControl {
    constructor(uiOptions, labelText) {
        this.uiOptions = uiOptions;
        this.host = document.createElement('div');
        this.host.className = uiOptions.form_group_class;
        this.host.id = LabeledFormControl.idFromLabel(labelText).replace('rstudio_label_', 'rstudio_group_');
        this.controlParent = this.host;
        this.controlId = LabeledFormControl.idFromLabel(labelText);
        let label = document.createElement('label');
        label.innerText = labelText;
        label.className = uiOptions.label_class;
        label.htmlFor = this.controlId;
        label.style.wordWrap = "break-word";
        if (uiOptions.table_layout) {
            this.groupTable = document.createElement('table');
            this.groupTable.setAttribute("role", "presentation");
            this.groupTable.style.setProperty("cellspacing", "0");
            this.groupTable.style.setProperty("cellpadding", "0");
            this.groupTable.createTFoot();
            this.row = this.groupTable.createTBody().insertRow();
            this.controlParent = this.row.insertCell();
        }
        this.controlParent.appendChild(label);
    }
    addControl(controlElement) {
        if (this.controlParent === null) {
            console.log("Assertion failure: incorrect usage of LabeledFormControl");
            return;
        }
        if (this.uiOptions.table_layout) {
            this.controlParent = this.row.insertCell();
        }
        this.controlParent.appendChild(controlElement);
        if (this.uiOptions.table_layout) {
            this.host.appendChild(this.groupTable);
        }
        this.controlParent = null;
    }
    static idSafeString(text) {
        var id = text.replace(/[^a-zA-Z0-9]/g, "_");
        id = id.replace(/_+/g, "_");
        id = id.replace(/^_+/g, "");
        id = id.replace(/_+$/g, "");
        return id.toLowerCase();
    }
    static idFromLabel(label) {
        return "rstudio_label_" + LabeledFormControl.idSafeString(label);
    }
}
class ResourceProfileControl extends LauncherControl {
    constructor(profiles) {
        super();
        this.profiles = profiles;
        this.select = null;
    }
    label() {
        return 'Resource Profile';
    }
    create(column, group) {
        var _a;
        var prettifyName = (p) => p.replace(/[-_]/g, ' ').
            replace(/(^|\s)\S/g, (t) => t.toUpperCase());
        let select = document.createElement('select');
        select.className = this.uiOptions.select_class;
        select.id = this.controlId;
        for (let profile of this.profiles) {
            let option = document.createElement('option');
            option.text = (_a = profile.displayName) !== null && _a !== void 0 ? _a : prettifyName(profile.name);
            option.value = profile.name;
            select.add(option);
        }
        select.addEventListener('change', () => {
            var _a;
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, select.value);
        });
        this.select = select;
        group.appendChild(select);
    }
    isCustom() {
        var _a;
        return ((_a = this.select) === null || _a === void 0 ? void 0 : _a.options[this.select.selectedIndex].value) === 'custom';
    }
    profile() {
        var _a;
        return (_a = this.select) === null || _a === void 0 ? void 0 : _a.options[this.select.selectedIndex].value;
    }
    limits() {
        const current = this.profile();
        for (let profile of this.profiles) {
            if (current == profile.name) {
                return profile.limits;
            }
        }
        return new Array();
    }
    queue() {
        const current = this.profile();
        for (let profile of this.profiles) {
            if (current == profile.name) {
                return profile.queue;
            }
        }
        return null;
    }
    constraints() {
        var _a;
        const current = this.profile();
        for (let profile of this.profiles) {
            if (current == profile.name) {
                return (_a = profile.placementConstraints) !== null && _a !== void 0 ? _a : [];
            }
        }
        return new Array();
    }
    set(value) {
        if (value === null) {
            return;
        }
        if (this.select !== null) {
            for (let i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    break;
                }
            }
        }
    }
}
class DatabricksInstanceControl {
    constructor(instances, defaultInstance) {
        this.defaultInstance = defaultInstance;
        this.button = null;
        this.span = null;
        this.error = null;
        this.select = null;
        this.onChange = null;
        this.instances = instances;
    }
    make(options) {
        var _a;
        const prettifyName = (p) => {
            return p.replace(/[-_]/g, " ").replace(/(^|\s)\S/g, (t) => t.toUpperCase());
        };
        let control = new LabeledFormControl(options, 'Databricks Workspace');
        let select = document.createElement('select');
        select.className = options.select_class;
        select.id = control.controlId;
        for (let instance of this.instances) {
            let option = document.createElement('option');
            option.value = instance.url;
            const instanceDisplayName = (_a = instance.display_name) !== null && _a !== void 0 ? _a : prettifyName(instance.name);
            option.text = instanceDisplayName + ' (' + instance.url + ')';
            select.add(option);
        }
        let option = document.createElement('option');
        option.value = 'None';
        option.text = 'None';
        select.add(option);
        if (this.defaultInstance !== null) {
            select.value = this.defaultInstance || 'None';
        }
        let button = document.createElement('button');
        button.className = 'btn btn-primary';
        button.textContent = 'Sign In';
        button.onclick = (e) => {
            e.preventDefault();
            this.setError(null);
            button.disabled = true;
            button.textContent = 'Signing In...';
            this.onTriggerSignIn().catch((e) => {
                var _a;
                button.disabled = false;
                button.textContent = "Retry";
                this.setError(e);
                (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
            });
        };
        this.button = button;
        let span = document.createElement('span');
        span.className = 'input-group-text';
        span.textContent = 'Signed In';
        this.span = span;
        let error = document.createElement('small');
        error.className = 'input-error';
        this.error = error;
        this.setError(null);
        select.addEventListener('change', () => {
            var _a;
            this.setError(null);
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
            this.restyle(this.instance());
        });
        this.select = select;
        this.restyle(this.instance());
        let append = document.createElement('div');
        append.className = "input-group-append";
        append.appendChild(this.span);
        append.appendChild(this.button);
        let errorAppend = document.createElement('div');
        errorAppend.className = "col-12 error-group-append";
        errorAppend.appendChild(this.error);
        let host = document.createElement('div');
        host.className = "col-sm-6 input-group";
        host.appendChild(this.select);
        host.appendChild(append);
        host.appendChild(errorAppend);
        control.addControl(host);
        return control.host;
    }
    isNone() {
        var _a;
        return ((_a = this.select) === null || _a === void 0 ? void 0 : _a.value) ? this.select.value === "None" : true;
    }
    instance() {
        if (this.isNone()) {
            return null;
        }
        let instance = this.instances.find(x => { var _a; return x.url === ((_a = this.select) === null || _a === void 0 ? void 0 : _a.value); });
        return instance === undefined ? null : instance;
    }
    onTriggerSignIn() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            let instance = this.instance();
            if (!instance) {
                return;
            }
            yield instance.oauth_client.startAuthCodeFlow();
            instance.authenticated = true;
            this.restyle(instance);
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
        });
    }
    restyle(instance) {
        if (instance === null) {
            this.button.style.display = 'none';
            this.button.ariaHidden = 'true';
            this.span.style.display = 'none';
            this.span.ariaHidden = 'true';
            return;
        }
        this.button.disabled = instance.authenticated || !instance.oauth_client;
        this.button.textContent = 'Sign In';
        this.button.style.display = instance.authenticated ? 'none' : '';
        this.button.ariaHidden = instance.authenticated ? 'true' : 'false';
        this.span.style.display = instance.authenticated ? '' : 'none';
        this.span.ariaHidden = instance.authenticated ? 'false' : 'true';
    }
    setError(err) {
        this.error.style.display = err ? '' : 'none';
        this.error.ariaHidden = err ? 'false' : 'true';
        this.error.textContent = err ? err.message : '';
    }
}
const IDENTIFIER_REGEX = /^[a-zA-Z_][a-zA-Z0-9_$]*$/;
const isQuotedIdentifier = (identifier) => {
    return identifier.startsWith('"') && identifier.endsWith('"');
};
const toValidIdentifier = (identifier) => {
    if (isQuotedIdentifier(identifier)) {
        return identifier;
    }
    else if (identifier !== '' && !IDENTIFIER_REGEX.test(identifier)) {
        return `"${identifier}"`;
    }
    ;
    return identifier;
};
class SnowflakeAccountControl {
    constructor(accounts, defaultAccount) {
        this.defaultAccount = defaultAccount;
        this.button = null;
        this.span = null;
        this.error = null;
        this.select = null;
        this.onChange = null;
        this.accounts = accounts;
    }
    make(options) {
        let control = new LabeledFormControl(options, 'Snowflake Account');
        let select = document.createElement('select');
        select.className = options.select_class;
        select.id = control.controlId;
        for (let account of this.accounts) {
            let option = document.createElement('option');
            option.value = account.accountId;
            option.text = account.display_name ? account.display_name :
                account.accountId;
            select.add(option);
        }
        let option = document.createElement('option');
        option.value = 'None';
        option.text = 'None';
        select.add(option);
        if (this.defaultAccount !== null) {
            select.value = this.defaultAccount || 'None';
        }
        let button = document.createElement('button');
        button.className = 'btn btn-primary';
        button.textContent = 'Sign In';
        button.onclick = (e) => {
            e.preventDefault();
            this.setError(null);
            button.disabled = true;
            button.textContent = 'Signing In...';
            this.onTriggerSignIn().catch((e) => {
                var _a;
                button.disabled = false;
                button.textContent = "Retry";
                this.setError(e);
                (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
            });
        };
        this.button = button;
        let span = document.createElement('span');
        span.className = 'input-group-text';
        span.textContent = 'Signed In';
        this.span = span;
        let error = document.createElement('small');
        error.className = 'input-error';
        this.error = error;
        this.setError(null);
        select.addEventListener('change', () => {
            var _a;
            this.setError(null);
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
            this.restyle(this.account());
        });
        this.select = select;
        this.restyle(this.account());
        let append = document.createElement('div');
        append.className = "input-group-append";
        append.appendChild(this.span);
        append.appendChild(this.button);
        let errorAppend = document.createElement('div');
        errorAppend.className = "col-12 error-group-append";
        errorAppend.appendChild(this.error);
        let host = document.createElement('div');
        host.className = "col-sm-6 input-group";
        host.appendChild(this.select);
        host.appendChild(append);
        host.appendChild(errorAppend);
        control.addControl(host);
        return control.host;
    }
    isNone() {
        var _a;
        return ((_a = this.select) === null || _a === void 0 ? void 0 : _a.value) ? this.select.value === "None" : true;
    }
    account() {
        if (this.isNone()) {
            return null;
        }
        let account = this.accounts.find(x => { var _a; return x.accountId === ((_a = this.select) === null || _a === void 0 ? void 0 : _a.value); });
        return account === undefined ? null : account;
    }
    extractRoleFromScope(scope) {
        let roleName = '';
        if (scope.indexOf('session:role:') !== -1) {
            roleName = toValidIdentifier(scope.slice(scope.indexOf('session:role:') + 'session:role:'.length));
        }
        return roleName;
    }
    onTriggerSignIn() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            let account = this.account();
            if (!account) {
                return;
            }
            const scope = yield account.oauth_client.startAuthCodeFlow();
            let role = this.extractRoleFromScope(scope);
            account.authenticated = true;
            account.role = role;
            this.restyle(account);
            (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);
        });
    }
    restyle(account) {
        if (account === null) {
            this.button.style.display = 'none';
            this.button.ariaHidden = 'true';
            this.span.style.display = 'none';
            this.span.ariaHidden = 'true';
            return;
        }
        this.button.disabled = account.authenticated || !account.oauth_client;
        this.button.textContent = 'Sign In';
        this.button.style.display = account.authenticated ? 'none' : '';
        this.button.ariaHidden = account.authenticated ? 'true' : 'false';
        this.span.style.display = account.authenticated ? '' : 'none';
        this.span.ariaHidden = account.authenticated ? 'false' : 'true';
    }
    setError(err) {
        this.error.style.display = err ? '' : 'none';
        this.error.ariaHidden = err ? 'false' : 'true';
        this.error.textContent = err ? err.message : '';
    }
}
class LauncherUI {
    constructor(host, rpcUrlPrefix, input, uiOptions) {
        this.host = host;
        this.rpcUrlPrefix = rpcUrlPrefix;
        this.input = input;
        this.uiOptions = uiOptions;
        this.sessionPrereqs = {
            lang: true,
            databricks: true,
            snowflake: true
        };
    }
    canStartSession() {
        for (const key in this.sessionPrereqs) {
            if (!this.sessionPrereqs[key]) {
                return false;
            }
        }
        return true;
    }
    initialize() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            this.host.textContent = "Loading...";
            this.availableClusters = [];
            this.uiOptions = Object.assign({ fieldset_class: "", form_group_class: "form-group", input_addon_class: "input-group-addon", input_hint_class: "form-text text-muted", input_hint_error_class: "form-text text-muted input-error", job_name_label: "Session Name", job_name_placeholder: "New Session", label_class: "col-sm-3 control-label", link_label_class: "", select_class: "form-control", show_legend: true, table_layout: false, textbox_class: "form-control", textbox_error_class: "form-control input-error" }, this.uiOptions);
            const metas = document.getElementsByTagName("meta");
            let csrfToken = "";
            for (let i = 0; i < metas.length; i++) {
                if (metas[i].getAttribute("name") === "rs-csrf-token") {
                    const val = metas[i].getAttribute("content");
                    if (val != null) {
                        csrfToken = val;
                    }
                }
            }
            if (typeof this.rpcUrlPrefix === 'function') {
                const resultText = yield this.rpcUrlPrefix();
                let result = null;
                try {
                    result = JSON.parse(resultText);
                }
                catch (e) {
                    this.host.textContent = "Failed to parse result: " + resultText;
                    console.error(e);
                    return;
                }
                try {
                    this.renderUI(result, this.uiOptions);
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                }
                catch (e) {
                    this.host.textContent = "Failed to render UI from server result: " + JSON.stringify(result, null, 2);
                    console.error(e);
                }
                return;
            }
            const xhr = new XMLHttpRequest();
            xhr.open('post', this.rpcUrlPrefix + '/job_launcher_rpc/get_info');
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.timeout = 30000;
            if (csrfToken !== "") {
                xhr.setRequestHeader('X-RS-CSRF-Token', csrfToken);
            }
            xhr.onload = () => {
                var _a;
                let result = null;
                try {
                    result = JSON.parse(xhr.responseText);
                }
                catch (e) {
                    this.host.textContent = "Failed to parse result: " + xhr.responseText;
                    return;
                }
                if (result.hasOwnProperty("error")) {
                    console.log("Failed to execute job_launcher_rpc/get_info");
                    console.log(result);
                    this.renderError(result.error);
                    return;
                }
                try {
                    this.renderUI(result, this.uiOptions);
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                }
                catch (e) {
                    this.host.textContent = "Failed to render UI from server result: " + xhr.responseText;
                }
            };
            xhr.onerror = () => {
                this.host.textContent = xhr.statusText;
            };
            xhr.send(JSON.stringify({ method: "get_info" }));
        });
    }
    setOnLaunchSpecModified(value) {
        this.onLaunchSpecModified = value;
    }
    setOnUiRender(value) {
        this.onUiRender = value;
    }
    renderError(error) {
        this.host.innerHTML = "";
        let bar = document.createElement('div');
        bar.className = "alert alert-danger";
        bar.textContent = "Error " + error.code + ": " + error.message;
        this.host.appendChild(bar);
        let msg = document.createElement('p');
        msg.textContent = error.error.category + " error " + error.error.code + ": " +
            error.error.message;
        this.host.appendChild(msg);
    }
    renderUI(info, uiOptions) {
        var _a, _b, _c, _d, _e;
        this.info = info;
        this.host.innerHTML = "";
        let form = document.createElement('form');
        form.className = "form-horizontal";
        let nameControl = new LabeledFormControl(this.uiOptions, uiOptions.job_name_label);
        let nameHost = document.createElement('div');
        nameHost.className = "col-sm-6 input-group";
        let nameInput = document.createElement('input');
        nameInput.type = "text";
        nameInput.placeholder = uiOptions.job_name_placeholder;
        nameInput.maxLength = 30;
        nameInput.className = this.uiOptions.textbox_class;
        nameInput.id = nameControl.controlId;
        nameHost.appendChild(nameInput);
        this.name = nameInput;
        nameControl.addControl(nameHost);
        form.appendChild(nameControl.host);
        let dirty = false;
        nameInput.addEventListener("change", () => {
            dirty = true;
        });
        let workbenchControl = new LabeledFormControl(this.uiOptions, "Editor");
        let workbenchHost = document.createElement('div');
        workbenchHost.className = "col-sm-6 input-group";
        this.workbench = document.createElement('select');
        this.workbench.id = workbenchControl.controlId;
        if (!this.input.show_workbenches) {
            workbenchControl.host.style.display = "none";
        }
        const allWorkbenches = Object.keys(info.workbenches);
        const filteredWorkbenches = this.input.workbenches.filter(workbench => allWorkbenches.indexOf(workbench) !== -1);
        this.input.workbenches = filteredWorkbenches;
        this.workbench.className = this.uiOptions.select_class;
        for (let workbench of filteredWorkbenches) {
            let option = document.createElement('option');
            option.value = workbench;
            option.text = workbench;
            this.workbench.add(option);
        }
        nameInput.value = this.input.default_names[0];
        this.workbench.addEventListener("change", (evt) => {
            var _a;
            let target = evt.target;
            if (!dirty) {
                nameInput.value = this.input.default_names[target.selectedIndex] || this.input.default_names[0];
            }
            this.populateAvailableClusters(filteredWorkbenches[target.selectedIndex]);
            this.showClusterOptions(this.cluster.selectedIndex);
            (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
        });
        this.workbench.selectedIndex = 0;
        const workbenchName = this.input.workbenches[0];
        workbenchHost.appendChild(this.workbench);
        workbenchControl.addControl(workbenchHost);
        form.appendChild(workbenchControl.host);
        let clusterControl = new LabeledFormControl(this.uiOptions, "Cluster");
        let clusterHost = document.createElement('div');
        clusterHost.className = "col-sm-6 input-group";
        this.cluster = document.createElement('select');
        this.cluster.id = clusterControl.controlId;
        this.cluster.className = this.uiOptions.select_class;
        this.populateAvailableClusters(workbenchName);
        const controlClusterVisibility = () => {
            const hide = this.availableClusters.length === 1;
            clusterControl.host.style.display = hide ? 'none' : '';
            clusterControl.host.ariaHidden = `${hide}`;
        };
        controlClusterVisibility();
        this.workbench.addEventListener("change", controlClusterVisibility);
        this.cluster.addEventListener("change", () => {
            var _a;
            this.showClusterOptions(this.cluster.selectedIndex);
            (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
        });
        clusterHost.appendChild(this.cluster);
        clusterControl.addControl(clusterHost);
        form.appendChild(clusterControl.host);
        if (this.input.aws_roles && this.input.aws_roles.length > 0) {
            let awsRoleControl = new LabeledFormControl(this.uiOptions, 'AWS Role');
            this.awsRole = document.createElement('select');
            this.awsRole.id = awsRoleControl.controlId;
            this.awsRole.className = this.uiOptions.select_class;
            this.awsRole.addEventListener('change', () => {
                var _a;
                (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
            });
            for (const role of this.input.aws_roles) {
                let option = document.createElement('option');
                option.value = role;
                option.text = role;
                this.awsRole.add(option);
            }
            let option = document.createElement('option');
            option.value = 'None';
            option.text = 'None';
            this.awsRole.add(option);
            let awsRoleHost = document.createElement('div');
            awsRoleHost.className = "col-sm-6 input-group";
            awsRoleHost.appendChild(this.awsRole);
            awsRoleControl.addControl(awsRoleHost);
            form.appendChild(awsRoleControl.host);
            if (this.input.default_aws_role !== null) {
                this.awsRole.value = this.input.default_aws_role || 'None';
            }
            const controlVisibility = () => {
                const workbench = this.input.workbenches[this.workbench.selectedIndex];
                const hide = workbench !== 'RStudio' && workbench !== 'VS Code';
                awsRoleControl.host.style.display = hide ? 'none' : '';
                awsRoleControl.host.ariaHidden = `${hide}`;
            };
            this.workbench.addEventListener("change", controlVisibility);
        }
        if (this.input.databricks_instances && this.input.databricks_instances.length > 0) {
            const databricksInstance = new DatabricksInstanceControl(this.input.databricks_instances, this.input.default_databricks_instance);
            this.databricksInstance = databricksInstance;
            const control = databricksInstance.make(this.uiOptions);
            form.appendChild(control);
            const placeholder = document.createElement('div');
            this.sessionPrereqs.databricks = (_b = (_a = this.databricksInstance.instance()) === null || _a === void 0 ? void 0 : _a.authenticated) !== null && _b !== void 0 ? _b : true;
            databricksInstance.onChange = () => {
                var _a, _b;
                const instance = databricksInstance.instance();
                if (!instance) {
                    this.sessionPrereqs.databricks = true;
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                    return;
                }
                this.sessionPrereqs.databricks = instance.authenticated;
                (_b = this.onLaunchSpecModified) === null || _b === void 0 ? void 0 : _b.call(this, this.getLaunchSpec());
            };
            const controlVisibility = (noUpdate = false) => {
                var _a;
                const workbench = this.input.workbenches[this.workbench.selectedIndex];
                const hide = workbench !== 'RStudio' && workbench !== 'VS Code';
                try {
                    form.replaceChild(hide ? placeholder : control, hide ? control : placeholder);
                }
                catch (e) { }
                if (!hide) {
                    if (!noUpdate) {
                        databricksInstance.onChange();
                    }
                }
                else {
                    this.sessionPrereqs.databricks = true;
                    if (!noUpdate) {
                        (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                    }
                }
            };
            controlVisibility(true);
            this.workbench.addEventListener("change", () => { controlVisibility(); });
        }
        if (this.input.snowflake_accounts && this.input.snowflake_accounts.length > 0) {
            const snowflakeAccount = new SnowflakeAccountControl(this.input.snowflake_accounts, this.input.default_snowflake_account);
            const control = snowflakeAccount.make(this.uiOptions);
            form.appendChild(control);
            const placeholder = document.createElement('div');
            this.sessionPrereqs.snowflake = (_d = (_c = snowflakeAccount.account()) === null || _c === void 0 ? void 0 : _c.authenticated) !== null && _d !== void 0 ? _d : true;
            snowflakeAccount.onChange = () => {
                var _a, _b;
                const account = snowflakeAccount.account();
                if (!account) {
                    this.sessionPrereqs.snowflake = true;
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                    return;
                }
                this.sessionPrereqs.snowflake = account.authenticated;
                (_b = this.onLaunchSpecModified) === null || _b === void 0 ? void 0 : _b.call(this, this.getLaunchSpec());
            };
            const controlVisibility = (noUpdate = false) => {
                var _a;
                const workbench = this.input.workbenches[this.workbench.selectedIndex];
                const hide = workbench !== 'RStudio' && workbench !== 'VS Code';
                try {
                    form.replaceChild(hide ? placeholder : control, hide ? control : placeholder);
                }
                catch (e) { }
                if (!hide) {
                    if (!noUpdate) {
                        snowflakeAccount.onChange();
                    }
                }
                else {
                    this.sessionPrereqs.snowflake = true;
                    if (!noUpdate) {
                        (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                    }
                }
            };
            controlVisibility(true);
            this.snowflakeAccount = snowflakeAccount;
            this.workbench.addEventListener("change", () => controlVisibility());
        }
        this.options = document.createElement('fieldset');
        if (uiOptions.fieldset_class.length > 0)
            this.options.className = this.uiOptions.fieldset_class;
        form.appendChild(this.options);
        this.host.appendChild(form);
        this.showClusterOptions(this.cluster.selectedIndex);
        (_e = this.onUiRender) === null || _e === void 0 ? void 0 : _e.call(this, info, uiOptions);
    }
    hasCollection(collection) {
        return typeof collection !== "undefined" &&
            collection !== null &&
            collection.length > 0;
    }
    populateAvailableClusters(workbench) {
        for (let i = this.cluster.options.length - 1; i >= 0; i--) {
            this.cluster.remove(i);
        }
        const filterFunc = (property, item) => {
            const workbenchInfo = item.workbenches[workbench];
            if (workbenchInfo) {
                return workbenchInfo[property];
            }
            return false;
        };
        switch (this.input.show_clusters) {
            case ShowClusterType.Interactive:
                this.availableClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                break;
            case ShowClusterType.NonInteractive:
                this.availableClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                break;
            case ShowClusterType.All:
            default:
                let sessionClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                let adhocClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                this.availableClusters = sessionClusters.concat(adhocClusters);
                break;
        }
        this.availableClusters.sort((a, b) => { return a.name.localeCompare(b.name); });
        let workbenchObj = this.info.workbenches[workbench];
        let defaultCluster = "";
        if (workbenchObj)
            defaultCluster = workbenchObj.default_cluster;
        for (let cluster of this.availableClusters) {
            let option = document.createElement('option');
            option.value = cluster.name;
            option.text = cluster.name;
            if (this.resuming()) {
                if (cluster.name === this.input.launch_spec.cluster) {
                    option.selected = true;
                }
            }
            else {
                if (cluster.name === defaultCluster) {
                    option.selected = true;
                }
            }
            this.cluster.add(option);
        }
    }
    showClusterOptions(index) {
        var _a, _b, _c;
        this.options.innerHTML = "";
        this.image = null;
        this.limits = new Array();
        this.constraints = new Array();
        const cluster = this.availableClusters[index];
        if (!cluster) {
            return;
        }
        const workbench = this.input.workbenches[this.workbench.selectedIndex];
        const workbenchObj = this.info.workbenches[workbench];
        this.sessionPrereqs.lang = (_b = (_a = workbenchObj.lang) === null || _a === void 0 ? void 0 : _a.available) !== null && _b !== void 0 ? _b : true;
        if (!this.sessionPrereqs.lang && workbenchObj.lang) {
            let sessionName = workbench;
            if (sessionName === "RStudio") {
                sessionName += " Pro";
            }
            const lang = workbenchObj.lang.name;
            let url = "";
            if (lang === "Jupyter") {
                url = "https://docs.posit.co/ide/server-pro/integration/jupyter-standalone.html";
            }
            else if (lang === "R") {
                url = "https://docs.posit.co/resources/install-r/";
            }
            else if (lang === "code-server") {
                url = "https://docs.posit.co/ide/server-pro/vscode_sessions/installation.html";
            }
            this.options.innerHTML = `
        </br>
        <p>
          ${sessionName} Sessions cannot be started because a necessary dependency is not installed: ${lang}.
            Please contact your system administrator for assistance.
        </p>
        </br>
        <p>
          More details about installing ${lang} can be found <a href="${url}" target="_blank">here</a>.
        </p>`;
            return;
        }
        const filterFunc = (property, item) => {
            const workbenchInfo = item.workbenches[workbench];
            if (workbenchInfo) {
                return workbenchInfo[property];
            }
            return false;
        };
        let availableImages = [];
        switch (this.input.show_clusters) {
            case ShowClusterType.Interactive:
                availableImages = cluster.images.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                break;
            case ShowClusterType.NonInteractive:
                availableImages = cluster.images.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                break;
            case ShowClusterType.All:
            default:
                let sessionImages = cluster.images.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                let adhocImages = cluster.images.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                availableImages = sessionImages.concat(adhocImages);
                break;
        }
        if (!this.hasCollection(cluster.resourceLimits) &&
            !this.hasCollection(cluster.resourceProfiles) &&
            !this.hasCollection(cluster.placementConstraints) &&
            !this.hasCollection(cluster.queues) &&
            !this.hasCollection(availableImages)) {
            return;
        }
        if (this.uiOptions.show_legend) {
            let legend = document.createElement('legend');
            legend.textContent = 'Cluster Options';
            legend.className = 'options';
            this.options.appendChild(legend);
        }
        if (this.hasCollection(cluster.resourceProfiles) && cluster.resourceProfiles.length > 0) {
            let control = new ResourceProfileControl(cluster.resourceProfiles);
            control.onChange = () => {
                var _a;
                if (control.isCustom()) {
                    for (const elem of this.limitElements) {
                        elem.input.disabled = false;
                    }
                    if (this.queue) {
                        this.queue.select.disabled = false;
                    }
                    if (this.constraintControls) {
                        for (const cc of this.constraintControls) {
                            cc.enable();
                        }
                    }
                }
                else {
                    for (const elem of this.limitElements) {
                        elem.input.disabled = true;
                        for (const plimit of control.limits()) {
                            if (elem.limit.type == plimit.type) {
                                elem.set(plimit.value);
                            }
                        }
                    }
                    const queue = control.queue();
                    if (queue) {
                        this.queue.select.disabled = true;
                        this.queue.set(queue);
                    }
                    if (this.constraintControls) {
                        for (const cc of this.constraintControls) {
                            cc.enable();
                            for (const pc of this.resourceProfile.constraints()) {
                                if (cc.name === pc.name) {
                                    cc.set(pc.value);
                                    cc.disable();
                                }
                            }
                        }
                    }
                }
                (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
            };
            this.resourceProfile = control;
            this.options.appendChild(control.make(this.uiOptions));
            if (this.resuming()) {
                if (this.input.launch_spec.resource_profile) {
                    control.set(this.input.launch_spec.resource_profile);
                }
                else if (this.input.launch_spec.resource_limits.length > 0) {
                    control.set("custom");
                }
            }
        }
        if (this.hasCollection(cluster.resourceLimits)) {
            this.limitElements = new Array();
            for (let limit of cluster.resourceLimits) {
                if (limit.type == "CPU Request" || limit.type == "Memory Request") {
                    continue;
                }
                let control = new ResourceControl(limit);
                control.onChange = () => {
                    var _a;
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                };
                this.limits.push(control);
                this.options.appendChild(control.make(this.uiOptions));
                if (this.resourceProfile && !this.resourceProfile.isCustom()) {
                    control.input.input.disabled = true;
                    for (const plimit of this.resourceProfile.limits()) {
                        if (limit.type == plimit.type) {
                            control.set(plimit.value);
                        }
                    }
                }
                this.limitElements.push(control.input);
                if (this.resuming()) {
                    for (let l of this.input.launch_spec.resource_limits) {
                        if (l.type === limit.type) {
                            control.set(l.value);
                            break;
                        }
                    }
                }
            }
        }
        if (this.hasCollection(cluster.placementConstraints)) {
            this.constraintControls = new Array();
            let constraints = {};
            for (let constraint of cluster.placementConstraints) {
                if (typeof constraints[constraint.name] === "undefined") {
                    constraints[constraint.name] = new Array();
                }
                if (typeof constraint.value === "string") {
                    constraints[constraint.name].push(constraint.value);
                }
            }
            for (let constraint in constraints) {
                let control = new PlacementControl(constraint, constraints[constraint]);
                control.onChange = () => {
                    var _a;
                    (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                };
                this.constraints.push(control);
                this.options.appendChild(control.make(this.uiOptions));
                if (this.resourceProfile && !this.resourceProfile.isCustom()) {
                    for (const pc of this.resourceProfile.constraints()) {
                        if (constraint === pc.name) {
                            control.set(pc.value);
                            control.disable();
                        }
                    }
                }
                this.constraintControls.push(control);
                if (this.resuming()) {
                    for (let p of this.input.launch_spec.placement_constraints) {
                        if (p.name === constraint) {
                            control.set(p.value);
                            break;
                        }
                    }
                }
            }
        }
        if (this.hasCollection(cluster.queues)) {
            let control = new QueueControl(cluster.queues, cluster.defaultQueue);
            this.queue = control;
            this.options.appendChild(control.make(this.uiOptions));
            if (this.resourceProfile) {
                const queue = this.resourceProfile.queue();
                if (queue) {
                    this.queue.select.disabled = true;
                    this.queue.set(queue);
                }
            }
            if (this.resuming() && this.hasCollection(this.input.launch_spec.queues)) {
                control.set(this.input.launch_spec.queues[0]);
            }
        }
        let defaultImage = "";
        if (workbenchObj)
            defaultImage = workbenchObj.default_image;
        if (cluster.supportsContainers &&
            (this.hasCollection(availableImages) || cluster.allowUnknownImages || cluster.defaultImage || defaultImage)) {
            if (!defaultImage && cluster.defaultImage) {
                defaultImage = cluster.defaultImage;
            }
            let control = new ImageControl(availableImages, defaultImage, cluster.allowUnknownImages, (_c = this.input.last_used_container_images) === null || _c === void 0 ? void 0 : _c[cluster.name]);
            this.image = control;
            this.image.onChange = () => {
                var _a;
                (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
            };
            this.options.appendChild(control.make(this.uiOptions));
            if (this.resuming()) {
                control.set(this.input.launch_spec.container_image, cluster.allowUnknownImages);
            }
        }
    }
    getLaunchSpec() {
        var _a;
        let spec = {};
        spec.name = this.name.value;
        let selected = this.cluster.options[this.cluster.selectedIndex];
        spec.cluster = (selected === null || selected === void 0 ? void 0 : selected.value) || '';
        let ok = true;
        for (let limit of this.limits) {
            if (!limit.input.validateInput())
                ok = false;
        }
        if (!ok) {
            return null;
        }
        spec.placement_constraints = new Array();
        for (let constraint of this.constraints) {
            let placement = constraint.constraint();
            if (placement !== null) {
                spec.placement_constraints.push(placement);
            }
        }
        spec.resource_limits = new Array();
        for (let limit of this.limits) {
            let value = limit.value();
            if (value === null) {
                continue;
            }
            spec.resource_limits.push(value);
        }
        spec.queues = [];
        if (this.queue) {
            spec.queues.push(this.queue.value());
        }
        if (this.image) {
            spec.container_image = this.image.value();
            spec.default_image = this.image.defaultImage;
            spec.container_images = this.image.images.map(img => img.image);
        }
        else {
            spec.container_image = "";
            spec.default_image = "";
            spec.container_images = [""];
        }
        const isAwsRoleNone = ((_a = this.awsRole) === null || _a === void 0 ? void 0 : _a.value) ? this.awsRole.value === "None" : true;
        if (this.awsRole && !isAwsRoleNone) {
            spec.aws_role = this.awsRole.value;
        }
        const workbench = this.input.workbenches[this.workbench.selectedIndex];
        const workbenchValid = !!['VS Code', 'RStudio'].find(wb => wb === workbench);
        if (workbenchValid && this.databricksInstance && !this.databricksInstance.isNone()) {
            spec.databricks_instance = this.databricksInstance.instance().url;
        }
        if (workbenchValid && this.snowflakeAccount && !this.snowflakeAccount.isNone()) {
            spec.snowflake_account = this.snowflakeAccount.account().accountId;
            spec.snowflake_role = this.snowflakeAccount.account().role;
        }
        if (this.resourceProfile) {
            spec.resource_profile = this.resourceProfile.profile();
            if (!this.resourceProfile.isCustom()) {
                spec.resource_limits = new Array();
            }
        }
        return spec;
    }
    getWorkbench() {
        return this.workbench.value;
    }
    setJobName(name) {
        this.name.value = name;
    }
    getJobName() {
        return this.name.value;
    }
    resuming() {
        return typeof (this.input.launch_spec) !== "undefined" &&
            this.input.launch_spec !== null;
    }
}
function launcherUi(host, rpcUrlPrefix, input, uiOptions) {
    let ui = new LauncherUI(host, rpcUrlPrefix, input, uiOptions);
    ui.initialize();
    return ui;
}
