<commit_before>function octane_job_configuration(target, progress, proxy) {

    if (typeof jQuery === 'undefined') {
        return {
            configure: function() {
                target.innerHTML = "JQuery plugin must be installed and enabled Plugin Manager";
            }
        }
    }

    var originalUnload = window.onbeforeunload;

    var $ = jQuery;

    function caseInsensitiveStringEquals(left, right) {
        // TODO: janotav: no easy way to do this in JS (?), need to implement this properly
        return left.toLowerCase() === right.toLowerCase();
    }

    function configure() {
        progressFunc("Retrieving configuration from server");
        proxy.loadJobConfigurationFromServer(function (t) {
            progressFunc();
            var response = t.responseObject();
            if (response.errors) {
                response.errors.forEach(function (error) {
                    var errorDiv = $("

");
                    errorDiv.find("b").text(error);
                    $(target).append(errorDiv);
                });
            } else {
                renderConfiguration(response);
            }
        });
    }

    function progressFunc(msg) {
        if (typeof msg === 'string') {
            $(progress).find("h3").text(msg);
            $(progress).show();
            $(target).hide();
        } else {
            $(progress).hide();
            $(target).show();
        }
    }

    function renderConfiguration(jobConfiguration, pipelineId) {
        var result = $(target);
        result.empty();

        var pipelineDiv = $("
");
        result.append(pipelineDiv);

        var buttons = $("
");

        var status = $("
");
        buttons.append(status);

        var applyButton = $("<input type='button' value='Apply'>");
        buttons.append(applyButton);

        var tagTypes = {};
        var allTags = {};
        var tagTypesByName = {};
        jobConfiguration.taxonomies.forEach(function (tagType) {
            tagTypes[tagType.tagTypeId] = tagType;
            tagTypesByName[tagType.tagTypeName] = tagType;
            tagType.values.forEach(function (tag) {
                allTags[tag.tagId] = {
                    tagId: tag.tagId,
                    tagName: tag.tagName,
                    tagTypeId: tagType.tagTypeId,
                    tagTypeName: tagType.tagTypeName
                };
            });
        });

        var validators = [];
        var apply = [];
        var dirty = [];

        function renderPipeline(pipeline, saveFunc, saveCallback) {

            var groupBy = {};

            function addTag(tag) {

                var container;

                container = groupBy[tag.tagTypeName];
                if (typeof container !== 'object') {
                    container = $("
");
                    var groupSpan = $("");
                    groupSpan.text(tag.tagTypeName + ": ");
                    container.append(groupSpan);
                    groupBy[tag.tagTypeName] = container;
                    tags.append(container);
                }

                var tagSpan = $("");
                tagSpan.text(tag.tagName);
                container.append(tagSpan);

                var remove = $("<input type='button' value='X'>");
                remove.click(function () {
                    var index = pipeline.taxonomyTags.indexOf(tag);
                    pipeline.taxonomyTags.splice(index, 1);
                    dirty.push(function () {
                        return true; // tag was removed
                    });
                    tagSpan.remove();
                    remove.remove();
                });
                container.append(remove);
            }

            validators.length = 0;
            apply.length = 0;
            dirty.length = 0;

            applyButton.unbind('click').click(function() {
                saveConfiguration(pipeline, saveFunc, saveCallback);
            });

            pipelineDiv.empty();
            pipelineDiv.append("Pipeline: ");
            if (pipeline.isRoot) {
                var input = $("<input type='text' placeholder='Pipeline name'>");
                input.attr("value", pipeline.name);
                apply.push(function() {
                    pipeline.name = input.val();
                });
                dirty.push(function () {
                    return pipeline.name !== input.val();
                });
                addInputWithValidation(input, pipelineDiv, "Pipeline name must be specified");
            } else {
                pipelineDiv.append(pipeline.name);
            }

            pipelineDiv.append($("
"));

            if (pipeline.isRoot) {
                pipelineDiv.append("Release: ");
                var select = $("<select>");
                for (var releaseId in jobConfiguration.releases) {
                    select.append(new Option(jobConfiguration.releases[releaseId], releaseId, (pipeline.releaseId === releaseId)));
                }
                apply.push(function () {
                    pipeline.releaseId = select.val();
                });
                dirty.push(function () {
                    return pipeline.releaseId != select.val();
                });
                pipelineDiv.append(select).append($("
"));
            }

            pipelineDiv.append("Tags: ").append($("
"));
            var tags = $("
");
            pipelineDiv.append(tags);
            pipeline.taxonomyTags.forEach(addTag);

            pipelineDiv.append(buttons);

            var selectDiv = $("
");
            var addSelect = $("<select>");
            var defaultOption = new Option("Choose...", "default", true);
            $(defaultOption).prop('disabled', 'disabled');
            addSelect.append(defaultOption);
            jobConfiguration.taxonomies.forEach(function (tagType) {
                var group = $("<optgroup>");
                group.attr('label', tagType.tagTypeName);
                tagTypes[tagType.tagTypeId].values.forEach(function (tag) {
                    group.append(new Option(tag.tagName, tag.tagId));
                });
                group.append(new Option("New value...", -tagType.tagTypeId));
                addSelect.append(group);
            });
            var group = $("<optgroup>");
            group.attr('label', "New type...");
            group.append(new Option("New value...", 0));
            addSelect.append(group);
            var addedTag;
            addSelect.change(function () {
                add.prop('disabled', false);
                var val = addSelect.val();
                if (val < 0) {
                    var tagType = tagTypes[-val];
                    addedTag = {
                        tagTypeId: tagType.tagTypeId,
                        tagTypeName: tagType.tagTypeName
                    };
                    tagTypeInput.val(tagType.tagTypeName);
                    tagTypeInput.prop('disabled', 'disabled');
                    tagTypeInput.css('display', 'inline');
                    tagInput.val("");
                    tagInput.attr('placeholder', 'Tag');
                    tagInput.css('display', 'inline');
                } else if (val == 0) {
                    addedTag = {};
                    tagTypeInput.val("");
                    tagTypeInput.attr('placeholder', 'Tag Type');
                    tagTypeInput.prop('disabled', false);
                    tagTypeInput.css('display', 'inline');
                    tagInput.val("");
                    tagInput.attr('placeholder', 'Tag');
                    tagInput.css('display', 'inline');
                } else {
                    addedTag = allTags[val];
                    tagTypeInput.hide();
                    tagInput.hide();
                }
                validationAreaTagType.empty();
                validationAreaTag.empty();
            });
            selectDiv.append(addSelect);
            pipelineDiv.append(selectDiv);

            pipeline.taxonomyTags.forEach(function (tag) {
                addSelect.find("option[value='"+tag.tagId+"']").prop('disabled', 'disabled');
            });

            var validationAreaTagType = $("
");
            var validationAreaTag = $("
");

            var tagTypeInput = $("<input type='text'>");
            tagTypeInput.hide();
            tagTypeInput.blur(validateInput(validationAreaTagType, newTagTypeValidation(tagTypeInput)));
            selectDiv.append(tagTypeInput);
            var tagInput = $("<input type='text'>");
            tagInput.hide();
            tagInput.blur(validateInput(validationAreaTag, newTagValidation(tagTypeInput, tagInput, pipeline.taxonomyTags)));
            selectDiv.append(tagInput);

            var add = $("<input type='button' value='Add'>");
            add.prop('disabled', 'disabled');
            add.click(function () {
                var validationOk = true;
                if (!addedTag.tagTypeId) {
                    addedTag.tagTypeName = tagTypeInput.val();
                    if (!validateInput(validationAreaTagType, newTagTypeValidation(tagTypeInput))()) {
                        validationOk = false;
                    }
                }
                if (!addedTag.tagId) {
                    addedTag.tagName = tagInput.val();
                    if (!validateInput(validationAreaTag, newTagValidation(tagTypeInput, tagInput, pipeline.taxonomyTags))()) {
                        validationOk = false;
                    }
                }
                if (!validationOk) {
                    return;
                }
                pipeline.taxonomyTags.push(addedTag);
                addTag(addedTag);
                if (addedTag.tagId) {
                    addSelect.find("option:selected").prop('disabled', 'disabled');
                }
                addedTag = undefined;
                dirty.push(function () {
                    return true; // there is new tag
                });
                $(defaultOption).prop('selected', 'selected');
                tagTypeInput.hide();
                tagInput.hide();
            });
            selectDiv.append(add);

            // put validation area bellow both input fields
            selectDiv.append(validationAreaTagType);
            selectDiv.append(validationAreaTag);
        }

        var CONFIRMATION = "There are unsaved changes, if you continue they will be discarded. Continue?";
        var pipelineSelect;
        var saveFunc, saveCallback;

        if (jobConfiguration.pipelines.length == 0) {
            saveFunc = function (pipeline, callback) {
                proxy.createPipelineOnServer(pipeline, callback);
            };
            saveCallback = function (pipeline, response) {
                pipeline.id = response.id;
                renderConfiguration(jobConfiguration, pipeline.id);
            };
            var createPipelineDiv = $("
No pipeline is currently defined for this job

");
            var createPipelineButton = $("<input type='button' value='Create Pipeline'>");
            createPipelineButton.click(function () {
                pipelineDiv.empty();
                var pipeline = {
                    id: null,
                    isRoot: true,
                    taxonomyTags: []
                };
                jobConfiguration.pipelines.push(pipeline);
                renderPipeline(pipeline, saveFunc, saveCallback);
            });
            createPipelineDiv.append(createPipelineButton);
            pipelineDiv.append(createPipelineDiv);
        } else {
            saveFunc = function (pipeline, callback) {
                proxy.updatePipelineOnSever(pipeline, callback);
            };
            saveCallback = function (pipeline, response) {
                pipeline.taxonomyTags = response.taxonomies;

                // merge newly created taxonomies with the existing ones in order to appear in drop-downs
                pipeline.taxonomyTags.forEach(function (taxonomy) {
                    var type = tagTypes[taxonomy.tagTypeId];
                    if (!type) {
                        type = {
                            tagTypeId: taxonomy.tagTypeId,
                            tagTypeName: taxonomy.tagTypeName,
                            values: []
                        };
                        jobConfiguration.taxonomies.push(type);
                        tagTypes[type.tagTypeId] = type;
                    }
                    var matchTag = function (tag) {
                        return tag.tagId == taxonomy.tagId;
                    };
                    if (!type.values.some(matchTag)) {
                        type.values.push({
                            tagId: taxonomy.tagId,
                            tagName: taxonomy.tagName
                        });
                    }
                });

                renderConfiguration(jobConfiguration, pipeline.id);
            };
            var selectedIndex = 0;
            if (jobConfiguration.pipelines.length > 1) {
                pipelineSelect = $("<select>");
                jobConfiguration.pipelines.forEach(function (pipeline) {
                    pipelineSelect.append(new Option(pipeline.name, pipeline.id, (pipeline.id === pipelineId)));
                });
                var lastSelected = $(pipelineSelect).find("option:selected");
                pipelineSelect.change(function () {
                    if (dirtyFields()) {
                        if (!window.confirm(CONFIRMATION)) {
                            lastSelected.attr("selected", true);
                            return;
                        }
                    }
                    lastSelected = $(pipelineSelect).find("option:selected");
                    renderPipeline(jobConfiguration.pipelines[pipelineSelect[0].selectedIndex], saveFunc, saveCallback);
                });
                result.prepend(pipelineSelect);
                selectedIndex = pipelineSelect[0].selectedIndex;
            }
            renderPipeline(jobConfiguration.pipelines[selectedIndex], saveFunc, saveCallback);
        }

        window.onbeforeunload = function() {
            if (dirtyFields()) {
                return CONFIRMATION;
            } else {
                // keep original check just in case there is another dirty data (shouldn't be)
                if (typeof originalUnload === 'function') {
                    return originalUnload();
                } else {
                    return undefined;
                }
            }
        };

        function dirtyFields() {
            return dirty.some(function (func) {
                return func()
            });
        }

        function validateFields() {
            var valid = true;
            validators.forEach(function (validator) {
                if (!validator()) {
                    valid = false;
                }
            });
            return valid;
        }

        function applyFields() {
            apply.forEach(function (func) {
                func();
            });
        }

        function newTagValidation(tagTypeInput, tagInput, taxonomyTags) {
            return function () {
                var error = undefined;

                function matchTag(tag) {
                    if (caseInsensitiveStringEquals(tag.tagName, tagInput.val())) {
                        error = "Tag " + tagType.tagTypeName + ":" + tag.tagName + " is already defined";
                        return true;
                    } else {
                        return false;
                    }
                }

                function matchAddedTag(tag) {
                    if (caseInsensitiveStringEquals(tag.tagName, tagInput.val()) &&
                            caseInsensitiveStringEquals(tag.tagTypeName, tagTypeInput.val())) {
                        error = "Tag " + tag.tagTypeName + ":" + tag.tagName + " is already added";
                        return true;
                    } else {
                        return false;
                    }
                }

                if (!tagInput.val()) {
                    return "Tag must be specified";
                }

                var tagType = tagTypesByName[tagTypeInput.val()];
                if (tagType) {
                    tagType.values.some(matchTag);
                }

                if (!error) {
                    // could be added as new tag
                    taxonomyTags.some(matchAddedTag);
                }

                return error;
            };
        }

        function newTagTypeValidation(tagTypeInput) {
            return function () {
                var error = undefined;

                function matchTagType(tagType) {
                    if (caseInsensitiveStringEquals(tagType.tagTypeName, tagTypeInput.val())) {
                        error = "Tag Type " + tagType.tagTypeName + " is already defined";
                        return true;
                    } else {
                        return false;
                    }
                }

                if (!tagTypeInput.val()) {
                    return "Tag type must be specified";
                }

                jobConfiguration.taxonomies.some(matchTagType);
                return error;
            };
        }

        function addInputWithValidation(input, target, message) {
            function emptyCheck() {
                if (!input.val()) {
                    return message;
                } else {
                    return false;
                }
            }
            target.append(input);
            var validationArea = $("
");
            target.append(validationArea);
            var validate = validateInput(validationArea, emptyCheck);
            input.blur(validate);
            validators.push(validate);
            validationArea.hide();
        }

        function validateInput(target, conditionFunc) {

            function showError(message) {
                var container = $("
");
                container.html(message);
                target.append(container);
                target.show();
            }

            return function() {
                target.empty();
                var error = conditionFunc();
                if (error) {
                    showError(error);
                    return false;
                }
                target.hide();
                return true;
            };
        }

        function validationError(error) {
            var errorDiv = $("

");
            errorDiv.find("b").text(error);
            status.append(errorDiv);
        }

        function saveConfiguration(pipeline, saveFunc, saveCallback) {
            if (!validateFields()) {
                return;
            }
            applyFields();

            status.empty();

            progressFunc("Storing configuration on server");
            saveFunc(pipeline, function (t) {
                progressFunc();
                var response = t.responseObject();
                if (response.errors) {
                    response.errors.forEach(validationError);
                } else {
                    saveCallback(pipeline, response);
                }
            });
        }
    }

    return {
        configure: configure
    };
}<commit_msg>user story #3555: remove empty group, re-enable removed tags<commit_after>function octane_job_configuration(target, progress, proxy) {

    if (typeof jQuery === 'undefined') {
        return {
            configure: function() {
                target.innerHTML = "JQuery plugin must be installed and enabled Plugin Manager";
            }
        }
    }

    var originalUnload = window.onbeforeunload;

    var $ = jQuery;

    function caseInsensitiveStringEquals(left, right) {
        // TODO: janotav: no easy way to do this in JS (?), need to implement this properly
        return left.toLowerCase() === right.toLowerCase();
    }

    function configure() {
        progressFunc("Retrieving configuration from server");
        proxy.loadJobConfigurationFromServer(function (t) {
            progressFunc();
            var response = t.responseObject();
            if (response.errors) {
                response.errors.forEach(function (error) {
                    var errorDiv = $("

");
                    errorDiv.find("b").text(error);
                    $(target).append(errorDiv);
                });
            } else {
                renderConfiguration(response);
            }
        });
    }

    function progressFunc(msg) {
        if (typeof msg === 'string') {
            $(progress).find("h3").text(msg);
            $(progress).show();
            $(target).hide();
        } else {
            $(progress).hide();
            $(target).show();
        }
    }

    function renderConfiguration(jobConfiguration, pipelineId) {
        var result = $(target);
        result.empty();

        var pipelineDiv = $("
");
        result.append(pipelineDiv);

        var buttons = $("
");

        var status = $("
");
        buttons.append(status);

        var applyButton = $("<input type='button' value='Apply'>");
        buttons.append(applyButton);

        var tagTypes = {};
        var allTags = {};
        var tagTypesByName = {};
        jobConfiguration.taxonomies.forEach(function (tagType) {
            tagTypes[tagType.tagTypeId] = tagType;
            tagTypesByName[tagType.tagTypeName] = tagType;
            tagType.values.forEach(function (tag) {
                allTags[tag.tagId] = {
                    tagId: tag.tagId,
                    tagName: tag.tagName,
                    tagTypeId: tagType.tagTypeId,
                    tagTypeName: tagType.tagTypeName
                };
            });
        });

        var validators = [];
        var apply = [];
        var dirty = [];

        function renderPipeline(pipeline, saveFunc, saveCallback) {

            var groupBy = {};

            function addTag(tag) {

                var container;
                var group = groupBy[tag.tagTypeName];
                if (typeof group !== 'object') {
                    container = $("
");
                    var groupSpan = $("");
                    groupSpan.text(tag.tagTypeName + ": ");
                    container.append(groupSpan);
                    group = {
                        target: container,
                        count: 0
                    };
                    groupBy[tag.tagTypeName] = group;
                    tags.append(container);
                }
                container = group.target;
                group.count++;

                var tagSpan = $("");
                tagSpan.text(tag.tagName);
                container.append(tagSpan);

                var remove = $("<input type='button' value='X'>");
                remove.click(function () {
                    var index = pipeline.taxonomyTags.indexOf(tag);
                    pipeline.taxonomyTags.splice(index, 1);
                    dirty.push(function () {
                        return true; // tag was removed
                    });
                    tagSpan.remove();
                    remove.remove();
                    if (--group.count == 0) {
                        container.remove();
                        delete groupBy[tag.tagTypeName];
                    }
                    if (tag.tagId) {
                        addSelect.find("option[value='" + tag.tagId + "']").prop('disabled', false);
                    }
                });
                container.append(remove);
            }

            validators.length = 0;
            apply.length = 0;
            dirty.length = 0;

            applyButton.unbind('click').click(function() {
                saveConfiguration(pipeline, saveFunc, saveCallback);
            });

            pipelineDiv.empty();
            pipelineDiv.append("Pipeline: ");
            if (pipeline.isRoot) {
                var input = $("<input type='text' placeholder='Pipeline name'>");
                input.attr("value", pipeline.name);
                apply.push(function() {
                    pipeline.name = input.val();
                });
                dirty.push(function () {
                    return pipeline.name !== input.val();
                });
                addInputWithValidation(input, pipelineDiv, "Pipeline name must be specified");
            } else {
                pipelineDiv.append(pipeline.name);
            }

            pipelineDiv.append($("
"));

            if (pipeline.isRoot) {
                pipelineDiv.append("Release: ");
                var select = $("<select>");
                for (var releaseId in jobConfiguration.releases) {
                    select.append(new Option(jobConfiguration.releases[releaseId], releaseId, (pipeline.releaseId === releaseId)));
                }
                apply.push(function () {
                    pipeline.releaseId = select.val();
                });
                dirty.push(function () {
                    return pipeline.releaseId != select.val();
                });
                pipelineDiv.append(select).append($("
"));
            }

            pipelineDiv.append("Tags: ").append($("
"));
            var tags = $("
");
            pipelineDiv.append(tags);
            pipeline.taxonomyTags.forEach(addTag);

            pipelineDiv.append(buttons);

            var selectDiv = $("
");
            var addSelect = $("<select>");
            var defaultOption = new Option("Choose...", "default", true);
            $(defaultOption).prop('disabled', 'disabled');
            addSelect.append(defaultOption);
            jobConfiguration.taxonomies.forEach(function (tagType) {
                var group = $("<optgroup>");
                group.attr('label', tagType.tagTypeName);
                tagTypes[tagType.tagTypeId].values.forEach(function (tag) {
                    group.append(new Option(tag.tagName, tag.tagId));
                });
                group.append(new Option("New value...", -tagType.tagTypeId));
                addSelect.append(group);
            });
            var group = $("<optgroup>");
            group.attr('label', "New type...");
            group.append(new Option("New value...", 0));
            addSelect.append(group);
            var addedTag;
            addSelect.change(function () {
                add.prop('disabled', false);
                var val = addSelect.val();
                if (val < 0) {
                    var tagType = tagTypes[-val];
                    addedTag = {
                        tagTypeId: tagType.tagTypeId,
                        tagTypeName: tagType.tagTypeName
                    };
                    tagTypeInput.val(tagType.tagTypeName);
                    tagTypeInput.prop('disabled', 'disabled');
                    tagTypeInput.css('display', 'inline');
                    tagInput.val("");
                    tagInput.attr('placeholder', 'Tag');
                    tagInput.css('display', 'inline');
                } else if (val == 0) {
                    addedTag = {};
                    tagTypeInput.val("");
                    tagTypeInput.attr('placeholder', 'Tag Type');
                    tagTypeInput.prop('disabled', false);
                    tagTypeInput.css('display', 'inline');
                    tagInput.val("");
                    tagInput.attr('placeholder', 'Tag');
                    tagInput.css('display', 'inline');
                } else {
                    addedTag = allTags[val];
                    tagTypeInput.hide();
                    tagInput.hide();
                }
                validationAreaTagType.empty();
                validationAreaTag.empty();
            });
            selectDiv.append(addSelect);
            pipelineDiv.append(selectDiv);

            pipeline.taxonomyTags.forEach(function (tag) {
                addSelect.find("option[value='"+tag.tagId+"']").prop('disabled', 'disabled');
            });

            var validationAreaTagType = $("
");
            var validationAreaTag = $("
");

            var tagTypeInput = $("<input type='text'>");
            tagTypeInput.hide();
            tagTypeInput.blur(validateInput(validationAreaTagType, newTagTypeValidation(tagTypeInput)));
            selectDiv.append(tagTypeInput);
            var tagInput = $("<input type='text'>");
            tagInput.hide();
            tagInput.blur(validateInput(validationAreaTag, newTagValidation(tagTypeInput, tagInput, pipeline.taxonomyTags)));
            selectDiv.append(tagInput);

            var add = $("<input type='button' value='Add'>");
            add.prop('disabled', 'disabled');
            add.click(function () {
                var validationOk = true;
                if (!addedTag.tagTypeId) {
                    addedTag.tagTypeName = tagTypeInput.val();
                    if (!validateInput(validationAreaTagType, newTagTypeValidation(tagTypeInput))()) {
                        validationOk = false;
                    }
                }
                if (!addedTag.tagId) {
                    addedTag.tagName = tagInput.val();
                    if (!validateInput(validationAreaTag, newTagValidation(tagTypeInput, tagInput, pipeline.taxonomyTags))()) {
                        validationOk = false;
                    }
                }
                if (!validationOk) {
                    return;
                }
                pipeline.taxonomyTags.push(addedTag);
                addTag(addedTag);
                if (addedTag.tagId) {
                    addSelect.find("option:selected").prop('disabled', 'disabled');
                }
                addedTag = undefined;
                dirty.push(function () {
                    return true; // there is new tag
                });
                $(defaultOption).prop('selected', 'selected');
                tagTypeInput.hide();
                tagInput.hide();
            });
            selectDiv.append(add);

            // put validation area bellow both input fields
            selectDiv.append(validationAreaTagType);
            selectDiv.append(validationAreaTag);
        }

        var CONFIRMATION = "There are unsaved changes, if you continue they will be discarded. Continue?";
        var pipelineSelect;
        var saveFunc, saveCallback;

        if (jobConfiguration.pipelines.length == 0) {
            saveFunc = function (pipeline, callback) {
                proxy.createPipelineOnServer(pipeline, callback);
            };
            saveCallback = function (pipeline, response) {
                pipeline.id = response.id;
                renderConfiguration(jobConfiguration, pipeline.id);
            };
            var createPipelineDiv = $("
No pipeline is currently defined for this job

");
            var createPipelineButton = $("<input type='button' value='Create Pipeline'>");
            createPipelineButton.click(function () {
                pipelineDiv.empty();
                var pipeline = {
                    id: null,
                    isRoot: true,
                    taxonomyTags: []
                };
                jobConfiguration.pipelines.push(pipeline);
                renderPipeline(pipeline, saveFunc, saveCallback);
            });
            createPipelineDiv.append(createPipelineButton);
            pipelineDiv.append(createPipelineDiv);
        } else {
            saveFunc = function (pipeline, callback) {
                proxy.updatePipelineOnSever(pipeline, callback);
            };
            saveCallback = function (pipeline, response) {
                pipeline.taxonomyTags = response.taxonomies;

                // merge newly created taxonomies with the existing ones in order to appear in drop-downs
                pipeline.taxonomyTags.forEach(function (taxonomy) {
                    var type = tagTypes[taxonomy.tagTypeId];
                    if (!type) {
                        type = {
                            tagTypeId: taxonomy.tagTypeId,
                            tagTypeName: taxonomy.tagTypeName,
                            values: []
                        };
                        jobConfiguration.taxonomies.push(type);
                        tagTypes[type.tagTypeId] = type;
                    }
                    var matchTag = function (tag) {
                        return tag.tagId == taxonomy.tagId;
                    };
                    if (!type.values.some(matchTag)) {
                        type.values.push({
                            tagId: taxonomy.tagId,
                            tagName: taxonomy.tagName
                        });
                    }
                });

                renderConfiguration(jobConfiguration, pipeline.id);
            };
            var selectedIndex = 0;
            if (jobConfiguration.pipelines.length > 1) {
                pipelineSelect = $("<select>");
                jobConfiguration.pipelines.forEach(function (pipeline) {
                    pipelineSelect.append(new Option(pipeline.name, pipeline.id, (pipeline.id === pipelineId)));
                });
                var lastSelected = $(pipelineSelect).find("option:selected");
                pipelineSelect.change(function () {
                    if (dirtyFields()) {
                        if (!window.confirm(CONFIRMATION)) {
                            lastSelected.attr("selected", true);
                            return;
                        }
                    }
                    lastSelected = $(pipelineSelect).find("option:selected");
                    renderPipeline(jobConfiguration.pipelines[pipelineSelect[0].selectedIndex], saveFunc, saveCallback);
                });
                result.prepend(pipelineSelect);
                selectedIndex = pipelineSelect[0].selectedIndex;
            }
            renderPipeline(jobConfiguration.pipelines[selectedIndex], saveFunc, saveCallback);
        }

        window.onbeforeunload = function() {
            if (dirtyFields()) {
                return CONFIRMATION;
            } else {
                // keep original check just in case there is another dirty data (shouldn't be)
                if (typeof originalUnload === 'function') {
                    return originalUnload();
                } else {
                    return undefined;
                }
            }
        };

        function dirtyFields() {
            return dirty.some(function (func) {
                return func()
            });
        }

        function validateFields() {
            var valid = true;
            validators.forEach(function (validator) {
                if (!validator()) {
                    valid = false;
                }
            });
            return valid;
        }

        function applyFields() {
            apply.forEach(function (func) {
                func();
            });
        }

        function newTagValidation(tagTypeInput, tagInput, taxonomyTags) {
            return function () {
                var error = undefined;

                function matchTag(tag) {
                    if (caseInsensitiveStringEquals(tag.tagName, tagInput.val())) {
                        error = "Tag " + tagType.tagTypeName + ":" + tag.tagName + " is already defined";
                        return true;
                    } else {
                        return false;
                    }
                }

                function matchAddedTag(tag) {
                    if (caseInsensitiveStringEquals(tag.tagName, tagInput.val()) &&
                            caseInsensitiveStringEquals(tag.tagTypeName, tagTypeInput.val())) {
                        error = "Tag " + tag.tagTypeName + ":" + tag.tagName + " is already added";
                        return true;
                    } else {
                        return false;
                    }
                }

                if (!tagInput.val()) {
                    return "Tag must be specified";
                }

                var tagType = tagTypesByName[tagTypeInput.val()];
                if (tagType) {
                    tagType.values.some(matchTag);
                }

                if (!error) {
                    // could be added as new tag
                    taxonomyTags.some(matchAddedTag);
                }

                return error;
            };
        }

        function newTagTypeValidation(tagTypeInput) {
            return function () {
                var error = undefined;

                function matchTagType(tagType) {
                    if (caseInsensitiveStringEquals(tagType.tagTypeName, tagTypeInput.val())) {
                        error = "Tag Type " + tagType.tagTypeName + " is already defined";
                        return true;
                    } else {
                        return false;
                    }
                }

                if (!tagTypeInput.val()) {
                    return "Tag type must be specified";
                }

                jobConfiguration.taxonomies.some(matchTagType);
                return error;
            };
        }

        function addInputWithValidation(input, target, message) {
            function emptyCheck() {
                if (!input.val()) {
                    return message;
                } else {
                    return false;
                }
            }
            target.append(input);
            var validationArea = $("
");
            target.append(validationArea);
            var validate = validateInput(validationArea, emptyCheck);
            input.blur(validate);
            validators.push(validate);
            validationArea.hide();
        }

        function validateInput(target, conditionFunc) {

            function showError(message) {
                var container = $("
");
                container.html(message);
                target.append(container);
                target.show();
            }

            return function() {
                target.empty();
                var error = conditionFunc();
                if (error) {
                    showError(error);
                    return false;
                }
                target.hide();
                return true;
            };
        }

        function validationError(error) {
            var errorDiv = $("

");
            errorDiv.find("b").text(error);
            status.append(errorDiv);
        }

        function saveConfiguration(pipeline, saveFunc, saveCallback) {
            if (!validateFields()) {
                return;
            }
            applyFields();

            status.empty();

            progressFunc("Storing configuration on server");
            saveFunc(pipeline, function (t) {
                progressFunc();
                var response = t.responseObject();
                if (response.errors) {
                    response.errors.forEach(validationError);
                } else {
                    saveCallback(pipeline, response);
                }
            });
        }
    }

    return {
        configure: configure
    };
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { Map, fromJS } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { resolveWidget } from '../Widgets';
import ControlHOC from '../Widgets/ControlHOC';
import styles from './ControlPane.css';

function isHidden(field) {
  return field.get('widget') === 'hidden';
}

export default class ControlPane extends Component {
  componentValidate = {};
  processControlRef(fieldName, wrappedControl) {
    if (!wrappedControl) return;
    this.componentValidate[fieldName] = wrappedControl.validate;
  }

  validate = () => {
    this.props.fields.forEach(field => this.componentValidate[field.get("name")]());
  };

  controlFor(field) {
    const { entry, fieldsMetaData, fieldsErrors, getAsset, onChange, onAddAsset, onRemoveAsset } = this.props;
    const widget = resolveWidget(field.get('widget'));
    const fieldName = field.get('name');
    const value = entry.getIn(['data', fieldName]);
    const metadata = fieldsMetaData.get(fieldName);
    const errors = fieldsErrors.get(fieldName);
    const labelClass = errors ? styles.labelWithError : styles.label;
    if (entry.size === 0 || entry.get('partial') === true) return null;
    return (

        {field.get('label')}

          {
            errors && errors.map(error => (
              typeof error === 'string' &&
{error}

            ))
          }

        <ControlHOC
          controlComponent={widget.control}
          field={field}
          value={value}
          metadata={metadata}
          onChange={(newValue, newMetadata) => onChange(fieldName, newValue, newMetadata)}
          onValidate={this.props.onValidate.bind(this, fieldName)}
          onAddAsset={onAddAsset}
          onRemoveAsset={onRemoveAsset}
          getAsset={getAsset}
          ref={this.processControlRef.bind(this, fieldName)}
        />

    );
  }

  render() {
    const { collection, fields } = this.props;
    if (!collection || !fields) {
      return null;
    }

    return (

        {
          fields.map((field) => {
            if (isHidden(field)) {
              return null;
            }
            return
{this.controlFor(field)}
;
          })
        }

    );
  }
}

ControlPane.propTypes = {
  collection: ImmutablePropTypes.map.isRequired,
  entry: ImmutablePropTypes.map.isRequired,
  fields: ImmutablePropTypes.list.isRequired,
  fieldsMetaData: ImmutablePropTypes.map.isRequired,
  fieldsErrors: ImmutablePropTypes.map.isRequired,
  getAsset: PropTypes.func.isRequired,
  onAddAsset: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  onValidate: PropTypes.func.isRequired,
  onRemoveAsset: PropTypes.func.isRequired,
};
<commit_msg>Don't try to validate hidden fields<commit_after>import React, { Component, PropTypes } from 'react';
import { Map, fromJS } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { resolveWidget } from '../Widgets';
import ControlHOC from '../Widgets/ControlHOC';
import styles from './ControlPane.css';

function isHidden(field) {
  return field.get('widget') === 'hidden';
}

export default class ControlPane extends Component {
  componentValidate = {};
  processControlRef(fieldName, wrappedControl) {
    if (!wrappedControl) return;
    this.componentValidate[fieldName] = wrappedControl.validate;
  }

  validate = () => {
    this.props.fields.forEach((field) => {
      if (isHidden(field)) return;
      this.componentValidate[field.get("name")]();
    });
  };

  controlFor(field) {
    const { entry, fieldsMetaData, fieldsErrors, getAsset, onChange, onAddAsset, onRemoveAsset } = this.props;
    const widget = resolveWidget(field.get('widget'));
    const fieldName = field.get('name');
    const value = entry.getIn(['data', fieldName]);
    const metadata = fieldsMetaData.get(fieldName);
    const errors = fieldsErrors.get(fieldName);
    const labelClass = errors ? styles.labelWithError : styles.label;
    if (entry.size === 0 || entry.get('partial') === true) return null;
    return (

        {field.get('label')}

          {
            errors && errors.map(error => (
              typeof error === 'string' &&
{error}

            ))
          }

        <ControlHOC
          controlComponent={widget.control}
          field={field}
          value={value}
          metadata={metadata}
          onChange={(newValue, newMetadata) => onChange(fieldName, newValue, newMetadata)}
          onValidate={this.props.onValidate.bind(this, fieldName)}
          onAddAsset={onAddAsset}
          onRemoveAsset={onRemoveAsset}
          getAsset={getAsset}
          ref={this.processControlRef.bind(this, fieldName)}
        />

    );
  }

  render() {
    const { collection, fields } = this.props;
    if (!collection || !fields) {
      return null;
    }

    return (

        {
          fields.map((field) => {
            if (isHidden(field)) {
              return null;
            }
            return
{this.controlFor(field)}
;
          })
        }

    );
  }
}

ControlPane.propTypes = {
  collection: ImmutablePropTypes.map.isRequired,
  entry: ImmutablePropTypes.map.isRequired,
  fields: ImmutablePropTypes.list.isRequired,
  fieldsMetaData: ImmutablePropTypes.map.isRequired,
  fieldsErrors: ImmutablePropTypes.map.isRequired,
  getAsset: PropTypes.func.isRequired,
  onAddAsset: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  onValidate: PropTypes.func.isRequired,
  onRemoveAsset: PropTypes.func.isRequired,
};
<|endoftext|>


<commit_before>import './styles.css'
import Inferno from 'inferno' // eslint-disable-line
import {connect} from 'cerebral/inferno'
import {state, signal} from 'cerebral/tags'
import classnames from 'classnames'
import {nameToColors} from '../../../common/utils'
import Mutation from '../Signals/Signal/Action/Mutation'
import connector from 'connector'

export default connect({
  port: state`port`,
  mutations: state`debugger.mutations`,
  currentRememberedMutationIndex: state`debugger.currentRememberedMutationIndex`,
  searchValue: state`debugger.searchValue`,
  executingSignalsCount: state`debugger.executingSignalsCount`,
  mutationDoubleClicked: signal`debugger.mutationDoubleClicked`,
  mutationClicked: signal`debugger.mutationClicked`,
  signalClicked: signal`debugger.signalClicked`
},
  function Mutations ({
    port,
    mutations,
    currentRememberedMutationIndex,
    searchValue,
    executingSignalsCount,
    mutationDoubleClicked,
    mutationClicked,
    signalClicked
  }) {
    return (

          {mutations.map((mutation, index) => {
            const namePath = mutation.signalName.split('.')
            const name = namePath.pop()
            const colors = nameToColors(mutation.signalName, name)
            const hex = colors.backgroundColor
            const signalStyle = {
              backgroundColor: hex
            }
            const isSearchHit = searchValue && mutation.data.args[0].join('.').indexOf(searchValue) >= 0

            return (

 signalClicked({executionId: mutation.executionId})}
                >
                  {mutation.signalName}

                <Mutation mutation={mutation.data} onMutationClick={(path) => mutationClicked({path})} />
                {currentRememberedMutationIndex === index ? (
                  <button disabled className='timetravel-button active'>now</button>
                ) : (
                  <button disabled={executingSignalsCount} onClick={() => {
                    mutationDoubleClicked({index})
                    connector.sendEvent(port, 'remember', index)
                  }} className='timetravel-button'>travel</button>
                )}

            )
          })}

    )
  }
)
<commit_msg>fix pathClicked for Mutation view as well<commit_after>import './styles.css'
import Inferno from 'inferno' // eslint-disable-line
import {connect} from 'cerebral/inferno'
import {state, signal} from 'cerebral/tags'
import classnames from 'classnames'
import {nameToColors} from '../../../common/utils'
import Mutation from '../Signals/Signal/Action/Mutation'
import connector from 'connector'

export default connect({
  port: state`port`,
  mutations: state`debugger.mutations`,
  currentRememberedMutationIndex: state`debugger.currentRememberedMutationIndex`,
  searchValue: state`debugger.searchValue`,
  executingSignalsCount: state`debugger.executingSignalsCount`,
  mutationDoubleClicked: signal`debugger.mutationDoubleClicked`,
  mutationClicked: signal`debugger.mutationClicked`,
  signalClicked: signal`debugger.signalClicked`,
  pathClicked: signal`debugger.pathClicked`
},
  function Mutations ({
    port,
    mutations,
    currentRememberedMutationIndex,
    searchValue,
    executingSignalsCount,
    mutationDoubleClicked,
    mutationClicked,
    signalClicked,
    pathClicked
  }) {
    return (

          {mutations.map((mutation, index) => {
            const namePath = mutation.signalName.split('.')
            const name = namePath.pop()
            const colors = nameToColors(mutation.signalName, name)
            const hex = colors.backgroundColor
            const signalStyle = {
              backgroundColor: hex
            }
            const isSearchHit = searchValue && mutation.data.args[0].join('.').indexOf(searchValue) >= 0

            return (

 signalClicked({executionId: mutation.executionId})}
                >
                  {mutation.signalName}

                <Mutation mutation={mutation.data} onMutationClick={(path) => mutationClicked({path})} pathClicked={pathClicked} />
                {currentRememberedMutationIndex === index ? (
                  <button disabled className='timetravel-button active'>now</button>
                ) : (
                  <button disabled={executingSignalsCount} onClick={() => {
                    mutationDoubleClicked({index})
                    connector.sendEvent(port, 'remember', index)
                  }} className='timetravel-button'>travel</button>
                )}

            )
          })}

    )
  }
)
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { setProperty } from '../../actions/properties';
import { saveTerminal, getTerminal } from '../../actions/posts';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Terminal.css';
import TextField from 'material-ui/TextField';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import DatePicker from 'material-ui/DatePicker';
import TimePicker from 'material-ui/TimePicker';
import RaisedButton from 'material-ui/RaisedButton';
import { injectIntl } from 'react-intl';
import { getAvailableCurrencies } from '../../services/linkService';

import msg from './messages.terminal';
import { getClientId, getPaddedDate, getPaddedTime } from '../../core/utils';
import FontIcon from 'material-ui/FontIcon';
import { getLocalDateTimeValue } from '../utils';

const labels = {
  departure: {
    dateInputTitle: 'Departure date',
    timeInputTitle: 'Time',
    placeInputTitle: 'Departure description'
  },
  arrival: {
    dateInputTitle: 'Arrival date',
    timeInputTitle: 'Time',
    placeInputTitle: 'Arrival description'
  }
}

const Terminal = ({
  intl, checkIn, transportTypes, openTerminals, type, editTerminal, userDepartures, priceTerminal,
  saveDisabled, setProperty, saveTerminal, getTerminal, terminalInputErrors
}) => {

  const transportOptions = transportTypes.map(type => (
    <MenuItem id={type.slug} key={type.slug} style={{ 'WebkitAppearance': 'initial' }}
              value={type.slug} primaryText={intl.formatMessage(msg[type.slug])} />
  ));

  const currencyCodes = getAvailableCurrencies(checkIn.country);

  const currencies = Object.keys(currencyCodes).map(code => (
    <MenuItem key={code} style={{ 'WebkitAppearance': 'initial' }} value={code} primaryText={`${code}`} />
  ));

  const setTerminalProperty = (name, value) => {
    setProperty('editTerminal.terminal', { ...editTerminal, [name]: value });
  };

  const typedOpenTerminals = (openTerminals || []).filter(terminal => (terminal.type === (type === 'arrival' ? 'departure' : 'arrival') && terminal.checkIn.uuid !== checkIn.uuid));

  const openTerminalOptions = typedOpenTerminals.map(terminal => {
    const menuItemLabel = (

            { terminal.transport && intl.formatMessage(msg[terminal.transport]) }

            { terminal.transportId }

          { terminal.checkIn.formattedAddress }

    );

    return (
      <MenuItem id={terminal.uuid} key={terminal.uuid} style={{ wdith: '100%', 'WebkitAppearance': 'initial' }}
                value={terminal.uuid} primaryText={menuItemLabel}>
      </MenuItem>
    );

  });

  let linkedTerminalUuid = null;
  if (editTerminal.linkedTerminalUuid) {
    linkedTerminalUuid = editTerminal.linkedTerminalUuid;
  } else {
    if (typedOpenTerminals.length > 0) {
      linkedTerminalUuid = typedOpenTerminals[0].uuid;
    }
  }

  let linkedTerminal = null;
  if (linkedTerminalUuid !== 'not-linked') {
    if (typedOpenTerminals.length > 0) {
      linkedTerminal = (typedOpenTerminals || []).filter(terminal => terminal.uuid === (linkedTerminalUuid || typedOpenTerminals[0].uuid))[0];
    }
  }

  const now = new Date();

  const linkedTerminalLabel = type === 'arrival' ? 'Link to departure' : 'Link to arrival';

  const getDefaultTerminalTime = () => {
    const checkInDateTime = new Date(checkIn.date);
    const timeDiff = Math.abs(now.getTime() - checkInDateTime.getTime());
    return (timeDiff < 1000 * 60 * 60 * 48) ? now : checkInDateTime;
  };

  const defaultDateTime = (linkedTerminal && !editTerminal.uuid) ?
    new Date(editTerminal.localDateTime || getDefaultTerminalTime()) :
    new Date(editTerminal.localDateTime || getDefaultTerminalTime());

  const dateTime = ({ date, time }) => {
    const newDate = date ? getPaddedDate(date) : getPaddedDate(editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime);
    const newTime = time ? getPaddedTime(time) : getPaddedTime(editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime);
    return newDate + 'T' + newTime;
  };

  const transportValue = editTerminal.transport || (priceTerminal ? priceTerminal.transport : undefined);
  const transportIdValue = (editTerminal.transportId || (priceTerminal || {}).transportId) || '';
  const descriptionValue = (editTerminal.description || (priceTerminal || {}).description) || '';

  const priceTerminalUuidValue = editTerminal.priceTerminalUuid ||
    (editTerminal.priceTerminal ? editTerminal.priceTerminal.uuid : undefined) ||
    (userDepartures && userDepartures.length > 0) && userDepartures[0].uuid;
  console.log('editTerminal', priceTerminalUuidValue, userDepartures, transportValue);
  const save = () => {

    if (!transportValue && !linkedTerminal) {
      setProperty('editTerminal.terminalInputErrors', {
        transport: 'empty'
      });
      return;
    }

    const editedTerminal = {
      uuid: editTerminal.uuid,
      checkInUuid: checkIn.uuid,
      type,
      transport: transportValue,
      transportId: transportIdValue,
      description: descriptionValue,
      priceCurrency: editTerminal.priceCurrency,
      priceType: editTerminal.priceType || 'payment',
      priceTerminalUuid: editTerminal.priceType === 'part' ? priceTerminalUuidValue : null
    };

    if (editTerminal.priceAmount && editTerminal.priceAmount.length > 0) {
      editedTerminal.priceAmount = parseFloat(editTerminal.priceAmount);
    }

    editedTerminal.date = editTerminal.localDateTime || dateTime({ date: defaultDateTime, time: defaultDateTime });

    if (linkedTerminalUuid !== 'not-linked' && linkedTerminal) {
      editedTerminal.linkedTerminalUuid = linkedTerminalUuid;
      editedTerminal.transport = linkedTerminal.transport;
      editedTerminal.transportId = linkedTerminal.transactionId;
    }

    const clientId = getClientId();
    editedTerminal.clientId = clientId;

    saveTerminal({ terminal: editedTerminal });

  };

  return (

          {
            (!editTerminal.uuid && openTerminalOptions.length > 0) &&

                <SelectField id="linked-terminal-select"
                             value={linkedTerminalUuid || ((typedOpenTerminals && typedOpenTerminals.length > 0) && typedOpenTerminals[0].uuid)}
                             fullWidth
                             floatingLabelFixed
                             floatingLabelText={linkedTerminalLabel}
                             hintText="Select terminal"
                             labelStyle={{ height: 'initial' }}
                             style={{ height: 'initial' }}
                             onChange={(event, index, value) => setProperty('editTerminal.terminal', { ...editTerminal, linkedTerminalUuid: value })}>
                  {openTerminalOptions}
                </SelectField>

          }
          {

            (linkedTerminal && !editTerminal.uuid) ?

                      <FontIcon className="material-icons" style={{ fontSize: '24px' }}>edit</FontIcon>

                    <RaisedButton label="LINK" fullWidth disabled={saveDisabled} onClick={() => save()} />

                      <DatePicker id={`${type}-date-picker`}
                                  value={
                                    editTerminal.localDateTime ?
                                      getLocalDateTimeValue(editTerminal.localDateTime) :
                                      defaultDateTime
                                  }
                                  autoOk
                                  fullWidth
                                  floatingLabelFixed
                                  floatingLabelStyle={{ width: '120px' }}
                                  floatingLabelText={labels[type].dateInputTitle}
                                  hintText={labels[type].dateInputTitle}
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ date: value }))} />

                      <TimePicker id={`${type}-time-picker`}
                                  value={
                                    editTerminal.localDateTime ?
                                      getLocalDateTimeValue(editTerminal.localDateTime) :
                                      defaultDateTime
                                  }
                                  format="24hr"
                                  autoOk
                                  fullWidth
                                  floatingLabelFixed
                                  floatingLabelText="Time"
                                  hintText={labels[type].timeInputTitle}
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ time: value }))} />

 :

                    <SelectField id="transport-select"
                                 value={transportValue}
                                 fullWidth
                                 floatingLabelFixed
                                 floatingLabelText="Transport"
                                 hintText="Select type"
                                 errorText={(terminalInputErrors && terminalInputErrors.transport) && 'Select transport'}
                                 onChange={(event, index, value) => {
                                   setProperty('editTerminal.terminalInputErrors', null);
                                   setTerminalProperty('transport', value);
                                 }}>
                      {transportOptions}
                    </SelectField>

                      <DatePicker id={`${type}-date-picker`}
                                  value={editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime}
                                  floatingLabelStyle={{ width: '120px' }}
                                  floatingLabelText={labels[type].dateInputTitle}
                                  floatingLabelFixed
                                  fullWidth
                                  autoOk
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ date: value }))} />

                      <TimePicker id={`${type}-time-picker`}
                                  value={editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime}
                                  format="24hr"
                                  floatingLabelText="Time"
                                  floatingLabelFixed
                                  fullWidth
                                  autoOk
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ time: value }))} />

                    <TextField id="transport-id"
                               value={transportIdValue}
                               fullWidth
                               floatingLabelFixed
                               floatingLabelText="Transport ID"
                               hintText={!editTerminal.transportId ? 'Number, company...' : null}
                               onChange={(e) => setTerminalProperty('transportId', e.target.value)}
                    />

                    <TextField id="description"
                               value={descriptionValue}
                               fullWidth
                               floatingLabelFixed
                               floatingLabelText="Description"
                               hintText={(!editTerminal.description) ? 'Other info' : null}
                               onChange={(e) => setTerminalProperty('description', e.target.value)}
                    />

                  {
                    (userDepartures && userDepartures.length > 0) &&

                        <FontIcon className="material-icons" style={{ fontSize: '20px', color: editTerminal.priceType !== 'part' ? '#0074c2' : 'black' }} onClick={() => {
                          setTerminalProperty('priceType', 'payment');
                        }}>payment</FontIcon>

                        <FontIcon className="material-icons" style={{ fontSize: '20px', color: editTerminal.priceType === 'part' ? '#0074c2' : 'black' }} onClick={() => {
                          setTerminalProperty('priceType', 'part');
                          //setTerminalProperty('priceTerminalUuid', userDepartures[0].uuid);
                          getTerminal(priceTerminal ? priceTerminal.uuid : userDepartures[0].uuid);
                        }}>dehaze</FontIcon>

                  }
                  {
                    editTerminal.priceType === 'part' ?

                        <SelectField value={priceTerminalUuidValue}
                                     style={{ width: '100%' }}
                                     floatingLabelText="Part of total cost"
                                     onChange={(event, index, value) => {
                                       setTerminalProperty('priceTerminalUuid', value);
                                       getTerminal(value);
                                     }}>
                          {(userDepartures || []).filter(dep => dep.uuid !== editTerminal.uuid).map(dep => {
                            const priceTerminalText = dep.transport + ' from ' + dep.locality + ' ' + dep.priceAmount + ' ' + dep.priceCurrency;
                            return (
                              <MenuItem id={`price-terminal-${dep.uuid}`}
                                        key={`price-terminal-${dep.uuid}`}
                                        value={dep.uuid}
                                        primaryText={priceTerminalText}>
                              </MenuItem>
                            );
                          })}
                        </SelectField>

 :

                          <TextField id="price-amount-input"
                                     value={editTerminal.priceAmount || ''}
                                     style={{ width: '100%' }}
                                     floatingLabelFixed
                                     floatingLabelText="Cost"
                                     hintText="Price"
                                     onChange={(e) => {
                                       setTerminalProperty('priceAmount', e.target.value);
                                     }}
                          />

                          <SelectField id="currency-select"
                                       value={editTerminal.priceCurrency}
                                       style={{ width: '100%' }}
                                       floatingLabelText="Currency"
                                       onChange={(event, index, value) => setTerminalProperty('priceCurrency', value)}>
                            {currencies}
                          </SelectField>

                  }

                    <RaisedButton label="OK" fullWidth disabled={saveDisabled} onClick={() => save()} />

          }

  );

};

export default injectIntl(
  connect(state => ({
    terminalProperties: state.editTerminal.terminalProperties || {},
    editTerminal: state.editTerminal.terminal || {},
    saveDisabled: state.editTerminal.saveDisabled,
    terminalInputErrors: state.editTerminal.terminalInputErrors,
    userDepartures: state.posts.userDepartures,
    priceTerminal: state.editTerminal.priceTerminal
  }), {
    setProperty, saveTerminal, getTerminal
  })(withStyles(s)(Terminal))
);
<commit_msg>Fixed small bugs in edit te terminal ui<commit_after>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { setProperty } from '../../actions/properties';
import { saveTerminal, getTerminal } from '../../actions/posts';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Terminal.css';
import TextField from 'material-ui/TextField';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import DatePicker from 'material-ui/DatePicker';
import TimePicker from 'material-ui/TimePicker';
import RaisedButton from 'material-ui/RaisedButton';
import { injectIntl } from 'react-intl';
import { getAvailableCurrencies } from '../../services/linkService';

import msg from './messages.terminal';
import { getClientId, getPaddedDate, getPaddedTime } from '../../core/utils';
import FontIcon from 'material-ui/FontIcon';
import { getLocalDateTimeValue } from '../utils';

const labels = {
  departure: {
    dateInputTitle: 'Departure date',
    timeInputTitle: 'Time',
    placeInputTitle: 'Departure description'
  },
  arrival: {
    dateInputTitle: 'Arrival date',
    timeInputTitle: 'Time',
    placeInputTitle: 'Arrival description'
  }
}

const Terminal = ({
  intl, checkIn, transportTypes, openTerminals, type, editTerminal, userDepartures, priceTerminal,
  saveDisabled, setProperty, saveTerminal, getTerminal, terminalInputErrors
}) => {

  const transportOptions = transportTypes.map(type => (
    <MenuItem id={type.slug} key={type.slug} style={{ 'WebkitAppearance': 'initial' }}
              value={type.slug} primaryText={intl.formatMessage(msg[type.slug])} />
  ));

  const currencyCodes = getAvailableCurrencies(checkIn.country);

  const currencies = Object.keys(currencyCodes).map(code => (
    <MenuItem key={code} style={{ 'WebkitAppearance': 'initial' }} value={code} primaryText={`${code}`} />
  ));

  const setTerminalProperty = (name, value) => {
    setProperty('editTerminal.terminal', { ...editTerminal, [name]: value });
  };

  const typedOpenTerminals = (openTerminals || []).filter(terminal => (terminal.type === (type === 'arrival' ? 'departure' : 'arrival') && terminal.checkIn.uuid !== checkIn.uuid));

  const openTerminalOptions = typedOpenTerminals.map(terminal => {
    const menuItemLabel = (

            { terminal.transport && intl.formatMessage(msg[terminal.transport]) }

            { terminal.transportId }

          { terminal.checkIn.formattedAddress }

    );

    return (
      <MenuItem id={terminal.uuid} key={terminal.uuid} style={{ wdith: '100%', 'WebkitAppearance': 'initial' }}
                value={terminal.uuid} primaryText={menuItemLabel}>
      </MenuItem>
    );

  });

  let linkedTerminalUuid = null;
  if (editTerminal.linkedTerminalUuid) {
    linkedTerminalUuid = editTerminal.linkedTerminalUuid;
  } else {
    if (typedOpenTerminals.length > 0) {
      linkedTerminalUuid = typedOpenTerminals[0].uuid;
    }
  }

  let linkedTerminal = null;
  if (linkedTerminalUuid !== 'not-linked') {
    if (typedOpenTerminals.length > 0) {
      linkedTerminal = (typedOpenTerminals || []).filter(terminal => terminal.uuid === (linkedTerminalUuid || typedOpenTerminals[0].uuid))[0];
    }
  }

  const now = new Date();

  const linkedTerminalLabel = type === 'arrival' ? 'Link to departure' : 'Link to arrival';

  const getDefaultTerminalTime = () => {
    const checkInDateTime = new Date(checkIn.date);
    const timeDiff = Math.abs(now.getTime() - checkInDateTime.getTime());
    return (timeDiff < 1000 * 60 * 60 * 48) ? now : checkInDateTime;
  };

  const defaultDateTime = (linkedTerminal && !editTerminal.uuid) ?
    new Date(editTerminal.localDateTime || getDefaultTerminalTime()) :
    new Date(editTerminal.localDateTime || getDefaultTerminalTime());

  const dateTime = ({ date, time }) => {
    const newDate = date ? getPaddedDate(date) : getPaddedDate(editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime);
    const newTime = time ? getPaddedTime(time) : getPaddedTime(editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime);
    return newDate + 'T' + newTime;
  };

  const transportValue = editTerminal.transport || (priceTerminal ? priceTerminal.transport : undefined);
  const transportIdValue = (editTerminal.transportId || (priceTerminal || {}).transportId) || '';
  const descriptionValue = (editTerminal.description || (priceTerminal || {}).description) || '';

  let priceTerminalUuidValue = editTerminal.priceTerminalUuid ||
    (editTerminal.priceTerminal ? editTerminal.priceTerminal.uuid : undefined) ||
    ((userDepartures && userDepartures.length > 0) ? userDepartures[0].uuid : undefined);
  console.log('editTerminal', priceTerminalUuidValue, userDepartures, transportValue);
  const save = () => {

    if (!transportValue && !linkedTerminal) {
      setProperty('editTerminal.terminalInputErrors', {
        transport: 'empty'
      });
      return;
    }

    const editedTerminal = {
      uuid: editTerminal.uuid,
      checkInUuid: checkIn.uuid,
      type,
      transport: transportValue,
      transportId: transportIdValue,
      description: descriptionValue,
      priceCurrency: editTerminal.priceCurrency,
      priceType: editTerminal.priceType || 'payment',
      priceTerminalUuid: editTerminal.priceType === 'part' ? priceTerminalUuidValue : null
    };

    if (editTerminal.priceAmount && editTerminal.priceAmount.length > 0) {
      editedTerminal.priceAmount = parseFloat(editTerminal.priceAmount);
    }

    editedTerminal.date = editTerminal.localDateTime || dateTime({ date: defaultDateTime, time: defaultDateTime });

    if (linkedTerminalUuid !== 'not-linked' && linkedTerminal) {
      editedTerminal.linkedTerminalUuid = linkedTerminalUuid;
      editedTerminal.transport = linkedTerminal.transport;
      editedTerminal.transportId = linkedTerminal.transactionId;
    }

    const clientId = getClientId();
    editedTerminal.clientId = clientId;

    saveTerminal({ terminal: editedTerminal });

  };

  return (

          {
            (!editTerminal.uuid && openTerminalOptions.length > 0) &&

                <SelectField id="linked-terminal-select"
                             value={linkedTerminalUuid || ((typedOpenTerminals && typedOpenTerminals.length > 0) && typedOpenTerminals[0].uuid)}
                             fullWidth
                             floatingLabelFixed
                             floatingLabelText={linkedTerminalLabel}
                             hintText="Select terminal"
                             labelStyle={{ height: 'initial' }}
                             style={{ height: 'initial' }}
                             onChange={(event, index, value) => setProperty('editTerminal.terminal', { ...editTerminal, linkedTerminalUuid: value })}>
                  {openTerminalOptions}
                </SelectField>

          }
          {

            (linkedTerminal && !editTerminal.uuid) ?

                      <FontIcon className="material-icons" style={{ fontSize: '24px' }}>edit</FontIcon>

                    <RaisedButton label="LINK" fullWidth disabled={saveDisabled} onClick={() => save()} />

                      <DatePicker id={`${type}-date-picker`}
                                  value={
                                    editTerminal.localDateTime ?
                                      getLocalDateTimeValue(editTerminal.localDateTime) :
                                      defaultDateTime
                                  }
                                  autoOk
                                  fullWidth
                                  floatingLabelFixed
                                  floatingLabelStyle={{ width: '120px' }}
                                  floatingLabelText={labels[type].dateInputTitle}
                                  hintText={labels[type].dateInputTitle}
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ date: value }))} />

                      <TimePicker id={`${type}-time-picker`}
                                  value={
                                    editTerminal.localDateTime ?
                                      getLocalDateTimeValue(editTerminal.localDateTime) :
                                      defaultDateTime
                                  }
                                  format="24hr"
                                  autoOk
                                  fullWidth
                                  floatingLabelFixed
                                  floatingLabelText="Time"
                                  hintText={labels[type].timeInputTitle}
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ time: value }))} />

 :

                    <SelectField id="transport-select"
                                 value={transportValue}
                                 fullWidth
                                 floatingLabelFixed
                                 floatingLabelText="Transport"
                                 hintText="Select type"
                                 errorText={(terminalInputErrors && terminalInputErrors.transport) && 'Select transport'}
                                 onChange={(event, index, value) => {
                                   setProperty('editTerminal.terminalInputErrors', null);
                                   setTerminalProperty('transport', value);
                                 }}>
                      {transportOptions}
                    </SelectField>

                      <DatePicker id={`${type}-date-picker`}
                                  value={editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime}
                                  floatingLabelStyle={{ width: '120px' }}
                                  floatingLabelText={labels[type].dateInputTitle}
                                  floatingLabelFixed
                                  fullWidth
                                  autoOk
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ date: value }))} />

                      <TimePicker id={`${type}-time-picker`}
                                  value={editTerminal.localDateTime ? new Date(editTerminal.localDateTime) : defaultDateTime}
                                  format="24hr"
                                  floatingLabelText="Time"
                                  floatingLabelFixed
                                  fullWidth
                                  autoOk
                                  onChange={(event, value) => setTerminalProperty('localDateTime', dateTime({ time: value }))} />

                    <TextField id="transport-id"
                               value={transportIdValue}
                               fullWidth
                               floatingLabelFixed
                               floatingLabelText="Transport ID"
                               hintText={!editTerminal.transportId ? 'Number, company...' : null}
                               onChange={(e) => setTerminalProperty('transportId', e.target.value)}
                    />

                    <TextField id="description"
                               value={descriptionValue}
                               fullWidth
                               floatingLabelFixed
                               floatingLabelText="Description"
                               hintText={(!editTerminal.description) ? 'Other info' : null}
                               onChange={(e) => setTerminalProperty('description', e.target.value)}
                    />

                  {
                    (userDepartures && userDepartures.length > 0) &&

                        <FontIcon className="material-icons" style={{ fontSize: '20px', color: editTerminal.priceType !== 'part' ? '#0074c2' : 'black' }} onClick={() => {
                          setTerminalProperty('priceType', 'payment');
                        }}>payment</FontIcon>

                        <FontIcon className="material-icons" style={{ fontSize: '20px', color: editTerminal.priceType === 'part' ? '#0074c2' : 'black' }} onClick={() => {
                          setTerminalProperty('priceType', 'part');
                          //setTerminalProperty('priceTerminalUuid', userDepartures[0].uuid);
                          getTerminal(priceTerminal ? priceTerminal.uuid : userDepartures[0].uuid);
                        }}>dehaze</FontIcon>

                  }
                  {
                    editTerminal.priceType === 'part' ?

                        <SelectField value={priceTerminalUuidValue}
                                     style={{ width: '100%' }}
                                     floatingLabelText="Part of total cost"
                                     onChange={(event, index, value) => {
                                       setTerminalProperty('priceTerminalUuid', value);
                                       getTerminal(value);
                                     }}>
                          {(userDepartures || []).filter(dep => dep.uuid !== editTerminal.uuid).map(dep => {
                            let priceTerminalText = dep.transport + ' from ' + dep.locality;
                            if (dep.priceAmount) {
                              priceTerminalText += ' ' + dep.priceAmount + ' ' + dep.priceCurrency;
                            }

                            return (
                              <MenuItem id={`price-terminal-${dep.uuid}`}
                                        key={`price-terminal-${dep.uuid}`}
                                        value={dep.uuid}
                                        primaryText={priceTerminalText}>
                              </MenuItem>
                            );
                          })}
                        </SelectField>

 :

                          <TextField id="price-amount-input"
                                     value={editTerminal.priceAmount || ''}
                                     style={{ width: '100%' }}
                                     floatingLabelFixed
                                     floatingLabelText="Cost"
                                     hintText="Price"
                                     onChange={(e) => {
                                       setTerminalProperty('priceAmount', e.target.value);
                                     }}
                          />

                          <SelectField id="currency-select"
                                       value={editTerminal.priceCurrency}
                                       style={{ width: '100%' }}
                                       floatingLabelText="Currency"
                                       onChange={(event, index, value) => setTerminalProperty('priceCurrency', value)}>
                            {currencies}
                          </SelectField>

                  }

                    <RaisedButton label="OK" fullWidth disabled={saveDisabled} onClick={() => save()} />

          }

  );

};

export default injectIntl(
  connect(state => ({
    terminalProperties: state.editTerminal.terminalProperties || {},
    editTerminal: state.editTerminal.terminal || {},
    saveDisabled: state.editTerminal.saveDisabled,
    terminalInputErrors: state.editTerminal.terminalInputErrors,
    userDepartures: state.posts.userDepartures,
    priceTerminal: state.editTerminal.priceTerminal
  }), {
    setProperty, saveTerminal, getTerminal
  })(withStyles(s)(Terminal))
);
<|endoftext|>